diff --git a/app/build.gradle b/app/build.gradle
index 508e08a..6a7902c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -48,8 +48,14 @@ dependencies {
compile 'com.android.support:support-v4:23.2.1'
compile 'com.android.support:appcompat-v7:23.2.1'
compile 'com.android.support:design:23.2.1'
+ // View annotation bindings
compile 'com.jakewharton:butterknife:7.0.1'
+ // Dependency injection tool
compile 'com.google.dagger:dagger:2.0.1'
+ // Charts
+ compile 'com.github.PhilJay:MPAndroidChart:v2.2.4'
+ // Advanced logging tool
+ compile 'com.jakewharton.timber:timber:4.1.2'
apt 'com.google.dagger:dagger-compiler:2.0.1'
provided 'org.glassfish:javax.annotation:10.0-b28'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 49cd21d..5054471 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -68,6 +68,11 @@
android:label="@string/title_settings"
android:screenOrientation="portrait"
android:theme="@style/Theme.Default" />
+
recordList = recordController.readAll();
+ List currencyNeeded = reportMaker.currencyNeeded(currency, recordList);
+
+ IMonthReport monthReport = null;
+ if (currencyNeeded.isEmpty()) monthReport = reportMaker.getMonthReport(currency, recordList);
+ else barChart.setNoDataText(createRatesNeededList(currency, currencyNeeded));
+
+ if (monthReport != null) {
+ BarChartConverter barChartConverter = new BarChartConverter(ChartsActivity.this,
+ monthReport);
+
+ BarData barData = new BarData(barChartConverter.getXAxisValueList(),
+ barChartConverter.getBarDataSetList());
+ barData.setDrawValues(false);
+
+ barChart.setData(barData);
+ barChart.setDescription(null);
+ barChart.setVisibleXRangeMinimum(8);
+ barChart.setScaleYEnabled(false);
+ barChart.setVisibleXRangeMaximum(34);
+ barChart.setHighlightPerDragEnabled(false);
+ barChart.setHighlightPerTapEnabled(false);
+ }
+ }
+
+ protected String createRatesNeededList(String currency, List ratesNeeded) {
+ StringBuilder sb = new StringBuilder(getString(R.string.error_exchange_rates));
+
+ for (String str : ratesNeeded) {
+ sb.append("\n").append(str).append(getString(R.string.arrow)).append(currency);
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/ExportActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/ExportActivity.java
index 0842275..7fd3cad 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/ExportActivity.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/ExportActivity.java
@@ -4,7 +4,6 @@
import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.content.FileProvider;
-import android.util.Log;
import com.blogspot.e_kanivets.moneytracker.R;
import com.blogspot.e_kanivets.moneytracker.activity.base.BaseBackActivity;
@@ -18,6 +17,7 @@
import javax.inject.Inject;
import butterknife.OnClick;
+import timber.log.Timber;
public class ExportActivity extends BaseBackActivity {
@SuppressWarnings("unused")
@@ -46,7 +46,7 @@ public void exportRecords() {
File exportDir = new File(getCacheDir(), "export");
boolean exportDirCreated = exportDir.mkdirs();
- Log.d(TAG, "exportDirCreated: " + exportDirCreated);
+ Timber.d("ExportDirCreated: %b", exportDirCreated);
File outFile;
if (exportDir.exists()) outFile = new File(exportDir, DEFAULT_EXPORT_FILE_NAME);
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/ReportActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/ReportActivity.java
index c81ff4b..02be4fc 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/ReportActivity.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/ReportActivity.java
@@ -13,9 +13,9 @@
import com.blogspot.e_kanivets.moneytracker.controller.data.ExchangeRateController;
import com.blogspot.e_kanivets.moneytracker.entity.Period;
import com.blogspot.e_kanivets.moneytracker.entity.data.Record;
-import com.blogspot.e_kanivets.moneytracker.report.ReportConverter;
+import com.blogspot.e_kanivets.moneytracker.report.record.RecordReportConverter;
import com.blogspot.e_kanivets.moneytracker.report.ReportMaker;
-import com.blogspot.e_kanivets.moneytracker.report.base.IReport;
+import com.blogspot.e_kanivets.moneytracker.report.record.IRecordReport;
import com.blogspot.e_kanivets.moneytracker.ui.presenter.ShortSummaryPresenter;
import java.util.List;
@@ -77,13 +77,13 @@ protected void initViews() {
private void update(String currency) {
ReportMaker reportMaker = new ReportMaker(rateController);
- IReport report = reportMaker.getReport(currency, period, recordList);
+ IRecordReport report = reportMaker.getRecordReport(currency, period, recordList);
ExpandableListReportAdapter adapter = null;
if (report != null) {
- ReportConverter reportConverter = new ReportConverter(report);
- adapter = new ExpandableListReportAdapter(ReportActivity.this, reportConverter);
+ RecordReportConverter recordReportConverter = new RecordReportConverter(report);
+ adapter = new ExpandableListReportAdapter(ReportActivity.this, recordReportConverter);
}
expandableListView.setAdapter(adapter);
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/base/BaseDrawerActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/base/BaseDrawerActivity.java
index 9025cea..afdd7e1 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/base/BaseDrawerActivity.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/base/BaseDrawerActivity.java
@@ -9,6 +9,7 @@
import android.view.MenuItem;
import com.blogspot.e_kanivets.moneytracker.R;
+import com.blogspot.e_kanivets.moneytracker.activity.ChartsActivity;
import com.blogspot.e_kanivets.moneytracker.activity.ExportActivity;
import com.blogspot.e_kanivets.moneytracker.activity.SettingsActivity;
import com.blogspot.e_kanivets.moneytracker.activity.account.AccountsActivity;
@@ -77,6 +78,10 @@ public boolean onNavigationItemSelected(MenuItem item) {
REQUEST_RATES);
break;
+ case R.id.nav_charts:
+ startActivity(new Intent(BaseDrawerActivity.this, ChartsActivity.class));
+ break;
+
case R.id.nav_export:
startActivity(new Intent(BaseDrawerActivity.this, ExportActivity.class));
break;
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/record/MainActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/record/MainActivity.java
index aa24b0e..9177242 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/record/MainActivity.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/record/MainActivity.java
@@ -24,7 +24,7 @@
import com.blogspot.e_kanivets.moneytracker.entity.data.Record;
import com.blogspot.e_kanivets.moneytracker.entity.Period;
import com.blogspot.e_kanivets.moneytracker.report.ReportMaker;
-import com.blogspot.e_kanivets.moneytracker.report.base.IReport;
+import com.blogspot.e_kanivets.moneytracker.report.record.IRecordReport;
import com.blogspot.e_kanivets.moneytracker.ui.AppRateDialog;
import com.blogspot.e_kanivets.moneytracker.ui.PeriodSpinner;
import com.blogspot.e_kanivets.moneytracker.ui.presenter.ShortSummaryPresenter;
@@ -194,7 +194,7 @@ protected void update() {
String currency = currencyController.readDefaultCurrency();
ReportMaker reportMaker = new ReportMaker(rateController);
- IReport report = reportMaker.getReport(currency, period, recordList);
+ IRecordReport report = reportMaker.getRecordReport(currency, period, recordList);
summaryPresenter.update(report, currency, reportMaker.currencyNeeded(currency, recordList));
fillDefaultAccount();
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/adapter/ExpandableListReportAdapter.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/adapter/ExpandableListReportAdapter.java
index e32d48b..3b23966 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/adapter/ExpandableListReportAdapter.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/adapter/ExpandableListReportAdapter.java
@@ -8,7 +8,7 @@
import android.widget.TextView;
import com.blogspot.e_kanivets.moneytracker.R;
-import com.blogspot.e_kanivets.moneytracker.report.ReportConverter;
+import com.blogspot.e_kanivets.moneytracker.report.record.RecordReportConverter;
import java.util.List;
import java.util.Locale;
@@ -32,7 +32,7 @@ public class ExpandableListReportAdapter extends SimpleExpandableListAdapter {
private int red;
private int green;
- public ExpandableListReportAdapter(Context context, ReportConverter converter) {
+ public ExpandableListReportAdapter(Context context, RecordReportConverter converter) {
this(context, converter.getGroupData(), converter.getGroupLayout(),
converter.getGroupFrom(), converter.getGroupTo(), converter.getChildData(),
converter.getChildLayout(), converter.getChildFrom(), converter.getChildTo());
@@ -75,7 +75,7 @@ private void customizeView(View view, Map values, boolean groupV
if (viewHolder == null) viewHolder = new ViewHolder(view);
/* Customize view to fit to model and UI */
- Double price = Double.parseDouble(values.get(ReportConverter.PRICE_PARAM_NAME));
+ Double price = Double.parseDouble(values.get(RecordReportConverter.PRICE_PARAM_NAME));
if (groupView) view.setBackgroundColor(price < 0 ? whiteRed : whiteGreen);
else view.setBackgroundColor(white);
@@ -83,7 +83,7 @@ private void customizeView(View view, Map values, boolean groupV
//Set color of total
viewHolder.tvTotal.setTextColor(price >= 0 ? green : red);
- viewHolder.tvCategory.setText(values.get(ReportConverter.TITLE_PARAM_NAME));
+ viewHolder.tvCategory.setText(values.get(RecordReportConverter.TITLE_PARAM_NAME));
viewHolder.tvTotal.setText(format(price));
}
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/di/AppComponent.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/di/AppComponent.java
index 3d58913..1e9ef3d 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/di/AppComponent.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/di/AppComponent.java
@@ -1,5 +1,6 @@
package com.blogspot.e_kanivets.moneytracker.di;
+import com.blogspot.e_kanivets.moneytracker.activity.ChartsActivity;
import com.blogspot.e_kanivets.moneytracker.activity.ExportActivity;
import com.blogspot.e_kanivets.moneytracker.activity.ReportActivity;
import com.blogspot.e_kanivets.moneytracker.activity.SettingsActivity;
@@ -47,6 +48,8 @@ public interface AppComponent {
void inject(ReportActivity reportActivity);
+ void inject(ChartsActivity chartsActivity);
+
void inject(SettingsActivity.SettingsFragment settingsFragment);
void inject(AccountsSummaryPresenter accountsSummaryPresenter);
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/base/BaseRepo.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/base/BaseRepo.java
index 632d353..349d407 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/base/BaseRepo.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/base/BaseRepo.java
@@ -5,13 +5,14 @@
import android.database.sqlite.SQLiteDatabase;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.util.Log;
import com.blogspot.e_kanivets.moneytracker.repo.DbHelper;
import com.blogspot.e_kanivets.moneytracker.entity.base.IEntity;
import java.util.List;
+import timber.log.Timber;
+
/**
* Base implementation of {@link IRepo}.
* No need to call db.close() at all, because SQLiteOpenHelper manage it for us + cache instances.
@@ -21,8 +22,6 @@
* @author Evgenii Kanivets
*/
public abstract class BaseRepo implements IRepo {
- private static final String TAG = "BaseRepo";
-
protected DbHelper dbHelper;
public BaseRepo(DbHelper dbHelper) {
@@ -46,11 +45,11 @@ public T create(@Nullable T instance) {
long id = db.insert(getTable(), null, contentValues(instance));
if (id == -1) {
- Log.d(TAG, "Couldn't create record : " + instance);
+ Timber.d("Couldn't create record: %s", instance);
return null;
} else {
T createdInstance = read(id);
- Log.d(TAG, "Created record : " + createdInstance);
+ Timber.d("Created record: %s", createdInstance);
return createdInstance;
}
}
@@ -75,11 +74,11 @@ public T update(@Nullable T instance) {
long rowsAffected = db.update(getTable(), contentValues(instance), "id=?", args);
if (rowsAffected == 0) {
- Log.d(TAG, "Couldn't update record : " + instance);
+ Timber.d("Couldn't update record: %s", instance);
return null;
} else {
T updatedInstance = read(instance.getId());
- Log.d(TAG, "Updated record : " + updatedInstance);
+ Timber.d("Updated record: %s", updatedInstance);
return updatedInstance;
}
}
@@ -99,7 +98,7 @@ public boolean delete(@Nullable T instance) {
String[] args = new String[]{Long.toString(instance.getId())};
long rowsAffected = db.delete(getTable(), "id=?", args);
- Log.d(TAG, instance + (rowsAffected == 0 ? " didn't " : " ") + "deleted");
+ Timber.d("%s %s deleted", instance, (rowsAffected == 0 ? " didn't " : " "));
return rowsAffected != 0;
}
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/ReportMaker.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/ReportMaker.java
index 9e6b5f7..261cacf 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/ReportMaker.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/ReportMaker.java
@@ -8,9 +8,13 @@
import com.blogspot.e_kanivets.moneytracker.entity.data.ExchangeRate;
import com.blogspot.e_kanivets.moneytracker.entity.Period;
import com.blogspot.e_kanivets.moneytracker.entity.data.Record;
-import com.blogspot.e_kanivets.moneytracker.report.base.IAccountsReport;
+import com.blogspot.e_kanivets.moneytracker.report.account.AccountsReport;
+import com.blogspot.e_kanivets.moneytracker.report.account.IAccountsReport;
import com.blogspot.e_kanivets.moneytracker.report.base.IExchangeRateProvider;
-import com.blogspot.e_kanivets.moneytracker.report.base.IReport;
+import com.blogspot.e_kanivets.moneytracker.report.chart.IMonthReport;
+import com.blogspot.e_kanivets.moneytracker.report.chart.MonthReport;
+import com.blogspot.e_kanivets.moneytracker.report.record.IRecordReport;
+import com.blogspot.e_kanivets.moneytracker.report.record.RecordReport;
import java.util.ArrayList;
import java.util.List;
@@ -18,7 +22,7 @@
import java.util.TreeSet;
/**
- * Util class to encapsulate {@link Report} generation logic.
+ * Util class to encapsulate {@link RecordReport} generation logic.
* Created on 2/26/16.
*
* @author Evgenii Kanivets
@@ -31,11 +35,11 @@ public ReportMaker(ExchangeRateController exchangeRateController) {
}
@Nullable
- public IReport getReport(String currency, Period period, List recordList) {
+ public IRecordReport getRecordReport(String currency, Period period, List recordList) {
if (currencyNeeded(currency, recordList).size() != 0) return null;
IExchangeRateProvider rateProvider = new ExchangeRateProvider(currency, rateController);
- return new Report(currency, period, recordList, rateProvider);
+ return new RecordReport(currency, period, recordList, rateProvider);
}
@Nullable
@@ -46,6 +50,14 @@ public IAccountsReport getAccountsReport(String currency, List accountL
return new AccountsReport(currency, accountList, rateProvider);
}
+ @Nullable
+ public IMonthReport getMonthReport(String currency, List recordList) {
+ if (currencyNeeded(currency, recordList).size() != 0) return null;
+
+ IExchangeRateProvider rateProvider = new ExchangeRateProvider(currency, rateController);
+ return new MonthReport(recordList, currency, rateProvider);
+ }
+
@NonNull
public List currencyNeeded(String currency, List recordList) {
Set currencies = new TreeSet<>();
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/AccountsReport.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/account/AccountsReport.java
similarity index 92%
rename from app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/AccountsReport.java
rename to app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/account/AccountsReport.java
index 69a9ff8..50f3635 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/AccountsReport.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/account/AccountsReport.java
@@ -1,10 +1,10 @@
-package com.blogspot.e_kanivets.moneytracker.report;
+package com.blogspot.e_kanivets.moneytracker.report.account;
import android.support.annotation.NonNull;
import com.blogspot.e_kanivets.moneytracker.entity.data.Account;
import com.blogspot.e_kanivets.moneytracker.entity.data.ExchangeRate;
-import com.blogspot.e_kanivets.moneytracker.report.base.IAccountsReport;
+import com.blogspot.e_kanivets.moneytracker.report.account.IAccountsReport;
import com.blogspot.e_kanivets.moneytracker.report.base.IExchangeRateProvider;
import java.util.List;
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/base/IAccountsReport.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/account/IAccountsReport.java
similarity index 87%
rename from app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/base/IAccountsReport.java
rename to app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/account/IAccountsReport.java
index 3fbcfa0..e046e61 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/base/IAccountsReport.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/account/IAccountsReport.java
@@ -1,4 +1,4 @@
-package com.blogspot.e_kanivets.moneytracker.report.base;
+package com.blogspot.e_kanivets.moneytracker.report.account;
import android.support.annotation.NonNull;
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/chart/BarChartConverter.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/chart/BarChartConverter.java
new file mode 100644
index 0000000..8855acb
--- /dev/null
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/chart/BarChartConverter.java
@@ -0,0 +1,78 @@
+package com.blogspot.e_kanivets.moneytracker.report.chart;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.support.annotation.NonNull;
+
+import com.blogspot.e_kanivets.moneytracker.R;
+import com.github.mikephil.charting.data.BarDataSet;
+import com.github.mikephil.charting.data.BarEntry;
+import com.github.mikephil.charting.interfaces.datasets.IBarDataSet;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Util class to convert {@link IMonthReport} to {@link com.github.mikephil.charting.charts.BarChart}
+ * input data.
+ * Created on 4/27/16.
+ *
+ * @author Evgenii Kanivets
+ */
+public class BarChartConverter {
+ private final IMonthReport report;
+
+ private final int green;
+ private final int red;
+ private final String incomesTitle;
+ private final String expensesTitle;
+
+ @SuppressWarnings("deprecation")
+ public BarChartConverter(@NonNull Context context, @NonNull IMonthReport report) {
+ this.report = report;
+
+ green = context.getResources().getColor(R.color.green_light);
+ red = context.getResources().getColor(R.color.red_light);
+ incomesTitle = context.getString(R.string.incomes);
+ expensesTitle = context.getString(R.string.expenses);
+ }
+
+ @NonNull
+ public List getXAxisValueList() {
+ List valueList = new ArrayList<>();
+
+ @SuppressLint("SimpleDateFormat") SimpleDateFormat sdf = new SimpleDateFormat("MMM yy");
+ for (long timestamp : report.getMonthList()) {
+ valueList.add(sdf.format(new Date(timestamp)));
+ }
+
+ return valueList;
+ }
+
+ @NonNull
+ public List getBarDataSetList() {
+ List incomeList = new ArrayList<>();
+ for (int i = 0; i < report.getIncomeList().size(); i++) {
+ incomeList.add(new BarEntry(report.getIncomeList().get(i).floatValue(), i));
+ }
+
+ BarDataSet incomeDataSet = new BarDataSet(incomeList, incomesTitle);
+ incomeDataSet.setColor(green);
+
+ List expenseList = new ArrayList<>();
+ for (int i = 0; i < report.getExpenseList().size(); i++) {
+ expenseList.add(new BarEntry(report.getExpenseList().get(i).floatValue(), i));
+ }
+
+ BarDataSet dataSet2 = new BarDataSet(expenseList, expensesTitle);
+ dataSet2.setColor(red);
+
+ List list = new ArrayList<>();
+ list.add(incomeDataSet);
+ list.add(dataSet2);
+
+ return list;
+ }
+}
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/chart/IMonthReport.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/chart/IMonthReport.java
new file mode 100644
index 0000000..00e449a
--- /dev/null
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/chart/IMonthReport.java
@@ -0,0 +1,37 @@
+package com.blogspot.e_kanivets.moneytracker.report.chart;
+
+import android.support.annotation.NonNull;
+
+import java.util.List;
+
+/**
+ * Interface that represents a contract of access to record report data grouped by month
+ * for all records. All three methods must return list of the same size.
+ * Created on 4/28/16.
+ *
+ * @author Evgenii Kanivets
+ */
+public interface IMonthReport {
+ /**
+ * @return code of report currency
+ */
+ @NonNull String getCurrency();
+
+ /**
+ * @return list of month timestamps with not zero record count
+ */
+ @NonNull
+ List getMonthList();
+
+ /**
+ * @return list of summary month incomes
+ */
+ @NonNull
+ List getIncomeList();
+
+ /**
+ * @return list of summary month expenses
+ */
+ @NonNull
+ List getExpenseList();
+}
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/chart/MonthReport.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/chart/MonthReport.java
new file mode 100644
index 0000000..8f582e1
--- /dev/null
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/chart/MonthReport.java
@@ -0,0 +1,167 @@
+package com.blogspot.e_kanivets.moneytracker.report.chart;
+
+import android.support.annotation.NonNull;
+
+import com.blogspot.e_kanivets.moneytracker.entity.data.ExchangeRate;
+import com.blogspot.e_kanivets.moneytracker.entity.data.Record;
+import com.blogspot.e_kanivets.moneytracker.report.base.IExchangeRateProvider;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * First {@link IMonthReport} implementation.
+ * Created on 4/28/16.
+ *
+ * @author Evgenii Kanivets
+ */
+public class MonthReport implements IMonthReport {
+ private final String currency;
+ private final IExchangeRateProvider rateProvider;
+
+ private final List monthList;
+
+ public MonthReport(List recordList, String currency, IExchangeRateProvider rateProvider) {
+ if (recordList == null || currency == null || rateProvider == null)
+ throw new NullPointerException("Params can't be null");
+
+ this.currency = currency;
+ this.rateProvider = rateProvider;
+
+ monthList = generateReport(recordList);
+ }
+
+ @NonNull
+ @Override
+ public String getCurrency() {
+ return currency;
+ }
+
+ @NonNull
+ @Override
+ public List getMonthList() {
+ List resultList = new ArrayList<>();
+
+ for (MonthNode node : monthList) {
+ resultList.add(node.getTimestamp());
+ }
+
+ return resultList;
+ }
+
+ @NonNull
+ @Override
+ public List getIncomeList() {
+ List resultList = new ArrayList<>();
+
+ for (MonthNode node : monthList) {
+ resultList.add(node.getTotalIncome());
+ }
+
+ return resultList;
+ }
+
+ @NonNull
+ @Override
+ public List getExpenseList() {
+ List resultList = new ArrayList<>();
+
+ for (MonthNode node : monthList) {
+ resultList.add(node.getTotalExpense());
+ }
+
+ return resultList;
+ }
+
+ /**
+ * @param recordList to generate report on
+ * @return sorted by timestamp list of {@link MonthNode}
+ */
+ @NonNull
+ private List generateReport(List recordList) {
+ SortedMap monthMap = new TreeMap<>();
+
+ for (Record record : recordList) {
+ long timestamp = getMonthTimestamp(record.getTime());
+
+ if (monthMap.get(timestamp) == null) monthMap.put(timestamp, new MonthNode(timestamp));
+ MonthNode node = monthMap.get(timestamp);
+
+ double convertedPrice = record.getPrice();
+ if (!currency.equals(record.getCurrency())) {
+ ExchangeRate exchangeRate = rateProvider.getRate(record);
+ if (exchangeRate == null) throw new NullPointerException("No exchange rate found");
+ convertedPrice *= exchangeRate.getAmount();
+ }
+
+ switch (record.getType()) {
+ case Record.TYPE_INCOME:
+ node.addIncome(convertedPrice);
+ break;
+
+ case Record.TYPE_EXPENSE:
+ node.addExpense(convertedPrice);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ List resultList = new ArrayList<>();
+ for (Long timestamp : monthMap.keySet()) {
+ resultList.add(monthMap.get(timestamp));
+ }
+
+ return resultList;
+ }
+
+ private long getMonthTimestamp(long timestamp) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(new Date(timestamp));
+
+ calendar.set(Calendar.DAY_OF_MONTH, 0);
+ calendar.set(Calendar.HOUR_OF_DAY, 0);
+ calendar.set(Calendar.MINUTE, 0);
+ calendar.set(Calendar.SECOND, 0);
+ calendar.set(Calendar.MILLISECOND, 0);
+
+ return calendar.getTimeInMillis();
+ }
+
+ private static class MonthNode {
+ private long timestamp;
+ private double totalIncome;
+ private double totalExpense;
+
+ public MonthNode(long timestamp) {
+ this.timestamp = timestamp;
+ totalExpense = 0;
+ totalIncome = 0;
+ }
+
+ public void addIncome(double income) {
+ totalIncome += income;
+ }
+
+ public void addExpense(double expense) {
+ totalExpense += expense;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public double getTotalIncome() {
+ return totalIncome;
+ }
+
+ public double getTotalExpense() {
+ return totalExpense;
+ }
+ }
+}
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/base/IReport.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/IRecordReport.java
similarity index 82%
rename from app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/base/IReport.java
rename to app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/IRecordReport.java
index 086bfd7..90d8e72 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/base/IReport.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/IRecordReport.java
@@ -1,9 +1,9 @@
-package com.blogspot.e_kanivets.moneytracker.report.base;
+package com.blogspot.e_kanivets.moneytracker.report.record;
import android.support.annotation.NonNull;
import com.blogspot.e_kanivets.moneytracker.entity.Period;
-import com.blogspot.e_kanivets.moneytracker.report.model.CategoryRecord;
+import com.blogspot.e_kanivets.moneytracker.report.record.model.CategoryRecord;
import java.util.List;
@@ -13,7 +13,7 @@
*
* @author Evgenii Kanivets
*/
-public interface IReport {
+public interface IRecordReport {
/**
* @return code of report currency
*/
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/Report.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/RecordReport.java
similarity index 92%
rename from app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/Report.java
rename to app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/RecordReport.java
index cc4a4d2..bac23af 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/Report.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/RecordReport.java
@@ -1,4 +1,4 @@
-package com.blogspot.e_kanivets.moneytracker.report;
+package com.blogspot.e_kanivets.moneytracker.report.record;
import android.support.annotation.NonNull;
@@ -6,9 +6,8 @@
import com.blogspot.e_kanivets.moneytracker.entity.Period;
import com.blogspot.e_kanivets.moneytracker.entity.data.Record;
import com.blogspot.e_kanivets.moneytracker.report.base.IExchangeRateProvider;
-import com.blogspot.e_kanivets.moneytracker.report.base.IReport;
-import com.blogspot.e_kanivets.moneytracker.report.model.CategoryRecord;
-import com.blogspot.e_kanivets.moneytracker.report.model.SummaryRecord;
+import com.blogspot.e_kanivets.moneytracker.report.record.model.CategoryRecord;
+import com.blogspot.e_kanivets.moneytracker.report.record.model.SummaryRecord;
import java.util.ArrayList;
import java.util.Collections;
@@ -18,14 +17,14 @@
import java.util.TreeMap;
/**
- * First {@link IReport} implementation.
+ * First {@link IRecordReport} implementation.
* Created on 2/25/16.
*
* @author Evgenii Kanivets
*/
-public class Report implements IReport {
+public class RecordReport implements IRecordReport {
@SuppressWarnings("unused")
- private static final String TAG = "Report";
+ private static final String TAG = "RecordReport";
private String currency;
private Period period;
@@ -35,7 +34,7 @@ public class Report implements IReport {
private double totalExpense;
private List categoryRecordList;
- public Report(String currency, Period period, List recordList, IExchangeRateProvider rateProvider) {
+ public RecordReport(String currency, Period period, List recordList, IExchangeRateProvider rateProvider) {
if (currency == null || period == null || recordList == null || rateProvider == null)
throw new NullPointerException("Params can't be null");
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/ReportConverter.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/RecordReportConverter.java
similarity index 82%
rename from app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/ReportConverter.java
rename to app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/RecordReportConverter.java
index 912c602..07ad91a 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/ReportConverter.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/RecordReportConverter.java
@@ -1,12 +1,11 @@
-package com.blogspot.e_kanivets.moneytracker.report;
+package com.blogspot.e_kanivets.moneytracker.report.record;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import com.blogspot.e_kanivets.moneytracker.R;
-import com.blogspot.e_kanivets.moneytracker.report.base.IReport;
-import com.blogspot.e_kanivets.moneytracker.report.model.CategoryRecord;
-import com.blogspot.e_kanivets.moneytracker.report.model.SummaryRecord;
+import com.blogspot.e_kanivets.moneytracker.report.record.model.CategoryRecord;
+import com.blogspot.e_kanivets.moneytracker.report.record.model.SummaryRecord;
import java.util.ArrayList;
import java.util.HashMap;
@@ -14,18 +13,18 @@
import java.util.Map;
/**
- * Util class to convert {@link Report} to {@link android.widget.ExpandableListView} input data.
+ * Util class to convert {@link RecordReport} to {@link android.widget.ExpandableListView} input data.
* Created on 2/26/16.
*
* @author Evgenii Kanivets
*/
-public class ReportConverter {
+public class RecordReportConverter {
public static final String TITLE_PARAM_NAME = "title";
public static final String PRICE_PARAM_NAME = "price";
- private final IReport report;
+ private final IRecordReport report;
- public ReportConverter(@NonNull IReport report) {
+ public RecordReportConverter(@NonNull IRecordReport report) {
this.report = report;
}
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/model/CategoryRecord.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/model/CategoryRecord.java
similarity index 95%
rename from app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/model/CategoryRecord.java
rename to app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/model/CategoryRecord.java
index 306a59d..3563c06 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/model/CategoryRecord.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/model/CategoryRecord.java
@@ -1,4 +1,4 @@
-package com.blogspot.e_kanivets.moneytracker.report.model;
+package com.blogspot.e_kanivets.moneytracker.report.record.model;
import android.support.annotation.NonNull;
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/model/SummaryRecord.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/model/SummaryRecord.java
similarity index 95%
rename from app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/model/SummaryRecord.java
rename to app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/model/SummaryRecord.java
index 94bd588..e60ab03 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/model/SummaryRecord.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/report/record/model/SummaryRecord.java
@@ -1,4 +1,4 @@
-package com.blogspot.e_kanivets.moneytracker.report.model;
+package com.blogspot.e_kanivets.moneytracker.report.record.model;
import android.support.annotation.NonNull;
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/ui/presenter/AccountsSummaryPresenter.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/ui/presenter/AccountsSummaryPresenter.java
index a0c75b2..31534ff 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/ui/presenter/AccountsSummaryPresenter.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/ui/presenter/AccountsSummaryPresenter.java
@@ -14,7 +14,7 @@
import com.blogspot.e_kanivets.moneytracker.controller.data.AccountController;
import com.blogspot.e_kanivets.moneytracker.controller.data.ExchangeRateController;
import com.blogspot.e_kanivets.moneytracker.report.ReportMaker;
-import com.blogspot.e_kanivets.moneytracker.report.base.IAccountsReport;
+import com.blogspot.e_kanivets.moneytracker.report.account.IAccountsReport;
import com.blogspot.e_kanivets.moneytracker.ui.presenter.base.BaseSummaryPresenter;
import java.util.List;
diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/ui/presenter/ShortSummaryPresenter.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/ui/presenter/ShortSummaryPresenter.java
index 20b329f..2faeea6 100644
--- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/ui/presenter/ShortSummaryPresenter.java
+++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/ui/presenter/ShortSummaryPresenter.java
@@ -6,7 +6,7 @@
import android.widget.TextView;
import com.blogspot.e_kanivets.moneytracker.R;
-import com.blogspot.e_kanivets.moneytracker.report.base.IReport;
+import com.blogspot.e_kanivets.moneytracker.report.record.IRecordReport;
import com.blogspot.e_kanivets.moneytracker.ui.presenter.base.BaseSummaryPresenter;
import java.util.List;
@@ -46,7 +46,7 @@ public View create(boolean shortSummary) {
return view;
}
- public void update(IReport report, String currency, List ratesNeeded) {
+ public void update(IRecordReport report, String currency, List ratesNeeded) {
ViewHolder viewHolder = (ViewHolder) view.getTag();
if (report == null) {
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_charts.png b/app/src/main/res/drawable-xxxhdpi/ic_charts.png
new file mode 100755
index 0000000..b7c5e7d
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_charts.png differ
diff --git a/app/src/main/res/layout/activity_charts.xml b/app/src/main/res/layout/activity_charts.xml
new file mode 100644
index 0000000..9c3df6a
--- /dev/null
+++ b/app/src/main/res/layout/activity_charts.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_nav_drawer.xml b/app/src/main/res/menu/menu_nav_drawer.xml
index 7a8b4a4..2865924 100644
--- a/app/src/main/res/menu/menu_nav_drawer.xml
+++ b/app/src/main/res/menu/menu_nav_drawer.xml
@@ -9,13 +9,20 @@
android:id="@+id/nav_rates"
android:icon="@drawable/ic_exchange_rates"
android:title="@string/title_exchange_rates" />
+
+
+
+
-
+
- Счет по умолчанию
Валюта по умолчанию
+ Графики
+ Доходы
+ Расходы
+
diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml
index 6700f77..85db8a6 100644
--- a/app/src/main/res/values-uk/strings.xml
+++ b/app/src/main/res/values-uk/strings.xml
@@ -59,4 +59,8 @@
Рахунок за замовчуванням
Валюта за замовчуванням
+ Графіки
+ Доходи
+ Витрати
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 04a347c..65223a1 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -45,7 +45,7 @@
To
Exchange rates
Add exchange rate
- "]]>
+ " -> "
Account was removed
1
=
@@ -65,6 +65,9 @@
%1$s - %2$s
Default currency
-
+ Charts
+ Incomes
+ Expenses
+
diff --git a/app/src/test/java/com/blogspot/e_kanivets/moneytracker/report/ReportTest.java b/app/src/test/java/com/blogspot/e_kanivets/moneytracker/report/ReportTest.java
index 68e743e..9ab1d7f 100644
--- a/app/src/test/java/com/blogspot/e_kanivets/moneytracker/report/ReportTest.java
+++ b/app/src/test/java/com/blogspot/e_kanivets/moneytracker/report/ReportTest.java
@@ -9,9 +9,10 @@
import com.blogspot.e_kanivets.moneytracker.entity.data.Record;
import com.blogspot.e_kanivets.moneytracker.entity.Period;
import com.blogspot.e_kanivets.moneytracker.report.base.IExchangeRateProvider;
-import com.blogspot.e_kanivets.moneytracker.report.base.IReport;
-import com.blogspot.e_kanivets.moneytracker.report.model.CategoryRecord;
-import com.blogspot.e_kanivets.moneytracker.report.model.SummaryRecord;
+import com.blogspot.e_kanivets.moneytracker.report.record.IRecordReport;
+import com.blogspot.e_kanivets.moneytracker.report.record.model.CategoryRecord;
+import com.blogspot.e_kanivets.moneytracker.report.record.model.SummaryRecord;
+import com.blogspot.e_kanivets.moneytracker.report.record.RecordReport;
import org.junit.After;
import org.junit.Before;
@@ -47,13 +48,13 @@ public void tearDown() throws Exception {
@Test
public void testForNulls() throws Exception {
- IReport report;
+ IRecordReport report;
Period period = new Period(new Date(1), new Date(), Period.TYPE_CUSTOM);
List recordList = new ArrayList<>();
try {
- report = new Report(null, period, recordList, rateProvider);
+ report = new RecordReport(null, period, recordList, rateProvider);
} catch (NullPointerException e) {
report = null;
}
@@ -61,7 +62,7 @@ public void testForNulls() throws Exception {
assertNull(report);
try {
- report = new Report(currency, null, recordList, rateProvider);
+ report = new RecordReport(currency, null, recordList, rateProvider);
} catch (NullPointerException e) {
report = null;
}
@@ -69,7 +70,7 @@ public void testForNulls() throws Exception {
assertNull(report);
try {
- report = new Report(currency, period, null, rateProvider);
+ report = new RecordReport(currency, period, null, rateProvider);
} catch (NullPointerException e) {
report = null;
}
@@ -77,7 +78,7 @@ public void testForNulls() throws Exception {
assertNull(report);
try {
- report = new Report(currency, period, recordList, null);
+ report = new RecordReport(currency, period, recordList, null);
} catch (NullPointerException e) {
report = null;
}
@@ -85,7 +86,7 @@ public void testForNulls() throws Exception {
assertNull(report);
try {
- report = new Report(null, null, null, null);
+ report = new RecordReport(null, null, null, null);
} catch (NullPointerException e) {
report = null;
}
@@ -93,7 +94,7 @@ public void testForNulls() throws Exception {
assertNull(report);
try {
- report = new Report(currency, period, recordList, rateProvider);
+ report = new RecordReport(currency, period, recordList, rateProvider);
} catch (NullPointerException e) {
report = null;
}
@@ -106,12 +107,12 @@ public void testGetCurrency() throws Exception {
Period period = new Period(new Date(1), new Date(), Period.TYPE_CUSTOM);
List recordList = new ArrayList<>();
- IReport report = new Report(currency, period, recordList, rateProvider);
+ IRecordReport report = new RecordReport(currency, period, recordList, rateProvider);
assertEquals(currency, report.getCurrency());
currency = "KHI";
- report = new Report(currency, period, recordList, rateProvider);
+ report = new RecordReport(currency, period, recordList, rateProvider);
assertEquals(currency, report.getCurrency());
}
@@ -121,12 +122,12 @@ public void testGetPeriod() throws Exception {
Period period = new Period(new Date(1), new Date(), Period.TYPE_CUSTOM);
List recordList = new ArrayList<>();
- IReport report = new Report(currency, period, recordList, rateProvider);
+ IRecordReport report = new RecordReport(currency, period, recordList, rateProvider);
assertEquals(period, report.getPeriod());
period = new Period(new Date(3), new Date(100), Period.TYPE_CUSTOM);
- report = new Report(currency, period, recordList, rateProvider);
+ report = new RecordReport(currency, period, recordList, rateProvider);
assertEquals(period, report.getPeriod());
}
@@ -137,7 +138,7 @@ public void testGetTotal() throws Exception {
List recordList = getRecordList();
- IReport report = new Report(currency, period, recordList, rateProvider);
+ IRecordReport report = new RecordReport(currency, period, recordList, rateProvider);
double expectedTotal = 10 * 4 - 2 + 5 - 10 * 4;
assertEquals(expectedTotal, report.getTotal(), 0.0000000001);
@@ -149,7 +150,7 @@ public void testGetTotalIncome() throws Exception {
List recordList = getRecordList();
- IReport report = new Report(currency, period, recordList, rateProvider);
+ IRecordReport report = new RecordReport(currency, period, recordList, rateProvider);
double expectedTotal = 10 * 4 + 5;
assertEquals(expectedTotal, report.getTotalIncome(), 0.0000000001);
@@ -161,7 +162,7 @@ public void testGetTotalExpense() throws Exception {
List recordList = getRecordList();
- IReport report = new Report(currency, period, recordList, rateProvider);
+ IRecordReport report = new RecordReport(currency, period, recordList, rateProvider);
double expectedTotal = -2 - 10 * 4;
assertEquals(expectedTotal, report.getTotalExpense(), 0.0000000001);
@@ -186,7 +187,7 @@ public void testGetSummary() throws Exception {
Record record4 = new Record(4, 3, Record.TYPE_EXPENSE, "4", category, 10, account2, "USD");
recordList.add(record4);
- IReport report = new Report(currency, period, recordList, rateProvider);
+ IRecordReport report = new RecordReport(currency, period, recordList, rateProvider);
List categoryRecordList = new ArrayList<>();
diff --git a/build.gradle b/build.gradle
index b180567..9ebcc91 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,8 +11,7 @@ buildscript {
allprojects {
repositories {
mavenCentral()
- maven{
- url 'https://oss.sonatype.org/content/repositories/snapshots/'
- }
+ maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' }
+ maven { url "https://jitpack.io" }
}
}
\ No newline at end of file