/*
* Copyright (C) 2012-2016 The Android Money Manager Ex Project Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.money.manager.ex.recurring.transactions;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.util.Log;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.mikepenz.mmex_icon_font_typeface_library.MMXIconFont;
import com.money.manager.ex.MoneyManagerApplication;
import com.money.manager.ex.common.MmxCursorLoader;
import com.money.manager.ex.datalayer.Select;
import com.money.manager.ex.log.ExceptionHandler;
import com.money.manager.ex.core.UIHelper;
import com.money.manager.ex.datalayer.RecurringTransactionRepository;
import com.money.manager.ex.domainmodel.Account;
import com.money.manager.ex.domainmodel.RecurringTransaction;
import com.money.manager.ex.transactions.CheckingTransactionEditActivity;
import com.money.manager.ex.R;
import com.money.manager.ex.adapter.AllDataAdapter;
import com.money.manager.ex.servicelayer.RecurringTransactionService;
import com.money.manager.ex.transactions.EditTransactionActivityConstants;
import com.money.manager.ex.database.QueryBillDeposits;
import com.money.manager.ex.common.BaseListFragment;
import com.money.manager.ex.utils.MmxDateTimeUtils;
import com.roomorama.caldroid.CaldroidFragment;
import com.roomorama.caldroid.CaldroidListener;
import com.shamanland.fonticon.FontIconDrawable;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import javax.inject.Inject;
import dagger.Lazy;
/**
* The recurring transactions list fragment.
* Includes floating action button.
*/
public class RecurringTransactionListFragment
extends BaseListFragment
implements LoaderManager.LoaderCallbacks<Cursor> {
private static final int REQUEST_ADD_REPEATING_TRANSACTION = 1001;
private static final int REQUEST_ADD_TRANSACTION = 1002;
private static final int REQUEST_EDIT_REPEATING_TRANSACTION = 1003;
private static final int ID_LOADER_REPEATING = 0;
private static QueryBillDeposits mBillDeposits;
@Inject
Lazy<MmxDateTimeUtils> dateTimeUtilsLazy;
// filter
private String mCurFilter;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// create a object query
mBillDeposits = new QueryBillDeposits(getActivity());
// set list view
setEmptyText(getActivity().getResources().getString(R.string.repeating_empty_transaction));
setHasOptionsMenu(true);
registerForContextMenu(getListView());
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
UIHelper uiHelper = new UIHelper(getActivity());
getListView().setDivider(new ColorDrawable(uiHelper.resolveAttribute(R.attr.theme_background_color)));
setListShown(false);
getLoaderManager().initLoader(ID_LOADER_REPEATING, null, this);
// show floating button.
setFloatingActionButtonVisible(true);
attachFloatingActionButtonToListView();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MoneyManagerApplication.getApp().iocComponent.inject(this);
setHasOptionsMenu(true);
}
@Override
public void onFloatingActionButtonClicked() {
// create new recurring transaction.
startRecurringTransactionEditActivity(null, REQUEST_ADD_REPEATING_TRANSACTION);
}
// Menu
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
// MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_item_calendar, menu);
MenuItem calendar = menu.findItem(R.id.menuCalendar);
if (calendar != null) {
Drawable icon = new UIHelper(getActivity()).getIcon(MMXIconFont.Icon.mmx_calendar);
calendar.setIcon(icon);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// handle calendar
switch (item.getItemId()) {
case R.id.menuCalendar:
showCaldroidFragment();
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
// show context menu here.
getActivity().openContextMenu(v);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, v, menuInfo);
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
// take a cursor and move to position
Cursor cursor = ((AllDataAdapter) getListAdapter()).getCursor();
if (cursor != null) {
cursor.moveToPosition(info.position);
// set title and inflate menu
menu.setHeaderTitle(getActivity().getTitle());
getActivity().getMenuInflater().inflate(R.menu.contextmenu_repeating_transactions, menu);
}
}
@Override
public boolean onContextItemSelected(android.view.MenuItem item) {
ContextMenu.ContextMenuInfo menuInfo = item.getMenuInfo();
if (menuInfo == null) {
String errorMessage = "no context menu info";
Log.w(this.getClass().getSimpleName(), errorMessage);
ExceptionHandler handler = new ExceptionHandler(getActivity(), this);
handler.showMessage("no context menu info");
return false;
}
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
int menuItemId = item.getItemId();
int transactionId = (int) info.id;
switch (menuItemId) {
case R.id.menu_enter_next_occurrence:
showCreateTransactionActivity(transactionId);
break;
case R.id.menu_skip_next_occurrence:
confirmSkip(transactionId);
break;
case R.id.menu_edit:
startRecurringTransactionEditActivity(transactionId, REQUEST_EDIT_REPEATING_TRANSACTION);
break;
case R.id.menu_delete:
confirmDelete(transactionId);
break;
}
return false;
}
// Loader callbacks.
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
switch (id) {
case ID_LOADER_REPEATING:
String select = null;
if (!TextUtils.isEmpty(mCurFilter)) {
select = Account.ACCOUNTNAME + " LIKE '" + mCurFilter + "%'";
}
Select query = new Select(mBillDeposits.getAllColumns())
.where(select)
.orderBy(QueryBillDeposits.NEXTOCCURRENCEDATE);
return new MmxCursorLoader(getActivity(), mBillDeposits.getUri(), query);
}
return null;
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
switch (loader.getId()) {
case ID_LOADER_REPEATING:
AllDataAdapter adapter = (AllDataAdapter) getListAdapter();
if (adapter != null) {
// adapter.swapCursor(null);
adapter.changeCursor(null);
}
}
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
switch (loader.getId()) {
case ID_LOADER_REPEATING:
if (data == null) return;
AllDataAdapter adapter = new AllDataAdapter(getActivity(), data,
AllDataAdapter.TypeCursor.RECURRINGTRANSACTION);
setListAdapter(adapter);
if (isResumed()) {
setListShown(true);
if (data.getCount() <= 0 && getFloatingActionButton() != null)
getFloatingActionButton().show(true);
} else {
setListShownNoAnimation(true);
}
}
}
// Other
@Override
public boolean onQueryTextChange(String newText) {
// Called when the action bar search text has changed. Update
// the search filter, and restart the loader to do a new query
// with this filter.
mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
getLoaderManager().restartLoader(ID_LOADER_REPEATING, null, this);
return true;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RecurringTransactionListActivity.RESULT_OK) {
// switch (requestCode) {
// case REQUEST_ADD_REPEATING_TRANSACTION:
// break;
// case REQUEST_ADD_TRANSACTION:
// break;
// case REQUEST_EDIT_REPEATING_TRANSACTION:
// break;
// }
// Always reload the activity?
getLoaderManager().restartLoader(ID_LOADER_REPEATING, null, this);
}
}
@Override
public String getSubTitle() {
return getString(R.string.recurring_transactions);
}
// private
private void confirmDelete(final int id) {
// create alert binaryDialog
new MaterialDialog.Builder(getContext())
.title(R.string.delete_repeating_transaction)
.icon(FontIconDrawable.inflate(getContext(), R.xml.ic_question))
.content(R.string.confirmDelete)
.positiveText(android.R.string.ok)
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
RecurringTransactionService recurringTransaction = new RecurringTransactionService(id, getActivity());
recurringTransaction.delete();
// restart loader
getLoaderManager().restartLoader(ID_LOADER_REPEATING,
null, RecurringTransactionListFragment.this);
}
})
.negativeText(android.R.string.cancel)
.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.cancel();
}
})
.build().show();
}
private void confirmSkip(final int id) {
new MaterialDialog.Builder(getContext())
.title(R.string.skip_next_occurrence)
.icon(FontIconDrawable.inflate(getContext(), R.xml.ic_question))
.content(R.string.skip_next_occurrence_confirmation)
.positiveText(android.R.string.ok)
.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
RecurringTransactionService recurringTransaction = new RecurringTransactionService(id, getActivity());
recurringTransaction.moveNextOccurrence();
getLoaderManager().restartLoader(ID_LOADER_REPEATING, null,
RecurringTransactionListFragment.this);
}
})
.negativeText(android.R.string.cancel)
.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.cancel();
}
})
.build().show();
}
private void showCaldroidFragment() {
Locale appLocale = MoneyManagerApplication.getApp().getAppLocale();
CaldroidFragment caldroidFragment = new CaldroidFragment();
// Customization
Bundle args = new Bundle();
Calendar cal = Calendar.getInstance(appLocale);
args.putInt(CaldroidFragment.MONTH, cal.get(Calendar.MONTH) + 1);
args.putInt(CaldroidFragment.YEAR, cal.get(Calendar.YEAR));
args.putInt(CaldroidFragment.START_DAY_OF_WEEK, dateTimeUtilsLazy.get().getFirstDayOfWeek());
if (new UIHelper(getActivity()).isUsingDarkTheme()) {
args.putInt(CaldroidFragment.THEME_RESOURCE, com.caldroid.R.style.CaldroidDefaultDark);
}
// disable switching month for now.
args.putBoolean(CaldroidFragment.SHOW_NAVIGATION_ARROWS, Boolean.FALSE);
args.putBoolean(CaldroidFragment.ENABLE_SWIPE, Boolean.FALSE);
caldroidFragment.setArguments(args);
// add different background for dates with events.
showDatesWithEvents(caldroidFragment);
// behaviour
caldroidFragment.setCaldroidListener(getCalendarListener());
android.support.v4.app.FragmentTransaction t = getActivity().getSupportFragmentManager()
.beginTransaction();
t.replace(R.id.fragmentMain, caldroidFragment);
t.addToBackStack(null);
t.commit();
}
private CaldroidListener getCalendarListener() {
return new CaldroidListener() {
@Override
public void onSelectDate(Date date, View view) {
// fragment.setCalendarDate(date);
// todo show the recurring transactions on this date.
}
@Override
public void onChangeMonth(int month, int year) {
}
@Override
public void onLongClickDate(Date date, View view) {
}
@Override
public void onCaldroidViewCreated() {
}
};
}
private void showDatesWithEvents(CaldroidFragment caldroid) {
ListAdapter adapter = getListAdapter();
int count = adapter.getCount();
ColorDrawable orange = new ColorDrawable(ContextCompat.getColor(getActivity(), R.color.holo_orange_dark));
RecurringTransaction tx = RecurringTransaction.createInstance();
for (int i = 0; i < count; i++) {
Cursor cursor = (Cursor) adapter.getItem(i);
tx.loadFromCursor(cursor);
caldroid.setBackgroundDrawableForDate(orange, tx.getPaymentDate());
}
}
private void showCreateTransactionActivity(int recurringTransactionId) {
RecurringTransactionRepository repo = new RecurringTransactionRepository(getActivity());
RecurringTransaction tx = repo.load(recurringTransactionId);
if (tx == null) return;
Intent intent = new Intent(getActivity(), CheckingTransactionEditActivity.class);
intent.setAction(Intent.ACTION_INSERT);
intent.putExtra(EditTransactionActivityConstants.KEY_BDID_ID, recurringTransactionId);
// start for insert new transaction
startActivityForResult(intent, REQUEST_ADD_TRANSACTION);
}
/**
* start RepeatingTransaction for insert or edit transaction
*
* @param billDepositsId Id of the recurring transaction.
* @param purposeCode Code that indicates why we are opening the editor.
* example: REQUEST_ADD_REPEATING_TRANSACTION
*/
private void startRecurringTransactionEditActivity(Integer billDepositsId, int purposeCode) {
// create intent, set Bill Deposits ID
Intent intent = new Intent(getActivity(), RecurringTransactionEditActivity.class);
// check transId not null
if (billDepositsId != null) {
intent.putExtra(RecurringTransactionEditActivity.KEY_BILL_DEPOSITS_ID, billDepositsId);
intent.setAction(Intent.ACTION_EDIT);
} else {
intent.setAction(Intent.ACTION_INSERT);
}
// launch activity
startActivityForResult(intent, purposeCode);
}
}