/******************************************************************************* * Copyright (c) 2010 Denis Solonenko. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * * Contributors: * Denis Solonenko - initial API and implementation ******************************************************************************/ package ru.orangesoftware.financisto2.activity; import android.app.ListActivity; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Color; import android.os.AsyncTask; import android.os.Bundle; import android.text.format.DateUtils; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.view.animation.*; import android.widget.ImageButton; import android.widget.ListView; import android.widget.TextView; import org.achartengine.ChartFactory; import org.achartengine.model.CategorySeries; import org.achartengine.renderer.DefaultRenderer; import org.achartengine.renderer.SimpleSeriesRenderer; import ru.orangesoftware.financisto2.R; import ru.orangesoftware.financisto2.adapter.ReportAdapter; import ru.orangesoftware.financisto2.db.CategoryRepository; import ru.orangesoftware.financisto2.db.CategoryRepository_; import ru.orangesoftware.financisto2.db.DatabaseAdapter_; import ru.orangesoftware.financisto2.filter.WhereFilter; import ru.orangesoftware.financisto2.filter.Criteria; import ru.orangesoftware.financisto2.db.DatabaseAdapter; import ru.orangesoftware.financisto2.db.DatabaseHelper.ReportColumns; import ru.orangesoftware.financisto2.graph.GraphUnit; import ru.orangesoftware.financisto2.model.Total; import ru.orangesoftware.financisto2.report.IncomeExpense; import ru.orangesoftware.financisto2.report.PeriodReport; import ru.orangesoftware.financisto2.report.Report; import ru.orangesoftware.financisto2.report.ReportData; import ru.orangesoftware.financisto2.utils.PinProtection; import ru.orangesoftware.financisto2.utils.Utils; import java.math.BigDecimal; import static ru.orangesoftware.financisto2.utils.AndroidUtils.isGreenDroidSupported; public class ReportActivity extends ListActivity implements RefreshSupportedActivity { protected static final int FILTER_REQUEST = 1; public static final String FILTER_INCOME_EXPENSE = "FILTER_INCOME_EXPENSE"; private DatabaseAdapter db; private CategoryRepository categoryRepository; private ImageButton bFilter; private ImageButton bToggle; private Report currentReport; private ReportAsyncTask reportTask; private WhereFilter filter = WhereFilter.empty(); private boolean saveFilter = false; private IncomeExpense incomeExpenseState = IncomeExpense.BOTH; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); setContentView(R.layout.report); db = DatabaseAdapter_.getInstance_(this); categoryRepository = CategoryRepository_.getInstance_(this); bFilter = (ImageButton)findViewById(R.id.bFilter); bFilter.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { Intent intent = new Intent(ReportActivity.this, ReportFilterActivity.class); filter.toIntent(intent); startActivityForResult(intent, FILTER_REQUEST); } }); bToggle = (ImageButton)findViewById(R.id.bToggle); bToggle.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { toggleIncomeExpense(); } }); ImageButton bPieChart = (ImageButton) findViewById(R.id.bPieChart); if (isGreenDroidSupported()) { bPieChart.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { showPieChart(); } }); } else { bPieChart.setVisibility(View.GONE); } Intent intent = getIntent(); if (intent != null) { currentReport = ReportsListActivity.createReport(this, db, intent.getExtras()); filter = WhereFilter.fromIntent(intent); if (intent.hasExtra(FILTER_INCOME_EXPENSE)) { incomeExpenseState = IncomeExpense.valueOf(intent.getStringExtra(FILTER_INCOME_EXPENSE)); } if (filter.isEmpty()) { loadFilter(); } selectReport(); } applyFilter(); applyIncomeExpense(); showOrRemoveTotals(); } private SharedPreferences getPreferencesForReport() { return getSharedPreferences("ReportActivity_"+currentReport.reportType.name()+"_DEFAULT", 0); } private void toggleIncomeExpense() { IncomeExpense[] values = IncomeExpense.values(); int nextIndex = incomeExpenseState.ordinal() + 1; incomeExpenseState = nextIndex < values.length ? values[nextIndex] : values[0]; applyIncomeExpense(); saveFilter(); selectReport(); } private void applyIncomeExpense() { String reportTitle = getString(currentReport.reportType.titleId); String incomeExpenseTitle = getString(incomeExpenseState.getTitleId()); setTitle(reportTitle+" ("+incomeExpenseTitle+")"); bToggle.setImageDrawable(getResources().getDrawable(incomeExpenseState.getIconId())); } private void showPieChart() { new PieChartGeneratorTask().execute(); } @Override protected void onPause() { super.onPause(); PinProtection.lock(this); } @Override protected void onResume() { super.onResume(); PinProtection.unlock(this); } private void showOrRemoveTotals() { if (!currentReport.shouldDisplayTotal()) { findViewById(R.id.total).setVisibility(View.GONE); } } private void applyAnimationToListView() { AnimationSet set = new AnimationSet(true); Animation animation = new AlphaAnimation(0.0f, 1.0f); animation.setDuration(50); set.addAnimation(animation); animation = new TranslateAnimation( Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f, Animation.RELATIVE_TO_SELF, 0.0f ); animation.setDuration(100); set.addAnimation(animation); LayoutAnimationController controller = new LayoutAnimationController(set, 0.5f); ListView listView = getListView(); listView.setLayoutAnimation(controller); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { if (currentReport != null) { Intent intent = currentReport.createActivityIntent(this, categoryRepository, WhereFilter.copyOf(filter), id); startActivity(intent); } } private void selectReport() { cancelCurrentReportTask(); reportTask = new ReportAsyncTask(currentReport, incomeExpenseState); reportTask.execute(); } private void cancelCurrentReportTask() { if (reportTask != null) { reportTask.cancel(true); } } private void applyFilter() { TextView tv = (TextView)findViewById(R.id.period); if (currentReport instanceof PeriodReport) { disableFilter(); tv.setVisibility(View.GONE); } else { Criteria c = filter.get(ReportColumns.DATETIME); if (c != null) { tv.setText(DateUtils.formatDateRange(this, c.getLongValue1(), c.getLongValue2(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_MONTH)); } else { tv.setText(R.string.no_filter); } enableFilter(); tv.setVisibility(View.VISIBLE); } } protected void disableFilter() { bFilter.setEnabled(false); bFilter.setImageResource(R.drawable.ic_menu_filter_off); } protected void enableFilter() { bFilter.setEnabled(true); bFilter.setImageResource(filter.isEmpty() ? R.drawable.ic_menu_filter_off : R.drawable.ic_menu_filter_on); } @Override protected void onDestroy() { cancelCurrentReportTask(); super.onDestroy(); } @Override public void recreateCursor() { selectReport(); } @Override public void integrityCheck() { } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == FILTER_REQUEST) { if (resultCode == RESULT_FIRST_USER) { filter.clear(); saveFilter(); selectReport(); } else if (resultCode == RESULT_OK) { filter = WhereFilter.fromIntent(data); saveFilter(); selectReport(); } } } private void saveFilter() { if (saveFilter) { SharedPreferences preferences = getPreferencesForReport(); filter.toSharedPreferences(preferences); SharedPreferences.Editor editor = preferences.edit(); editor.putString(FILTER_INCOME_EXPENSE, incomeExpenseState.name()); editor.commit(); } applyFilter(); } private void loadFilter() { SharedPreferences preferences = getPreferencesForReport(); filter = WhereFilter.fromSharedPreferences(preferences); incomeExpenseState = IncomeExpense.valueOf(preferences.getString(FILTER_INCOME_EXPENSE, IncomeExpense.BOTH.name())); saveFilter = true; } private void displayTotal(Total total) { if (currentReport.shouldDisplayTotal()) { TextView totalText = (TextView)findViewById(R.id.total); Utils u = new Utils(this); u.setTotal(totalText, total); } } private class ReportAsyncTask extends AsyncTask<Void, Void, ReportData> { private final Report report; private final IncomeExpense incomeExpense; private ReportAsyncTask(Report report, IncomeExpense incomeExpense) { this.report = report; this.incomeExpense = incomeExpense; } @Override protected void onPreExecute() { setProgressBarIndeterminateVisibility(true); ((TextView)findViewById(android.R.id.empty)).setText(R.string.calculating); } @Override protected ReportData doInBackground(Void...voids) { report.setIncomeExpense(incomeExpense); return report.getReport(db, WhereFilter.copyOf(filter)); } @Override protected void onPostExecute(ReportData data) { setProgressBarIndeterminateVisibility(false); displayTotal(data.total); ((TextView) findViewById(android.R.id.empty)).setText(R.string.empty_report); ReportAdapter adapter = new ReportAdapter(ReportActivity.this, data.units); setListAdapter(adapter); applyAnimationToListView(); } } private class PieChartGeneratorTask extends AsyncTask<Void, Void, Intent> { @Override protected void onPreExecute() { setProgressBarIndeterminateVisibility(true); } @Override protected Intent doInBackground(Void... voids) { return createPieChart(); } private Intent createPieChart() { DefaultRenderer renderer = new DefaultRenderer(); renderer.setLabelsTextSize(getResources().getDimension(R.dimen.report_labels_text_size)); renderer.setLegendTextSize(getResources().getDimension(R.dimen.report_legend_text_size)); renderer.setMargins(new int[] { 0, 0, 0, 0 }); ReportData report = currentReport.getReportForChart(db, WhereFilter.copyOf(filter)); CategorySeries series = new CategorySeries("AAA"); long total = Math.abs(report.total.amount)+Math.abs(report.total.balance); int[] colors = generateColors(2*report.units.size()); int i = 0; for (GraphUnit unit : report.units) { addSeries(series, renderer, unit.name, unit.getIncomeExpense().income, total, colors[i++]); addSeries(series, renderer, unit.name, unit.getIncomeExpense().expense, total, colors[i++]); } renderer.setZoomButtonsVisible(true); renderer.setZoomEnabled(true); renderer.setChartTitleTextSize(20); return ChartFactory.getPieChartIntent(ReportActivity.this, series, renderer, getString(R.string.report)); } public int[] generateColors(int n) { int[] colors = new int[n]; for (int i = 0; i < n; i++) { colors[i] = Color.HSVToColor(new float[]{360*(float)i/(float)n, .75f, .85f}); } return colors; } private void addSeries(CategorySeries series, DefaultRenderer renderer, String name, BigDecimal expense, long total, int color) { long amount = expense.longValue(); if (amount != 0 && total != 0) { long percentage = 100*Math.abs(amount)/total; series.add((amount > 0 ? "+" : "-") + name + "(" + percentage + "%)", percentage); SimpleSeriesRenderer r = new SimpleSeriesRenderer(); r.setColor(color); renderer.addSeriesRenderer(r); } } @Override protected void onPostExecute(Intent intent) { setProgressBarIndeterminateVisibility(false); startActivity(intent); } } }