/*
* 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.common;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v4.widget.CursorAdapter;
import android.support.v7.app.ActionBar;
import android.text.TextUtils;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.money.manager.ex.Constants;
import com.money.manager.ex.core.TransactionTypes;
import com.money.manager.ex.core.UIHelper;
import com.money.manager.ex.currency.CurrencyService;
import com.money.manager.ex.database.ITransactionEntity;
import com.money.manager.ex.datalayer.AccountTransactionRepository;
import com.money.manager.ex.datalayer.Select;
import com.money.manager.ex.datalayer.SplitCategoriesRepository;
import com.money.manager.ex.domainmodel.AccountTransaction;
import com.money.manager.ex.domainmodel.SplitCategory;
import com.money.manager.ex.sync.SyncManager;
import com.money.manager.ex.transactions.CheckingTransactionEditActivity;
import com.money.manager.ex.R;
import com.money.manager.ex.servicelayer.qif.QifExport;
import com.money.manager.ex.transactions.EditTransactionActivityConstants;
import com.money.manager.ex.search.SearchActivity;
import com.money.manager.ex.adapter.AllDataAdapter;
import com.money.manager.ex.adapter.AllDataAdapter.TypeCursor;
import com.money.manager.ex.home.DrawerMenuItem;
import com.money.manager.ex.home.DrawerMenuItemAdapter;
import com.money.manager.ex.core.ExportToCsvFile;
import com.money.manager.ex.database.QueryAllData;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import info.javaperformance.money.Money;
import info.javaperformance.money.MoneyFactory;
import timber.log.Timber;
/**
* Fragment that displays the transactions.
*/
public class AllDataListFragment
extends BaseListFragment
implements LoaderCallbacks<Cursor>, IAllDataMultiChoiceModeListenerCallbacks {
private static final String ARG_ACCOUNT_ID = "AccountId";
private static final String ARG_SHOW_FLOATING_BUTTON = "ShowFloatingButton";
public static AllDataListFragment newInstance(int accountId) {
return newInstance(accountId, true);
}
/**
* Create a new instance of AllDataListFragment with accountId params
*
* @param accountId Id of account to display. If generic shown set -1
* @return new instance AllDataListFragment
*/
public static AllDataListFragment newInstance(int accountId, boolean showFloatingButton) {
AllDataListFragment fragment = new AllDataListFragment();
Bundle args = new Bundle();
args.putInt(ARG_ACCOUNT_ID, accountId);
args.putBoolean(ARG_SHOW_FLOATING_BUTTON, showFloatingButton);
fragment.setArguments(args);
return fragment;
}
public static final int ID_LOADER_ALL_DATA_DETAIL = 1;
public static final String KEY_ARGUMENTS_WHERE = "SearchResultFragment:ArgumentsWhere";
public static final String KEY_ARGUMENTS_SORT = "SearchResultFragment:ArgumentsSort";
public int AccountId = Constants.NOT_SET;
private LinearLayout footer;
private LoaderManager.LoaderCallbacks<Cursor> mSearResultFragmentLoaderCallbacks;
private boolean mAutoStarLoader = true;
private boolean mShowHeader = false;
private boolean mShowBalance = false;
private AllDataMultiChoiceModeListener mMultiChoiceModeListener;
private View mListHeader = null;
private Bundle mArguments;
private boolean mShowFooter = false;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setEmptyText(getString(R.string.no_data));
setListShown(false);
// Read arguments
this.AccountId = getArguments().getInt(ARG_ACCOUNT_ID);
// Read header indicator directly from the activity.
// todo: make this a parameter or a property.
if (getActivity() instanceof SearchActivity) {
SearchActivity activity = (SearchActivity) getActivity();
setShownHeader(activity.ShowAccountHeaders);
}
// create adapter for data.
AllDataAdapter adapter = new AllDataAdapter(getActivity(), null, TypeCursor.ALLDATA);
adapter.setAccountId(this.AccountId);
adapter.setShowAccountName(isShownHeader());
adapter.setShowBalanceAmount(isShownBalance());
// set multi-choice mode in the list view.
mMultiChoiceModeListener = new AllDataMultiChoiceModeListener();
mMultiChoiceModeListener.setListener(this);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
getListView().setMultiChoiceModeListener(mMultiChoiceModeListener);
// e item click
getListView().setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (getListAdapter() != null && getListAdapter() instanceof AllDataAdapter) {
Cursor cursor = ((AllDataAdapter) getListAdapter()).getCursor();
if (cursor.moveToPosition(position - (mListHeader != null ? 1 : 0))) {
startEditAccountTransactionActivity(cursor.getInt(cursor.getColumnIndex(QueryAllData.ID)));
}
}
}
});
// Header and footer must be added before setAdapter().
// Add a header to the list view if one exists.
if (getListAdapter() == null) {
if (mListHeader != null)
getListView().addHeaderView(mListHeader);
}
if (this.mShowFooter) {
renderFooter();
}
// set adapter
setListAdapter(adapter);
// register context menu
registerForContextMenu(getListView());
// set animation progress
setListShown(false);
boolean showAddButton = getArguments().getBoolean(ARG_SHOW_FLOATING_BUTTON);
if (showAddButton) {
// Show floating action button.
setFloatingActionButtonVisible(true);
attachFloatingActionButtonToListView();
}
// start loader if asked to do so by the caller.
if (isAutoStarLoader()) {
loadData();
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
// Loader event handlers
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (getSearchResultFragmentLoaderCallbacks() != null)
getSearchResultFragmentLoaderCallbacks().onCreateLoader(id, args);
//animation
setListShown(false);
switch (id) {
case ID_LOADER_ALL_DATA_DETAIL:
// compose selection and sort
String selection = "";
if (args != null && args.containsKey(KEY_ARGUMENTS_WHERE)) {
selection = args.getString(KEY_ARGUMENTS_WHERE);
}
// String[] whereParams = new String[0];
// if (args != null && args.containsKey(KEY_ARGUMENTS_WHERE_PARAMS)) {
// ArrayList<String> whereParamsList = args.getStringArrayList(KEY_ARGUMENTS_WHERE_PARAMS);
// whereParams = whereParamsList.toArray(whereParams);
// }
// set sort
String sort = "";
if (args != null && args.containsKey(KEY_ARGUMENTS_SORT)) {
sort = args.getString(KEY_ARGUMENTS_SORT);
}
// create loader
QueryAllData allData = new QueryAllData(getActivity());
Select query = new Select(allData.getAllColumns())
.where(selection)
.orderBy(sort);
return new MmxCursorLoader(getActivity(), allData.getUri(), query);
}
return null;
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
LoaderManager.LoaderCallbacks<Cursor> parent = getSearchResultFragmentLoaderCallbacks();
if (parent != null) parent.onLoaderReset(loader);
//((CursorAdapter) getListAdapter()).swapCursor(null);
((CursorAdapter) getListAdapter()).changeCursor(null);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
LoaderManager.LoaderCallbacks<Cursor> parent = getSearchResultFragmentLoaderCallbacks();
if (parent != null) parent.onLoadFinished(loader, data);
switch (loader.getId()) {
case ID_LOADER_ALL_DATA_DETAIL:
// Transactions list loaded.
AllDataAdapter adapter = (AllDataAdapter) getListAdapter();
// adapter.swapCursor(data);
adapter.changeCursor(data);
if (isResumed()) {
setListShown(true);
if (data != null && data.getCount() <= 0 && getFloatingActionButton() != null)
getFloatingActionButton().show(true);
} else {
setListShownNoAnimation(true);
}
// reset the transaction groups (account name collection)
adapter.resetAccountHeaderIndexes();
// Show totals
if (this.mShowFooter) {
try {
this.updateFooter(data);
} catch (Exception e) {
Timber.e(e, "displaying footer");
}
}
}
}
// End loader event handlers
/**
* Add options to the action bar of the host activity.
* This is not called in ActionBar Activity, i.e. Search.
* @param menu
* @param inflater
*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
Activity activity = getActivity();
if (activity == null) return;
MenuItem itemExportToCsv = menu.findItem(R.id.menu_export_to_csv);
if (itemExportToCsv != null) itemExportToCsv.setVisible(true);
MenuItem itemSearch = menu.findItem(R.id.menu_search_transaction);
if (itemSearch != null) {
itemSearch.setVisible(!activity.getClass().getSimpleName()
.equals(SearchActivity.class.getSimpleName()));
}
// show this on all transactions lists later?
// show this menu only when on Search Activity for now.
if (activity.getClass().getSimpleName().equals(SearchActivity.class.getSimpleName())) {
// Add default menu options. todo: check why this is executed twice.
// Includes menu item for .qif export
MenuItem qifExport = menu.findItem(R.id.menu_qif_export);
if (qifExport == null) {
inflater.inflate(R.menu.menu_alldata_operations, menu);
}
}
}
/**
* This is just to test:
* http://stackoverflow.com/questions/15207305/getting-the-error-java-lang-illegalstateexception-activity-has-been-destroyed
*/
@Override
public void onDetach() {
super.onDetach();
try {
Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Override
public void onDestroy() {
if (mMultiChoiceModeListener != null)
mMultiChoiceModeListener.onDestroyActionMode(null);
super.onDestroy();
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onStop() {
super.onStop();
try {
MmxBaseFragmentActivity activity = (MmxBaseFragmentActivity) getActivity();
if (activity != null) {
ActionBar actionBar = activity.getSupportActionBar();
if(actionBar != null) {
View customView = actionBar.getCustomView();
if (customView != null) {
actionBar.setCustomView(null);
}
}
}
} catch (Exception e) {
Timber.e(e, "stopping the all-data fragment");
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.menu_export_to_csv) {
exportDataToCSVFile();
return true;
}
if (itemId == R.id.menu_qif_export) {
// export visible transactions.
exportToQif();
}
return super.onOptionsItemSelected(item);
}
@Override
public String getSubTitle() {
return null;
}
@Override
public void onFloatingActionButtonClicked() {
startEditAccountTransactionActivity(null);
}
// Multi-choice-mode listener callback handlers.
/**
* handler for multi-choice-mode listener
*/
@Override
public void onMultiChoiceCreated(android.view.Menu menu) {
getActivity().getMenuInflater().inflate(R.menu.menu_all_data_adapter, menu);
}
@Override
public void onDestroyActionMode() {
if (getListAdapter() != null && getListAdapter() instanceof AllDataAdapter) {
AllDataAdapter adapter = (AllDataAdapter) getListAdapter();
adapter.clearPositionChecked();
adapter.notifyDataSetChanged();
}
}
@Override
public void onDeleteClicked() {
ArrayList<Integer> transIds = getTransactionIds();
showDialogDeleteCheckingAccount(transIds);
}
@Override
public void onChangeTransactionStatusClicked() {
ArrayList<Integer> transIds = getTransactionIds();
changeTransactionStatus(transIds);
}
@Override
public void onTransactionStatusClicked(String status) {
ArrayList<Integer> transIds = getTransactionIds();
if (setStatusCheckingAccount(convertArrayListToArray(transIds), status)) {
((AllDataAdapter) getListAdapter()).clearPositionChecked();
loadData();
}
}
@Override
public void onSelectAllRecordsClicked() {
selectAllRecords();
}
@Override
public void onDuplicateTransactionsClicked() {
ArrayList<Integer> transIds = getTransactionIds();
showDuplicateTransactionView(transIds);
}
@Override
public void onItemCheckedStateChanged(int position, boolean checked) {
if (getListHeader() != null) {
position--;
}
if (getListAdapter() != null && getListAdapter() instanceof AllDataAdapter) {
AllDataAdapter adapter = (AllDataAdapter) getListAdapter();
adapter.setPositionChecked(position, checked);
adapter.notifyDataSetChanged();
}
}
// Methods
public void displayRunningBalances(HashMap<Integer, Money> balances) {
AllDataAdapter adapter = getAllDataAdapter();
if(adapter == null) return;
adapter.setBalances(balances);
}
/**
* Export data to CSV file
*/
public void exportDataToCSVFile() {
exportDataToCSVFile("");
}
/**
* Export data to CSV file
*
* @param prefixName prefix for the file
*/
public void exportDataToCSVFile(String prefixName) {
ExportToCsvFile csv = new ExportToCsvFile(getActivity(), (AllDataAdapter) getListAdapter());
csv.setPrefixName(prefixName);
csv.execute();
}
/**
* @return the mSearResultFragmentLoaderCallbacks
*/
public LoaderManager.LoaderCallbacks<Cursor> getSearchResultFragmentLoaderCallbacks() {
return mSearResultFragmentLoaderCallbacks;
}
/**
* @param searResultFragmentLoaderCallbacks the searResultFragmentLoaderCallbacks to set
*/
public void setSearResultFragmentLoaderCallbacks(LoaderManager.LoaderCallbacks<Cursor> searResultFragmentLoaderCallbacks) {
this.mSearResultFragmentLoaderCallbacks = searResultFragmentLoaderCallbacks;
}
/**
* @return the mAutoStarLoader
*/
public boolean isAutoStarLoader() {
return mAutoStarLoader;
}
/**
* @param mAutoStarLoader the mAutoStarLoader to set
*/
public void setAutoStarLoader(boolean mAutoStarLoader) {
this.mAutoStarLoader = mAutoStarLoader;
}
/**
* @return the mShowHeader
*/
public boolean isShownHeader() {
return mShowHeader;
}
/**
* Start loader into fragment
*/
public void loadData() {
loadData(getLatestArguments());
}
public void loadData(Bundle arguments) {
// set the account id in the data adapter
AllDataAdapter adapter = getAllDataAdapter();
if (adapter != null) {
adapter.setAccountId(this.AccountId);
adapter.setBalances(null);
}
// set the current arguments / account id
setLatestArguments(arguments);
// reload data with the latest arguments.
getLoaderManager().restartLoader(ID_LOADER_ALL_DATA_DETAIL, arguments, this);
}
/**
* @param mShownHeader the mShowHeader to set
*/
public void setShownHeader(boolean mShownHeader) {
this.mShowHeader = mShownHeader;
}
public View getListHeader() {
return mListHeader;
}
public void setListHeader(View mHeaderList) {
this.mListHeader = mHeaderList;
}
/**
* @return the mShowBalance
*/
public boolean isShownBalance() {
return mShowBalance;
}
/**
* @param mShownBalance the mShowBalance to set
*/
public void setShownBalance(boolean mShownBalance) {
this.mShowBalance = mShownBalance;
AllDataAdapter adapter = getAllDataAdapter();
if (adapter == null) {
return;
}
adapter.setShowBalanceAmount(mShownBalance);
}
public void showTotalsFooter() {
this.mShowFooter = true;
}
// Private methods.
private void renderFooter() {
this.footer = (LinearLayout) View.inflate(getActivity(),
R.layout.item_generic_report_2_columns, null);
TextView txtColumn1 = (TextView) footer.findViewById(R.id.textViewColumn1);
TextView txtColumn2 = (TextView) footer.findViewById(R.id.textViewColumn2);
txtColumn1.setText(R.string.total);
txtColumn1.setTypeface(null, Typeface.BOLD_ITALIC);
txtColumn2.setText(R.string.total);
txtColumn2.setTypeface(null, Typeface.BOLD_ITALIC);
ListView listView = getListView();
listView.addFooterView(footer);
}
private void updateFooter(Cursor data) {
if (data == null) return;
String display;
// number of records
display = Integer.toString(data.getCount()) + " " + getString(R.string.records) + ", ";
// sum
Money total = MoneyFactory.fromString("0");
if (data.getCount() != 0) {
total = getTotalFromCursor(data);
}
TextView txtColumn2 = (TextView) this.footer.findViewById(R.id.textViewColumn2);
CurrencyService currencyService = new CurrencyService(getContext());
display += currencyService.getBaseCurrencyFormatted(total);
txtColumn2.setText(display);
}
private Money getTotalFromCursor(Cursor cursor) {
Money total = MoneyFactory.fromString("0");
int originalPosition = cursor.getPosition();
AllDataAdapter adapter = getAllDataAdapter();
CurrencyService currencyService = new CurrencyService(getContext());
int baseCurrencyId = currencyService.getBaseCurrencyId();
ContentValues values = new ContentValues();
int currencyId;
Money amount;
Money converted;
String transType;
TransactionTypes transactionType;
cursor.moveToPosition(Constants.NOT_SET);
while(cursor.moveToNext()) {
values.clear();
// Read needed data.
DatabaseUtils.cursorStringToContentValues(cursor, adapter.TRANSACTIONTYPE, values);
DatabaseUtils.cursorIntToContentValues(cursor, adapter.CURRENCYID, values);
DatabaseUtils.cursorIntToContentValues(cursor, adapter.TOCURRENCYID, values);
DatabaseUtils.cursorDoubleToCursorValues(cursor, adapter.AMOUNT, values);
DatabaseUtils.cursorDoubleToCursorValues(cursor, adapter.TOAMOUNT, values);
transType = values.getAsString(adapter.TRANSACTIONTYPE);
transactionType = TransactionTypes.valueOf(transType);
if (transactionType.equals(TransactionTypes.Transfer)) {
currencyId = values.getAsInteger(adapter.TOCURRENCYID);
amount = MoneyFactory.fromString(values.getAsString(adapter.TOAMOUNT));
} else {
currencyId = values.getAsInteger(adapter.CURRENCYID);
amount = MoneyFactory.fromString(values.getAsString(adapter.AMOUNT));
}
converted = currencyService.doCurrencyExchange(baseCurrencyId, amount, currencyId);
total = total.add(converted);
}
cursor.moveToPosition(originalPosition);
return total;
}
private boolean setStatusCheckingAccount(int[] transId, String status) {
// check if status = "U" convert to empty string
if (TextUtils.isEmpty(status) || "U".equalsIgnoreCase(status)) status = "";
SyncManager sync = new SyncManager(getActivity());
// Pause synchronization while bulk processing.
sync.disableAutoUpload();
for (int id : transId) {
// content value for updates
ContentValues values = new ContentValues();
// set new state
values.put(ITransactionEntity.STATUS, status.toUpperCase());
AccountTransactionRepository repo = new AccountTransactionRepository(getActivity());
// update
int updateResult = getActivity().getContentResolver().update(repo.getUri(),
values,
AccountTransaction.TRANSID + "=?",
new String[]{Integer.toString(id)});
if (updateResult <= 0) {
Toast.makeText(getActivity(), R.string.db_update_failed, Toast.LENGTH_LONG).show();
sync.enableAutoUpload();
sync.dataChanged();
return false;
}
}
// Now notify Dropbox about modifications.
sync.enableAutoUpload();
sync.dataChanged();
return true;
}
/**
* @param transactionIds primary key of transaction
*/
private void showDialogDeleteCheckingAccount(final ArrayList<Integer> transactionIds) {
// create alert binaryDialog and set title and message
MaterialDialog.Builder alertDialog = new MaterialDialog.Builder(getContext())
.title(R.string.delete_transaction)
.icon(new UIHelper(getActivity()).getIcon(GoogleMaterial.Icon.gmd_warning))
.content(getResources().getQuantityString(R.plurals.plurals_delete_transactions,
transactionIds.size(), transactionIds.size()));
// alert.setIcon(R.drawable.ic_action_warning_light);
// set listener button positive
alertDialog.positiveText(android.R.string.ok);
alertDialog.onPositive(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
SyncManager sync = new SyncManager(getActivity());
// Pause sync notification while bulk processing.
sync.disableAutoUpload();
for (int transactionId : transactionIds) {
// First delete any splits. See if there are any split records.
SplitCategoriesRepository splitRepo = new SplitCategoriesRepository(getActivity());
Cursor curSplit = getActivity().getContentResolver().query(splitRepo.getUri(), null,
SplitCategory.TRANSID + "=" + Integer.toString(transactionId),
null, SplitCategory.SPLITTRANSID);
int splitCount = curSplit.getCount();
curSplit.close();
if (splitCount > 0) {
int deleteResult = getActivity().getContentResolver().delete(splitRepo.getUri(),
SplitCategory.TRANSID + "=?",
new String[]{Integer.toString(transactionId)});
if (deleteResult != splitCount) {
Toast.makeText(getActivity(), R.string.db_delete_failed, Toast.LENGTH_SHORT).show();
// Now notify Dropbox about modifications.
sync.enableAutoUpload();
sync.dataChanged();
return;
}
}
// Delete the transaction.
AccountTransactionRepository repo = new AccountTransactionRepository(getActivity());
int deleteResult = getActivity().getContentResolver().delete(repo.getUri(),
AccountTransaction.TRANSID + "=?",
new String[]{Integer.toString(transactionId)});
if (deleteResult == 0) {
Toast.makeText(getActivity(), R.string.db_delete_failed, Toast.LENGTH_SHORT).show();
// Now notify Dropbox about modifications.
sync.enableAutoUpload();
sync.dataChanged();
return;
}
}
// Now notify Dropbox about modifications.
sync.enableAutoUpload();
sync.dataChanged();
// restart loader
loadData();
}
});
// set listener negative button
alertDialog.negativeText(android.R.string.cancel);
alertDialog.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.cancel();
}
});
alertDialog.build().show();
}
/**
* start the activity of transaction management
*
* @param transId null set if you want to do a new transaction, or transaction id
*/
private void startEditAccountTransactionActivity(Integer transId) {
// create intent, set Account ID
Intent intent = new Intent(getActivity(), CheckingTransactionEditActivity.class);
// check transId not null
if (transId != null) {
intent.putExtra(EditTransactionActivityConstants.KEY_TRANS_ID, transId);
intent.setAction(Intent.ACTION_EDIT);
} else {
intent.putExtra(EditTransactionActivityConstants.KEY_ACCOUNT_ID, this.AccountId);
intent.setAction(Intent.ACTION_INSERT);
}
// launch activity
startActivity(intent);
}
private AllDataAdapter getAllDataAdapter() {
AllDataAdapter adapter = null;
ListAdapter listAdapter = getListAdapter();
if (listAdapter != null && listAdapter instanceof AllDataAdapter) {
adapter = (AllDataAdapter) getListAdapter();
}
return adapter;
}
private void selectAllRecords() {
AllDataAdapter adapter = getAllDataAdapter();
if(adapter == null) return;
// Clear selection first.
adapter.clearPositionChecked();
int numRecords = adapter.getCount();
for (int i = 0; i < numRecords; i++) {
adapter.setPositionChecked(i, true);
}
adapter.notifyDataSetChanged();
}
private ArrayList<Integer> getTransactionIds(){
final ArrayList<Integer> transIds = new ArrayList<>();
AllDataAdapter adapter = getAllDataAdapter();
if(adapter == null) return transIds;
Cursor cursor = adapter.getCursor();
if (cursor != null) {
// get checked items & count from the adapter, not from the list view.
// List view only contains the one that was tapped, ignoring the Select All.
// SparseBooleanArray positionChecked = getListView().getCheckedItemPositions();
SparseBooleanArray positionChecked = adapter.getPositionsChecked();
// int checkedItemsCount = getListView().getCheckedItemCount();
int checkedItemsCount = positionChecked.size();
for (int i = 0; i < checkedItemsCount; i++) {
int position = positionChecked.keyAt(i);
// This screws up the selection?
// if (getListHeader() != null)
// position--;
if (cursor.moveToPosition(position)) {
transIds.add(cursor.getInt(cursor.getColumnIndex(QueryAllData.ID)));
}
}
}
return transIds;
}
private void changeTransactionStatus(final ArrayList<Integer> transIds){
final DrawerMenuItemAdapter adapter = new DrawerMenuItemAdapter(getActivity());
// final Core core = new Core(getActivity().getApplicationContext());
final Boolean isDarkTheme = new UIHelper(getActivity()).isUsingDarkTheme();
// add status
adapter.add(new DrawerMenuItem().withId(R.id.menu_none)
.withText(getString(R.string.status_none))
.withIcon(isDarkTheme ? R.drawable.ic_action_help_dark : R.drawable.ic_action_help_light)
.withShortcut(""));
adapter.add(new DrawerMenuItem().withId(R.id.menu_reconciled)
.withText(getString(R.string.status_reconciled))
.withIcon(isDarkTheme ? R.drawable.ic_action_done_dark : R.drawable.ic_action_done_light)
.withShortcut("R"));
adapter.add(new DrawerMenuItem().withId(R.id.menu_follow_up)
.withText(getString(R.string.status_follow_up))
.withIcon(isDarkTheme ? R.drawable.ic_action_alarm_on_dark : R.drawable.ic_action_alarm_on_light)
.withShortcut("F"));
adapter.add(new DrawerMenuItem().withId(R.id.menu_duplicate)
.withText(getString(R.string.status_duplicate))
.withIcon(isDarkTheme ? R.drawable.ic_action_copy_dark : R.drawable.ic_action_copy_light)
.withShortcut("D"));
adapter.add(new DrawerMenuItem().withId(R.id.menu_void)
.withText(getString(R.string.status_void))
.withIcon(isDarkTheme ? R.drawable.ic_action_halt_dark : R.drawable.ic_action_halt_light)
.withShortcut("V"));
// open binaryDialog
final MaterialDialog dialog = new MaterialDialog.Builder(getActivity())
.title(getString(R.string.change_status))
.adapter(adapter, null)
.build();
ListView listView = dialog.getListView();
if (listView != null) listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
DrawerMenuItem item = adapter.getItem(position);
switch (item.getId()) {
case R.id.menu_none:
case R.id.menu_reconciled:
case R.id.menu_follow_up:
case R.id.menu_duplicate:
case R.id.menu_void:
String status = item.getShortcut();
if (setStatusCheckingAccount(convertArrayListToArray(transIds), status)) {
((AllDataAdapter) getListAdapter()).clearPositionChecked();
loadData();
}
}
dialog.dismiss();
}
});
dialog.show();
}
private void showDuplicateTransactionView(ArrayList<Integer> transIds) {
// validation
int transactionCount = transIds.size();
if (transactionCount <= 0) return;
int[] ids = convertArrayListToArray(transIds);
Intent[] intents = new Intent[transactionCount];
for (int i = 0; i < transactionCount; i++) {
intents[i] = new Intent(getActivity(), CheckingTransactionEditActivity.class);
intents[i].putExtra(EditTransactionActivityConstants.KEY_TRANS_ID, ids[i]);
intents[i].setAction(Intent.ACTION_PASTE);
}
getActivity().startActivities(intents);
}
// end multi-choice-mode listener callback handlers.
private void exportToQif(){
AllDataAdapter adapter = (AllDataAdapter) getListAdapter();
QifExport qif = new QifExport(getActivity());
qif.export(adapter);
}
private int[] convertArrayListToArray(ArrayList<Integer> list) {
int[] result = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
result[i] = list.get(i);
}
return result;
}
/**
* Returns the latest-set arguments. This is because the original arguments, when the
* fragment was created, can not be altered.
* But, when an account changes, we need to modify them. The new arguments are passed
* through the call to loadData().
* @return
*/
private Bundle getLatestArguments() {
if (mArguments == null) {
mArguments = getArguments();
}
return mArguments;
}
private void setLatestArguments(Bundle arguments) {
mArguments = arguments;
}
}