/*
* 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.reports;
import android.content.ContentValues;
import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteQueryBuilder;
import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.money.manager.ex.R;
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.ViewMobileData;
import com.money.manager.ex.search.CategorySub;
import com.money.manager.ex.search.SearchActivity;
import com.money.manager.ex.search.SearchParameters;
import org.parceler.Parcels;
import java.util.ArrayList;
import info.javaperformance.money.Money;
import info.javaperformance.money.MoneyFactory;
import timber.log.Timber;
/**
* Categories report fragment.
*/
public class CategoriesReportFragment
extends BaseReportFragment {
private LinearLayout mListViewFooter;
@Override
public void onActivityCreated(Bundle savedInstanceState) {
setListAdapter(null);
setSearchMenuVisible(true);
//create header view
LinearLayout mListViewHeader = (LinearLayout) addListViewHeaderFooter(R.layout.item_generic_report_2_columns);
TextView txtColumn1 = (TextView) mListViewHeader.findViewById(R.id.textViewColumn1);
TextView txtColumn2 = (TextView) mListViewHeader.findViewById(R.id.textViewColumn2);
//set header
txtColumn1.setText(R.string.category);
txtColumn1.setTypeface(null, Typeface.BOLD);
txtColumn2.setText(R.string.amount);
txtColumn2.setTypeface(null, Typeface.BOLD);
//add to list view
getListView().addHeaderView(mListViewHeader);
//create footer view
mListViewFooter = (LinearLayout) addListViewHeaderFooter(R.layout.item_generic_report_2_columns);
txtColumn1 = (TextView) mListViewFooter.findViewById(R.id.textViewColumn1);
txtColumn2 = (TextView) mListViewFooter.findViewById(R.id.textViewColumn2);
//set footer
txtColumn1.setText(R.string.total);
txtColumn1.setTypeface(null, Typeface.BOLD_ITALIC);
txtColumn2.setText(R.string.total);
txtColumn2.setTypeface(null, Typeface.BOLD_ITALIC);
//add to list view --> move to load finished
//getListView().addFooterView(mListViewFooter);
//set adapter
CategoriesReportAdapter adapter = new CategoriesReportAdapter(getActivity(), null);
setListAdapter(adapter);
//call super method
super.onActivityCreated(savedInstanceState);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
// pie chart
MenuItem itemChart = menu.findItem(R.id.menu_chart);
if (itemChart != null) {
itemChart.setVisible(!(((CategoriesReportActivity) getActivity()).mIsDualPanel));
UIHelper uiHelper = new UIHelper(getActivity());
itemChart.setIcon(uiHelper.resolveAttribute(R.attr.ic_action_pie_chart));
}
}
// Loader
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
super.onLoadFinished(loader, data);
switch (loader.getId()) {
case ID_LOADER:
//parse cursor for calculate total
if (data == null) return;
CurrencyService currencyService = new CurrencyService(getActivity().getApplicationContext());
Money totalAmount = MoneyFactory.fromString("0");
while (data.moveToNext()) {
String totalRow = data.getString(data.getColumnIndex("TOTAL"));
if (!TextUtils.isEmpty(totalRow)) {
totalAmount = totalAmount.add(MoneyFactory.fromString(totalRow));
} else {
new UIHelper(getActivity()).showToast("reading total");
}
}
TextView txtColumn2 = (TextView) mListViewFooter.findViewById(R.id.textViewColumn2);
txtColumn2.setText(currencyService.getBaseCurrencyFormatted(totalAmount));
// solved bug chart
if (data.getCount() > 0) {
getListView().removeFooterView(mListViewFooter);
getListView().addFooterView(mListViewFooter);
}
if (((CategoriesReportActivity) getActivity()).mIsDualPanel) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
showChart();
}
}, 1000);
}
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_chart:
showChart();
break;
}
if (item.getItemId() < 0) {
// category
String whereClause = getWhereClause();
if (!TextUtils.isEmpty(whereClause))
whereClause += " AND ";
else
whereClause = "";
whereClause += " " + ViewMobileData.CATEGID + "=" + Integer.toString(Math.abs(item.getItemId()));
//create arguments
Bundle args = new Bundle();
args.putString(KEY_WHERE_CLAUSE, whereClause);
//starts loader
startLoader(args);
}
return super.onOptionsItemSelected(item);
}
@Override
protected boolean onQueryTextChange(String newText) {
//recall last where clause
String whereClause = getWhereClause();
if (whereClause == null) whereClause = "";
int start = whereClause.indexOf("/** */");
if (start > 0) {
int end = whereClause.indexOf("/** */", start + 1) + "/** */".length();
whereClause = whereClause.substring(0, start) + whereClause.substring(end);
// trim some space
whereClause = whereClause.trim();
}
if (!TextUtils.isEmpty(whereClause)) {
whereClause += " /** */AND ";
} else {
whereClause = "/** */";
}
// use token to replace criteria
whereClause += "(" + ViewMobileData.Category + " Like '%" + newText + "%' OR " +
ViewMobileData.Subcategory + " Like '%" + newText + "%')/** */";
//create arguments
Bundle args = new Bundle();
args.putString(KEY_WHERE_CLAUSE, whereClause);
//starts loader
startLoader(args);
return super.onQueryTextChange(newText);
}
@Override
protected String prepareQuery(String whereClause) {
SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
ViewMobileData mobileData = new ViewMobileData(getContext());
//data to compose builder
String[] projectionIn = new String[]{
"ROWID AS _id", // this does not fetch anything, unfortunately.
ViewMobileData.CATEGID, ViewMobileData.Category,
ViewMobileData.SubcategID, ViewMobileData.Subcategory,
"SUM(" + ViewMobileData.AmountBaseConvRate + ") AS TOTAL"
};
String selection = ViewMobileData.Status + "<>'V' AND " +
ViewMobileData.TransactionType + " IN ('Withdrawal', 'Deposit')";
if (!TextUtils.isEmpty(whereClause)) {
selection += " AND " + whereClause;
}
String groupBy = ViewMobileData.CATEGID + ", " + ViewMobileData.Category + ", " +
ViewMobileData.SubcategID + ", " + ViewMobileData.Subcategory;
String having = null;
if (!TextUtils.isEmpty(((CategoriesReportActivity) getActivity()).mFilter)) {
String filter = ((CategoriesReportActivity) getActivity()).mFilter;
if (TransactionTypes.valueOf(filter).equals(TransactionTypes.Withdrawal)) {
having = "SUM(" + ViewMobileData.AmountBaseConvRate + ") < 0";
} else {
having = "SUM(" + ViewMobileData.AmountBaseConvRate + ") > 0";
}
}
String sortOrder = ViewMobileData.Category + ", " + ViewMobileData.Subcategory;
//compose builder
builder.setTables(mobileData.getSource());
//return query
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
return builder.buildQuery(projectionIn, selection, groupBy, having, sortOrder, null);
} else {
return builder.buildQuery(projectionIn, selection, null, groupBy, having, sortOrder, null);
}
}
@Override
public String getSubTitle() {
return null;
}
/**
* List item clicked. Show the transaction list for the category.
* @param l The ListView where the click happened
* @param v The view that was clicked within the ListView
* @param position The position of the view in the list
* @param id The row id of the item that was clicked
*/
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
CategorySub category = null;
try {
category = getCategoryFromSelectedItem(l, position);
} catch (Exception e) {
Timber.e(e, "getting category from selected item");
}
if (category == null) return;
// now list the transactions for the given category/subcategory combination,
// in the selected time period.
// showTransactionsFragment(values);
// Show search activity with the results.
SearchParameters parameters = new SearchParameters();
parameters.category = category;
parameters.dateFrom = mDateFrom;
parameters.dateTo = mDateTo;
showSearchActivityFor(parameters);
}
public void showChart() {
CategoriesReportAdapter adapter = (CategoriesReportAdapter) getListAdapter();
if (adapter == null) return;
Cursor cursor = adapter.getCursor();
if (cursor == null) return;
if (cursor.getCount() <= 0) return;
ArrayList<ValuePieEntry> arrayList = new ArrayList<>();
CurrencyService currencyService = new CurrencyService(getActivity().getApplicationContext());
// Reset cursor to initial position.
cursor.moveToPosition(-1);
// process cursor
while (cursor.moveToNext()) {
ValuePieEntry item = new ValuePieEntry();
String category = cursor.getString(cursor.getColumnIndex(ViewMobileData.Category));
if (!TextUtils.isEmpty(cursor.getString(cursor.getColumnIndex(ViewMobileData.Subcategory)))) {
category += " : " + cursor.getString(cursor.getColumnIndex(ViewMobileData.Subcategory));
}
// total
double total = Math.abs(cursor.getDouble(cursor.getColumnIndex("TOTAL")));
// check if category is empty
if (TextUtils.isEmpty(category)) {
category = getString(R.string.empty_category);
}
item.setText(category);
item.setValue(total);
item.setValueFormatted(currencyService.getCurrencyFormatted(currencyService.getBaseCurrencyId(),
MoneyFactory.fromDouble(total)));
// add element
arrayList.add(item);
}
Bundle args = new Bundle();
args.putSerializable(PieChartFragment.KEY_CATEGORIES_VALUES, arrayList);
//get fragment manager
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
if (fragmentManager != null) {
PieChartFragment fragment;
fragment = (PieChartFragment) fragmentManager.findFragmentByTag(IncomeVsExpensesChartFragment.class.getSimpleName());
if (fragment == null) {
fragment = new PieChartFragment();
}
fragment.setChartArguments(args);
fragment.setDisplayHomeAsUpEnabled(true);
if (fragment.isVisible()) fragment.onResume();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (((CategoriesReportActivity) getActivity()).mIsDualPanel) {
fragmentTransaction.replace(R.id.fragmentChart, fragment, PieChartFragment.class.getSimpleName());
} else {
fragmentTransaction.replace(R.id.fragmentMain, fragment, PieChartFragment.class.getSimpleName());
fragmentTransaction.addToBackStack(null);
}
fragmentTransaction.commit();
}
}
// Private
private CategorySub getCategoryFromSelectedItem(ListView l, int position) {
// Reading item from the list view, not adapter!
Object item = l.getItemAtPosition(position);
if (item == null) return null;
Cursor cursor = (Cursor) item;
ContentValues values = new ContentValues();
DatabaseUtils.cursorIntToContentValues(cursor, ViewMobileData.CATEGID, values);
DatabaseUtils.cursorStringToContentValues(cursor, ViewMobileData.Category, values);
DatabaseUtils.cursorIntToContentValues(cursor, ViewMobileData.SubcategID, values);
DatabaseUtils.cursorStringToContentValues(cursor, ViewMobileData.Subcategory, values);
CategorySub result = new CategorySub();
result.categId = values.getAsInteger(ViewMobileData.CATEGID);
result.categName = values.getAsString(ViewMobileData.Category);
result.subCategId = values.getAsInteger(ViewMobileData.SubcategID);
result.subCategName = values.getAsString(ViewMobileData.Subcategory);
return result;
}
private void showSearchActivityFor(SearchParameters parameters) {
Intent intent = new Intent(getActivity(), SearchActivity.class);
intent.putExtra(SearchActivity.EXTRA_SEARCH_PARAMETERS, Parcels.wrap(parameters));
intent.setAction(Intent.ACTION_INSERT);
startActivity(intent);
}
}