diff --git a/app/build.gradle b/app/build.gradle index deb0fbb..e280fb9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,4 +1,19 @@ +buildscript { + repositories { + maven { url 'https://maven.fabric.io/public' } + } + + dependencies { + classpath 'io.fabric.tools:gradle:1.+' + } +} apply plugin: 'com.android.application' +apply plugin: 'io.fabric' + +repositories { + maven { url 'https://maven.fabric.io/public' } +} + apply plugin: 'com.neenbedankt.android-apt' android { @@ -64,4 +79,7 @@ dependencies { androidTestCompile 'com.crittercism.dexmaker:dexmaker:1.4' androidTestCompile 'com.crittercism.dexmaker:dexmaker-dx:1.4' androidTestCompile 'com.crittercism.dexmaker:dexmaker-mockito:1.4' + compile('com.crashlytics.sdk.android:crashlytics:2.6.5@aar') { + transitive = true; + } } diff --git a/app/fabric.properties b/app/fabric.properties new file mode 100644 index 0000000..055320f --- /dev/null +++ b/app/fabric.properties @@ -0,0 +1,3 @@ +#Contains API Secret used to validate your application. Commit to internal source control; avoid making secret public. +#Wed Dec 14 10:33:29 EET 2016 +apiSecret=82d758bae86a87ef822afbfc6f3c016c28c0b43f1d46862ebf37405141fa3414 diff --git a/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/AccountRepoTest.java b/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/AccountRepoTest.java index 74252b1..cb2f27e 100644 --- a/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/AccountRepoTest.java +++ b/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/AccountRepoTest.java @@ -44,9 +44,9 @@ public void testContentValues() throws Exception { ContentValues expected = new ContentValues(); expected.put(DbHelper.TITLE_COLUMN, "title1"); - expected.put(DbHelper.CUR_SUM_COLUMN, 100); + expected.put(DbHelper.CUR_SUM_COLUMN, 100L); expected.put(DbHelper.CURRENCY_COLUMN, "NON"); - expected.put(DbHelper.DECIMALS_COLUMN, 30); + expected.put(DbHelper.DECIMALS_COLUMN, 30L); ContentValues actual = repo.contentValues(account); @@ -67,7 +67,7 @@ public void testGetListFromCursor() throws Exception { Mockito.when(mockCursor.getLong(1)).thenReturn(1L); Mockito.when(mockCursor.getString(2)).thenReturn("title"); - Mockito.when(mockCursor.getInt(3)).thenReturn(100); + Mockito.when(mockCursor.getLong(3)).thenReturn(100L); Mockito.when(mockCursor.getString(4)).thenReturn("NON"); List expected = new ArrayList<>(); diff --git a/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/RecordRepoTest.java b/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/RecordRepoTest.java index ac23b6a..0214f7e 100644 --- a/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/RecordRepoTest.java +++ b/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/RecordRepoTest.java @@ -47,10 +47,10 @@ public void testContentValues() throws Exception { expected.put(DbHelper.TYPE_COLUMN, Record.TYPE_EXPENSE); expected.put(DbHelper.TITLE_COLUMN, "title"); expected.put(DbHelper.CATEGORY_ID_COLUMN, 1L); - expected.put(DbHelper.PRICE_COLUMN, 100); + expected.put(DbHelper.PRICE_COLUMN, 100L); expected.put(DbHelper.ACCOUNT_ID_COLUMN, 1L); expected.put(DbHelper.CURRENCY_COLUMN, "NON"); - expected.put(DbHelper.DECIMALS_COLUMN, 50); + expected.put(DbHelper.DECIMALS_COLUMN, 50L); ContentValues actual = repo.contentValues(record); @@ -79,10 +79,10 @@ public void testGetListFromCursor() throws Exception { Mockito.when(mockCursor.getInt(3)).thenReturn(Record.TYPE_EXPENSE); Mockito.when(mockCursor.getString(4)).thenReturn("title"); Mockito.when(mockCursor.getLong(5)).thenReturn(1L); - Mockito.when(mockCursor.getInt(6)).thenReturn(100); + Mockito.when(mockCursor.getLong(6)).thenReturn(100L); Mockito.when(mockCursor.getLong(7)).thenReturn(1L); Mockito.when(mockCursor.getString(8)).thenReturn("NON"); - Mockito.when(mockCursor.getInt(9)).thenReturn(50); + Mockito.when(mockCursor.getLong(9)).thenReturn(50L); List expected = new ArrayList<>(); expected.add(new Record(1, 1, Record.TYPE_EXPENSE, "title", 1, 100, 1, "NON", 50)); diff --git a/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/TransferRepoTest.java b/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/TransferRepoTest.java index 9234100..d133708 100644 --- a/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/TransferRepoTest.java +++ b/app/src/androidTest/java/com/blogspot/e_kanivets/moneytracker/repo/data/TransferRepoTest.java @@ -46,10 +46,10 @@ public void testContentValues() throws Exception { expected.put(DbHelper.TIME_COLUMN, 1L); expected.put(DbHelper.FROM_ACCOUNT_ID_COLUMN, 1L); expected.put(DbHelper.TO_ACCOUNT_ID_COLUMN, 2L); - expected.put(DbHelper.FROM_AMOUNT_COLUMN, 100); - expected.put(DbHelper.TO_AMOUNT_COLUMN, 200); - expected.put(DbHelper.DECIMALS_FROM_COLUMN, 45); - expected.put(DbHelper.DECIMALS_TO_COLUMN, 50); + expected.put(DbHelper.FROM_AMOUNT_COLUMN, 100L); + expected.put(DbHelper.TO_AMOUNT_COLUMN, 200L); + expected.put(DbHelper.DECIMALS_FROM_COLUMN, 45L); + expected.put(DbHelper.DECIMALS_TO_COLUMN, 50L); ContentValues actual = repo.contentValues(transfer); @@ -76,10 +76,10 @@ public void testGetListFromCursor() throws Exception { Mockito.when(mockCursor.getLong(2)).thenReturn(1L); Mockito.when(mockCursor.getLong(3)).thenReturn(1L); Mockito.when(mockCursor.getLong(4)).thenReturn(2L); - Mockito.when(mockCursor.getInt(5)).thenReturn(100); - Mockito.when(mockCursor.getInt(6)).thenReturn(200); - Mockito.when(mockCursor.getInt(7)).thenReturn(45); - Mockito.when(mockCursor.getInt(8)).thenReturn(50); + Mockito.when(mockCursor.getLong(5)).thenReturn(100L); + Mockito.when(mockCursor.getLong(6)).thenReturn(200L); + Mockito.when(mockCursor.getLong(7)).thenReturn(45L); + Mockito.when(mockCursor.getLong(8)).thenReturn(50L); List expected = new ArrayList<>(); expected.add(new Transfer(1, 1, 1, 2, 100, 200, 45, 50)); diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0b5070f..53269b3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -111,6 +111,9 @@ android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> + \ No newline at end of file diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/MtApp.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/MtApp.java index 9669e7d..86bcdd4 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/MtApp.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/MtApp.java @@ -7,6 +7,8 @@ import com.blogspot.e_kanivets.moneytracker.di.module.ControllerModule; import com.blogspot.e_kanivets.moneytracker.di.module.repo.CachedRepoModule; +import com.crashlytics.android.Crashlytics; +import io.fabric.sdk.android.Fabric; import timber.log.Timber; /** @@ -27,6 +29,9 @@ public static MtApp get() { @Override public void onCreate() { super.onCreate(); + if (!BuildConfig.DEBUG) { + Fabric.with(this, new Crashlytics()); + } mtApp = this; buildAppComponent(); 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 02be4fc..12681f1 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 @@ -51,6 +51,7 @@ protected int getContentViewId() { return R.layout.activity_report; } + @SuppressWarnings("RedundantIfStatement") @Override protected boolean initData() { super.initData(); diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/AccountsActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/AccountsActivity.java index 9c006c8..368f58f 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/AccountsActivity.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/AccountsActivity.java @@ -14,6 +14,8 @@ import com.blogspot.e_kanivets.moneytracker.adapter.AccountAdapter; import com.blogspot.e_kanivets.moneytracker.controller.data.AccountController; import com.blogspot.e_kanivets.moneytracker.ui.presenter.AccountsSummaryPresenter; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.ContentViewEvent; import javax.inject.Inject; @@ -68,8 +70,7 @@ public boolean onCreateOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_transfer: - startActivityForResult(new Intent(AccountsActivity.this, TransferActivity.class), - REQUEST_TRANSFER); + makeTransfer(); return true; default: @@ -99,8 +100,23 @@ public boolean onContextItemSelected(MenuItem item) { } } + public void makeTransfer() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Add Transfer") + .putContentType("Button")); + + startActivityForResult(new Intent(AccountsActivity.this, TransferActivity.class), + REQUEST_TRANSFER); + } + @OnClick(R.id.btn_add_account) public void addAccount() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Add Account") + .putContentType("Button")); + Intent intent = new Intent(AccountsActivity.this, AddAccountActivity.class); startActivityForResult(intent, REQUEST_ADD_ACCOUNT); } diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/AddAccountActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/AddAccountActivity.java index 1760cac..9054e2e 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/AddAccountActivity.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/AddAccountActivity.java @@ -3,14 +3,18 @@ import android.support.v7.widget.AppCompatSpinner; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import android.widget.ArrayAdapter; -import android.widget.EditText; import com.blogspot.e_kanivets.moneytracker.R; import com.blogspot.e_kanivets.moneytracker.activity.base.BaseBackActivity; import com.blogspot.e_kanivets.moneytracker.controller.data.AccountController; import com.blogspot.e_kanivets.moneytracker.controller.CurrencyController; import com.blogspot.e_kanivets.moneytracker.entity.data.Account; +import com.blogspot.e_kanivets.moneytracker.util.validator.AccountValidator; +import com.blogspot.e_kanivets.moneytracker.util.validator.IValidator; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.ContentViewEvent; import java.util.ArrayList; @@ -27,10 +31,10 @@ public class AddAccountActivity extends BaseBackActivity { @Inject CurrencyController currencyController; - @Bind(R.id.et_title) - EditText etTitle; - @Bind(R.id.et_init_sum) - EditText etInitSum; + private IValidator accountValidator; + + @Bind(R.id.content) + View contentView; @Bind(R.id.spinner) AppCompatSpinner spinner; @@ -50,6 +54,7 @@ protected boolean initData() { protected void initViews() { super.initViews(); + accountValidator = new AccountValidator(AddAccountActivity.this, contentView); spinner.setAdapter(new ArrayAdapter<>(AddAccountActivity.this, R.layout.view_spinner_item, new ArrayList<>(currencyController.readAll()))); @@ -57,7 +62,7 @@ protected void initViews() { @Override public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_add_record, menu); + getMenuInflater().inflate(R.menu.menu_add_account, menu); return true; } @@ -65,10 +70,7 @@ public boolean onCreateOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_done: - if (addAccount()) { - setResult(RESULT_OK); - finish(); - } else showToast(R.string.wrong_number_text); + tryAddAccount(); return true; default: @@ -76,20 +78,27 @@ public boolean onOptionsItemSelected(MenuItem item) { } } - private boolean addAccount() { - String title = etTitle.getText().toString().trim(); - - double initSum; - try { - initSum = Double.parseDouble(etInitSum.getText().toString().trim()); - } catch (NumberFormatException e) { - e.printStackTrace(); - return false; - } + private void tryAddAccount() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Done Account") + .putContentType("Button")); - String currency = (String) spinner.getSelectedItem(); + if (addAccount()) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Done Account") + .putContentType("Event")); - Account account = new Account(title, initSum, currency); - return accountController.create(account) != null; + setResult(RESULT_OK); + finish(); + } + } + + @SuppressWarnings("SimplifiableIfStatement") + private boolean addAccount() { + Account account = accountValidator.validate(); + if (account == null) return false; + else return accountController.create(account) != null; } } diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/TransferActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/TransferActivity.java index 9d627e8..da8ca0c 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/TransferActivity.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/account/TransferActivity.java @@ -3,8 +3,8 @@ import android.support.v7.widget.AppCompatSpinner; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import android.widget.ArrayAdapter; -import android.widget.EditText; import com.blogspot.e_kanivets.moneytracker.R; import com.blogspot.e_kanivets.moneytracker.activity.base.BaseBackActivity; @@ -12,6 +12,10 @@ import com.blogspot.e_kanivets.moneytracker.controller.data.TransferController; import com.blogspot.e_kanivets.moneytracker.entity.data.Account; import com.blogspot.e_kanivets.moneytracker.entity.data.Transfer; +import com.blogspot.e_kanivets.moneytracker.util.validator.IValidator; +import com.blogspot.e_kanivets.moneytracker.util.validator.TransferValidator; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.ContentViewEvent; import java.util.ArrayList; import java.util.List; @@ -29,16 +33,16 @@ public class TransferActivity extends BaseBackActivity { @Inject AccountController accountController; + private IValidator transferValidator; + private List accountList; + @Bind(R.id.content) + View contentView; @Bind(R.id.spinner_from) AppCompatSpinner spinnerFrom; @Bind(R.id.spinner_to) AppCompatSpinner spinnerTo; - @Bind(R.id.et_from_amount) - EditText etFromAmount; - @Bind(R.id.et_to_amount) - EditText etToAmount; @Override protected int getContentViewId() { @@ -62,6 +66,14 @@ protected void initViews() { accounts.add(account.getTitle()); } + transferValidator = new TransferValidator(TransferActivity.this, contentView, accountList); + + if (accounts.size() == 0) { + accounts.add(getString(R.string.none)); + spinnerFrom.setEnabled(false); + spinnerTo.setEnabled(false); + } + spinnerFrom.setAdapter(new ArrayAdapter<>(TransferActivity.this, R.layout.view_spinner_item, accounts)); @@ -79,10 +91,7 @@ public boolean onCreateOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_done: - doTransfer(); - - setResult(RESULT_OK); - finish(); + tryTransfer(); return true; default: @@ -90,26 +99,27 @@ public boolean onOptionsItemSelected(MenuItem item) { } } - private void doTransfer() { - Account fromAccount = accountList.get(spinnerFrom.getSelectedItemPosition()); - Account toAccount = accountList.get(spinnerTo.getSelectedItemPosition()); + private void tryTransfer() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Done Transfer") + .putContentType("Button")); - double fromAmount = -1; - try { - fromAmount = Double.parseDouble(etFromAmount.getText().toString()); - } catch (NumberFormatException e) { - e.printStackTrace(); - } + if (doTransfer()) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Done Transfer") + .putContentType("Event")); - double toAmount = -1; - try { - toAmount = Double.parseDouble(etToAmount.getText().toString()); - } catch (NumberFormatException e) { - e.printStackTrace(); + setResult(RESULT_OK); + finish(); } + } - Transfer transfer = new Transfer(System.currentTimeMillis(), fromAccount.getId(), - toAccount.getId(), fromAmount, toAmount); - transferController.create(transfer); + @SuppressWarnings("SimplifiableIfStatement") + private boolean doTransfer() { + Transfer transfer = transferValidator.validate(); + if (transfer == null) return false; + else return transferController.create(transfer) != null; } } 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 22c6f10..0a61393 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 @@ -15,6 +15,8 @@ import com.blogspot.e_kanivets.moneytracker.activity.SettingsActivity; import com.blogspot.e_kanivets.moneytracker.activity.account.AccountsActivity; import com.blogspot.e_kanivets.moneytracker.activity.exchange_rate.ExchangeRatesActivity; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.ContentViewEvent; import butterknife.Bind; @@ -72,32 +74,27 @@ protected void initViews() { public boolean onNavigationItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.nav_accounts: - startActivityForResult(new Intent(BaseDrawerActivity.this, AccountsActivity.class), - REQUEST_ACCOUNTS); + showAccounts(); break; case R.id.nav_rates: - startActivityForResult(new Intent(BaseDrawerActivity.this, ExchangeRatesActivity.class), - REQUEST_RATES); + showRates(); break; case R.id.nav_charts: - startActivity(new Intent(BaseDrawerActivity.this, ChartsActivity.class)); + showCharts(); break; case R.id.nav_backup: - startActivityForResult(new Intent(BaseDrawerActivity.this, BackupActivity.class), - REQUEST_BACKUP); + showBackup(); break; case R.id.nav_import_export: - startActivityForResult(new Intent(BaseDrawerActivity.this, ImportExportActivity.class), - REQUEST_IMPORT_EXPORT); + showImportExport(); break; case R.id.nav_settings: - startActivityForResult(new Intent(BaseDrawerActivity.this, SettingsActivity.class), - REQUEST_SETTINGS); + showSettings(); break; default: @@ -135,4 +132,63 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } } } + + private void showAccounts() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Show Accounts") + .putContentType("Button")); + + startActivityForResult(new Intent(BaseDrawerActivity.this, AccountsActivity.class), + REQUEST_ACCOUNTS); + } + + private void showRates() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Show Rates") + .putContentType("Button")); + + startActivityForResult(new Intent(BaseDrawerActivity.this, ExchangeRatesActivity.class), + REQUEST_RATES); + } + + private void showCharts() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Show Charts") + .putContentType("Button")); + + startActivity(new Intent(BaseDrawerActivity.this, ChartsActivity.class)); + } + + private void showBackup() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Show Backup") + .putContentType("Button")); + + startActivityForResult(new Intent(BaseDrawerActivity.this, BackupActivity.class), + REQUEST_BACKUP); + } + + private void showImportExport() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Show Import Export") + .putContentType("Button")); + + startActivityForResult(new Intent(BaseDrawerActivity.this, ImportExportActivity.class), + REQUEST_IMPORT_EXPORT); + } + + private void showSettings() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Show Settings") + .putContentType("Button")); + + startActivityForResult(new Intent(BaseDrawerActivity.this, SettingsActivity.class), + REQUEST_SETTINGS); + } } diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/exchange_rate/AddExchangeRateActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/exchange_rate/AddExchangeRateActivity.java index daafcd6..5b2adcf 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/exchange_rate/AddExchangeRateActivity.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/exchange_rate/AddExchangeRateActivity.java @@ -4,6 +4,7 @@ import android.support.v7.widget.AppCompatSpinner; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import android.widget.ArrayAdapter; import android.widget.EditText; @@ -13,6 +14,10 @@ import com.blogspot.e_kanivets.moneytracker.controller.FormatController; import com.blogspot.e_kanivets.moneytracker.controller.data.ExchangeRateController; import com.blogspot.e_kanivets.moneytracker.entity.ExchangeRatePair; +import com.blogspot.e_kanivets.moneytracker.util.validator.ExchangeRatePairValidator; +import com.blogspot.e_kanivets.moneytracker.util.validator.IValidator; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.ContentViewEvent; import java.util.ArrayList; import java.util.List; @@ -34,10 +39,14 @@ public class AddExchangeRateActivity extends BaseBackActivity { @Inject FormatController formatController; + private IValidator exchangeRatePairValidator; + // This field passed from Intent and may be used for presetting from/to spinner values @Nullable private ExchangeRatePair exchangeRatePair; + @Bind(R.id.content) + View contentView; @Bind(R.id.spinner_from_currency) AppCompatSpinner spinnerFromCurrency; @Bind(R.id.spinner_to_currency) @@ -65,8 +74,16 @@ protected boolean initData() { @Override protected void initViews() { super.initViews(); + + exchangeRatePairValidator = new ExchangeRatePairValidator(AddExchangeRateActivity.this, contentView); List currencyList = currencyController.readAll(); + if (currencyList.size() == 0) { + currencyList.add(getString(R.string.none)); + spinnerFromCurrency.setEnabled(false); + spinnerToCurrency.setEnabled(false); + } + spinnerFromCurrency.setAdapter(new ArrayAdapter<>(AddExchangeRateActivity.this, R.layout.view_spinner_item, new ArrayList<>(currencyList))); @@ -101,10 +118,7 @@ public boolean onCreateOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_done: - if (addExchangeRate()) { - setResult(RESULT_OK); - finish(); - } + tryAddExchangeRate(); return true; default: @@ -112,30 +126,27 @@ public boolean onOptionsItemSelected(MenuItem item) { } } - private boolean addExchangeRate() { - String fromCurrency = (String) spinnerFromCurrency.getSelectedItem(); - String toCurrency = (String) spinnerToCurrency.getSelectedItem(); - double amountBuy = -1; - double amountSell = -1; + private void tryAddExchangeRate() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Done Exchange Rate") + .putContentType("Button")); - if (fromCurrency.equals(toCurrency)) return false; + if (addExchangeRate()) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Done Exchange Rate") + .putContentType("Event")); - try { - amountBuy = Double.parseDouble(etBuy.getText().toString().trim()); - } catch (Exception e) { - e.printStackTrace(); + setResult(RESULT_OK); + finish(); } - try { - amountSell = Double.parseDouble(etSell.getText().toString().trim()); - } catch (Exception e) { - e.printStackTrace(); - } - - if (amountBuy == -1 || amountSell == -1) return false; - - ExchangeRatePair pair = new ExchangeRatePair(fromCurrency, toCurrency, amountBuy, amountSell); - ExchangeRatePair createdPair = exchangeRateController.createExchangeRatePair(pair); + } - return createdPair != null; + @SuppressWarnings("SimplifiableIfStatement") + private boolean addExchangeRate() { + ExchangeRatePair pair = exchangeRatePairValidator.validate(); + if (pair == null) return false; + else return exchangeRateController.createExchangeRatePair(pair) != null; } } diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/exchange_rate/ExchangeRatesActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/exchange_rate/ExchangeRatesActivity.java index ddd25ce..1796cc1 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/exchange_rate/ExchangeRatesActivity.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/exchange_rate/ExchangeRatesActivity.java @@ -15,6 +15,8 @@ import com.blogspot.e_kanivets.moneytracker.controller.data.ExchangeRateController; import com.blogspot.e_kanivets.moneytracker.entity.ExchangeRatePair; import com.blogspot.e_kanivets.moneytracker.util.ExchangeRatesSummarizer; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.ContentViewEvent; import java.util.Collections; import java.util.List; @@ -71,23 +73,42 @@ public boolean onContextItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.delete: - rateController.deleteExchangeRatePair(exchangeRateList.get(info.position)); - update(); - setResult(RESULT_OK); + deleteExchangeRate(info.position); return true; default: return super.onContextItemSelected(item); } } + public void deleteExchangeRate(int position) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Delete Exchange Rate") + .putContentType("Button")); + + rateController.deleteExchangeRatePair(exchangeRateList.get(position)); + update(); + setResult(RESULT_OK); + } + @OnClick(R.id.btn_add_exchange_rate) public void addExchangeRate() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Add Exchange Rate") + .putContentType("Button")); + Intent intent = new Intent(ExchangeRatesActivity.this, AddExchangeRateActivity.class); startActivityForResult(intent, REQUEST_ADD_EXCHANGE_RATE); } @OnItemClick(R.id.list_view) public void addExchangeRateOnBaseOfExisted(int position) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Edit Exchange Rate") + .putContentType("Button")); + if (position < 0 || position >= exchangeRateList.size()) return; Intent intent = new Intent(ExchangeRatesActivity.this, AddExchangeRateActivity.class); intent.putExtra(AddExchangeRateActivity.KEY_EXCHANGE_RATE, exchangeRateList.get(position)); diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/external/BackupActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/external/BackupActivity.java index 71250ba..3460de8 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/external/BackupActivity.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/external/BackupActivity.java @@ -12,6 +12,8 @@ import com.blogspot.e_kanivets.moneytracker.activity.base.BaseBackActivity; import com.blogspot.e_kanivets.moneytracker.controller.BackupController; import com.blogspot.e_kanivets.moneytracker.controller.PreferenceController; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.ContentViewEvent; import com.dropbox.client2.DropboxAPI; import com.dropbox.client2.android.AndroidAuthSession; import com.dropbox.client2.session.AppKeyPair; @@ -89,10 +91,20 @@ protected void onResume() { @OnClick(R.id.btn_backup_now) public void backupNow() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Make Backup") + .putContentType("Button")); + startProgress(getString(R.string.making_backup)); backupController.makeBackup(dbApi, new BackupController.OnBackupListener() { @Override public void onBackupSuccess() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Backup success") + .putContentType("Event")); + Timber.d("Backup success."); if (isFinishing()) return; @@ -102,6 +114,11 @@ public void onBackupSuccess() { @Override public void onBackupFailure(String reason) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Backup failure") + .putContentType("Event")); + Timber.d("Backup failure."); if (isFinishing()) return; @@ -115,6 +132,11 @@ public void onBackupFailure(String reason) { @OnItemClick(R.id.list_view) public void restoreBackupClicked(int position) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Restore backup") + .putContentType("Button")); + final String backupName = listView.getAdapter().getItem(position).toString(); AlertDialog.Builder builder = new AlertDialog.Builder(BackupActivity.this); @@ -135,6 +157,11 @@ private void restoreBackup(final String backupName) { backupController.restoreBackup(dbApi, backupName, new BackupController.OnRestoreBackupListener() { @Override public void onRestoreSuccess() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Restore Success") + .putContentType("Event")); + Timber.d("Restore success."); if (isFinishing()) return; @@ -157,6 +184,11 @@ public void onDismiss(DialogInterface dialog) { @Override public void onRestoreFailure(String reason) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Restore Failure") + .putContentType("Event")); + Timber.d("Restore failure."); if (isFinishing()) return; diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/external/ImportExportActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/external/ImportExportActivity.java index 2d4dba4..ec8f2ac 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/external/ImportExportActivity.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/external/ImportExportActivity.java @@ -15,6 +15,8 @@ import com.blogspot.e_kanivets.moneytracker.controller.external.ExportController; import com.blogspot.e_kanivets.moneytracker.controller.external.ImportController; import com.blogspot.e_kanivets.moneytracker.entity.data.Record; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.ContentViewEvent; import java.io.File; import java.io.FileNotFoundException; @@ -60,11 +62,7 @@ public boolean onCreateOptionsMenu(Menu menu) { public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.action_help: - AlertDialog.Builder builder = new AlertDialog.Builder(ImportExportActivity.this); - builder.setTitle(R.string.help) - .setMessage(R.string.import_help) - .setPositiveButton(android.R.string.ok, null) - .show(); + showHelp(); return true; default: @@ -72,8 +70,26 @@ public boolean onOptionsItemSelected(MenuItem item) { } } + public void showHelp() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Show Help") + .putContentType("Button")); + + AlertDialog.Builder builder = new AlertDialog.Builder(ImportExportActivity.this); + builder.setTitle(R.string.help) + .setMessage(R.string.import_help) + .setPositiveButton(android.R.string.ok, null) + .show(); + } + @OnClick(R.id.btn_import) public void importRecords() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Import Records") + .putContentType("Button")); + final String data = etImportData.getText().toString().trim(); AsyncTask importTask = new AsyncTask() { @@ -93,7 +109,7 @@ protected Integer doInBackground(Void... params) { protected void onPostExecute(Integer recordCount) { super.onPostExecute(recordCount); stopProgress(); - showToast(getString(R.string.records_imported, recordCount)); + showToast(getString(R.string.records_imported, recordCount.toString())); setResult(RESULT_OK); } }; @@ -102,6 +118,11 @@ protected void onPostExecute(Integer recordCount) { @OnClick(R.id.btn_export) public void exportRecords() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Export Records") + .putContentType("Button")); + List records = exportController.getRecordsForExport(0, Long.MAX_VALUE); File exportDir = new File(getCacheDir(), "export"); @@ -133,6 +154,11 @@ public void exportRecords() { } private void shareExportedRecords(@NonNull File exportFile) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Share Records") + .putContentType("Event")); + Uri fileUri = FileProvider.getUriForFile(ImportExportActivity.this, getPackageName(), exportFile); Intent sendIntent = new Intent(); diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/record/AddRecordActivity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/record/AddRecordActivity.java index c12173f..bbf4c96 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/record/AddRecordActivity.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/activity/record/AddRecordActivity.java @@ -3,6 +3,7 @@ import android.annotation.SuppressLint; import android.app.DatePickerDialog; import android.app.TimePickerDialog; +import android.support.annotation.Nullable; import android.support.v7.widget.AppCompatSpinner; import android.text.InputFilter; import android.text.Spanned; @@ -28,10 +29,13 @@ import com.blogspot.e_kanivets.moneytracker.controller.data.CategoryController; import com.blogspot.e_kanivets.moneytracker.controller.data.RecordController; import com.blogspot.e_kanivets.moneytracker.entity.data.Account; -import com.blogspot.e_kanivets.moneytracker.entity.data.Category; import com.blogspot.e_kanivets.moneytracker.entity.data.Record; import com.blogspot.e_kanivets.moneytracker.ui.AddRecordUiDecorator; import com.blogspot.e_kanivets.moneytracker.util.CategoryAutoCompleter; +import com.blogspot.e_kanivets.moneytracker.util.validator.IValidator; +import com.blogspot.e_kanivets.moneytracker.util.validator.RecordValidator; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.ContentViewEvent; import java.util.ArrayList; import java.util.Calendar; @@ -56,6 +60,7 @@ public class AddRecordActivity extends BaseBackActivity { public static final String KEY_MODE = "key_mode"; public static final String KEY_TYPE = "key_type"; + @Nullable private Record record; private Mode mode; private int type; @@ -72,8 +77,11 @@ public class AddRecordActivity extends BaseBackActivity { @Inject FormatController formatController; - AddRecordUiDecorator uiDecorator; + private IValidator recordValidator; + private AddRecordUiDecorator uiDecorator; + @Bind(R.id.content) + View contentView; @Bind(R.id.tv_date) TextView tvDate; @Bind(R.id.tv_time) @@ -104,10 +112,11 @@ record = getIntent().getParcelableExtra(KEY_RECORD); type = getIntent().getIntExtra(KEY_TYPE, -1); accountList = accountController.readAll(); - if (mode == Mode.MODE_EDIT) timestamp = record.getTime(); + if (mode == Mode.MODE_EDIT && record != null) timestamp = record.getTime(); else timestamp = new Date().getTime(); - return mode != null && type != -1 && (!mode.equals(Mode.MODE_EDIT) || record != null); + return mode != null && (type == Record.TYPE_INCOME || type == Record.TYPE_EXPENSE) + && (!mode.equals(Mode.MODE_EDIT) || record != null); } @SuppressWarnings("deprecation") @@ -116,6 +125,10 @@ record = getIntent().getParcelableExtra(KEY_RECORD); protected void initViews() { super.initViews(); + long recordId = record == null ? -1 : record.getId(); + recordValidator = new RecordValidator(AddRecordActivity.this, contentView, mode, + accountList, timestamp, type, recordId); + // Add texts to dialog if it's edit dialog if (mode == Mode.MODE_EDIT) { etTitle.setText(record.getTitle()); @@ -178,9 +191,10 @@ public boolean onOptionsItemSelected(MenuItem item) { return true; case R.id.action_delete: - recordController.delete(record); - setResult(RESULT_OK); - finish(); + if (recordController.delete(record)) { + setResult(RESULT_OK); + finish(); + } return true; default: @@ -190,58 +204,65 @@ public boolean onOptionsItemSelected(MenuItem item) { @OnClick(R.id.tv_date) public void selectDate() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Select Date") + .putContentType("Button")); + Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(timestamp); - DatePickerDialog dialog = new DatePickerDialog(AddRecordActivity.this, - uiDecorator.getTheme(type), new DatePickerDialog.OnDateSetListener() { - @Override - public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(timestamp); - calendar.set(Calendar.YEAR, year); - calendar.set(Calendar.MONTH, monthOfYear); - calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); - - if (calendar.getTimeInMillis() < new Date().getTime()) { - timestamp = calendar.getTimeInMillis(); - updateDateAndTime(); - } - } - }, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), + DatePickerDialog dialog = new DatePickerDialog(AddRecordActivity.this, uiDecorator.getTheme(type), + new DatePickerDialog.OnDateSetListener() { + @Override + public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(timestamp); + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, monthOfYear); + calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth); + + if (calendar.getTimeInMillis() < new Date().getTime()) { + timestamp = calendar.getTimeInMillis(); + updateDateAndTime(); + } else { + showToast(R.string.record_in_future); + } + } + }, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); dialog.show(); } @OnClick(R.id.tv_time) public void selectTime() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Show Time") + .putContentType("Button")); + Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(timestamp); - TimePickerDialog dialog = new TimePickerDialog(AddRecordActivity.this, - uiDecorator.getTheme(type), new TimePickerDialog.OnTimeSetListener() { - @Override - public void onTimeSet(TimePicker view, int hourOfDay, int minute) { - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(timestamp); - calendar.set(Calendar.HOUR_OF_DAY, hourOfDay); - calendar.set(Calendar.MINUTE, minute); - - if (calendar.getTimeInMillis() < new Date().getTime()) { - timestamp = calendar.getTimeInMillis(); - updateDateAndTime(); - } - } - }, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), + TimePickerDialog dialog = new TimePickerDialog(AddRecordActivity.this, uiDecorator.getTheme(type), + new TimePickerDialog.OnTimeSetListener() { + @Override + public void onTimeSet(TimePicker view, int hourOfDay, int minute) { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(timestamp); + calendar.set(Calendar.HOUR_OF_DAY, hourOfDay); + calendar.set(Calendar.MINUTE, minute); + + if (calendar.getTimeInMillis() < new Date().getTime()) { + timestamp = calendar.getTimeInMillis(); + updateDateAndTime(); + } else { + showToast(R.string.record_in_future); + } + } + }, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), DateFormat.is24HourFormat(AddRecordActivity.this)); dialog.show(); } - private void tryRecord() { - if (prepareRecord()) { - setResult(RESULT_OK); - finish(); - } else showToast(R.string.wrong_number_text); - } - private void presentSpinnerAccount() { List accounts = new ArrayList<>(); for (Account account : accountList) { @@ -251,7 +272,7 @@ private void presentSpinnerAccount() { int selectedAccountIndex = -1; if (mode == Mode.MODE_EDIT) { - if (record.getAccount() != null) { + if (record != null && record.getAccount() != null) { for (int i = 0; i < accountList.size(); i++) { Account account = accountList.get(i); if (account.getId() == record.getAccount().getId()) selectedAccountIndex = i; @@ -271,8 +292,11 @@ private void presentSpinnerAccount() { selectedAccountIndex = 0; spinnerAccount.setEnabled(false); - accounts = new ArrayList<>(); - accounts.add(getString(R.string.account_was_removed)); + if (accounts.size() == 0) { + accounts.add(getString(R.string.none)); + } else { + accounts.add(getString(R.string.account_was_removed)); + } } spinnerAccount.setAdapter(new ArrayAdapter<>(AddRecordActivity.this, @@ -280,50 +304,34 @@ private void presentSpinnerAccount() { spinnerAccount.setSelection(selectedAccountIndex); } - private boolean prepareRecord() { - String title = etTitle.getText().toString().trim(); - String category = etCategory.getText().toString().trim(); + private void tryRecord() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Done Record") + .putContentType("Button")); - if (title.isEmpty()) return false; - if (category.isEmpty()) return false; + if (addRecord()) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Done Record") + .putContentType("Event")); - //Check if price is valid - double price = -1; - try { - price = Double.parseDouble(etPrice.getText().toString()); - } catch (NumberFormatException e) { - e.printStackTrace(); + setResult(RESULT_OK); + finish(); } - - long now = new Date().getTime(); - if (timestamp > now) return false; - - if (price < 0.0 || price > 1000000000.0) return false; - - if (spinnerAccount.getSelectedItemPosition() < 0) return false; - - Account account = null; - if (spinnerAccount.isEnabled()) - account = accountList.get(spinnerAccount.getSelectedItemPosition()); - //noinspection SimplifiableIfStatement - if (account == null) return false; - - return makeRecord(timestamp, title, category, price, account); } - /** - * All data must be valid here. - */ - private boolean makeRecord(long timestamp, String title, String category, double price, Account account) { - long recordId = (record == null ? -1 : record.getId()); - Record record = new Record(recordId, timestamp, type, title, new Category(category), - price, account, account.getCurrency()); - - Record resultedRecord = null; - if (mode == Mode.MODE_ADD) resultedRecord = recordController.create(record); - else if (mode == Mode.MODE_EDIT) resultedRecord = recordController.update(record); - - return resultedRecord != null; + @SuppressWarnings("SimplifiableIfStatement") + private boolean addRecord() { + Record newRecord = recordValidator.validate(); + if (newRecord == null) return false; + else { + if (mode == Mode.MODE_ADD) { + return recordController.create(newRecord) != null; + } else if (mode == Mode.MODE_EDIT) { + return recordController.update(newRecord) != null; + } else return false; + } } private void updateDateAndTime() { 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 e6850b3..9adf563 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 @@ -26,6 +26,8 @@ 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; +import com.crashlytics.android.answers.Answers; +import com.crashlytics.android.answers.ContentViewEvent; import java.util.ArrayList; import java.util.Collections; @@ -124,6 +126,11 @@ public void onPeriodSelected(Period period) { @OnItemClick(R.id.list_view) public void editRecord(int position) { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Edit Record") + .putContentType("Button")); + // Minus one because of list view's header view Record record = recordList.get(position - 1); startAddRecordActivity(record, AddRecordActivity.Mode.MODE_EDIT, record.getType()); @@ -131,15 +138,30 @@ public void editRecord(int position) { @OnClick(R.id.btn_add_expense) public void addExpense() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Add Expense") + .putContentType("Button")); + startAddRecordActivity(null, AddRecordActivity.Mode.MODE_ADD, Record.TYPE_EXPENSE); } @OnClick(R.id.btn_add_income) public void addIncome() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Add Income") + .putContentType("Button")); + startAddRecordActivity(null, AddRecordActivity.Mode.MODE_ADD, Record.TYPE_INCOME); } public void showReport() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Show Report") + .putContentType("Button")); + Intent intent = new Intent(MainActivity.this, ReportActivity.class); intent.putExtra(ReportActivity.KEY_PERIOD, period); intent.putExtra(ReportActivity.KEY_RECORD_LIST, (ArrayList) recordList); @@ -184,6 +206,11 @@ protected void update() { } private void showAppRateDialog() { + // Answers event + Answers.getInstance().logContentView(new ContentViewEvent() + .putContentName("Show App Rate Dialog") + .putContentType("Button")); + AppRateDialog dialog = new AppRateDialog(MainActivity.this); dialog.setCanceledOnTouchOutside(false); dialog.show(); 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 9c5b2b1..4018db3 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 @@ -13,7 +13,6 @@ import com.blogspot.e_kanivets.moneytracker.report.record.RecordReportConverter; import java.util.List; -import java.util.Locale; import java.util.Map; import javax.inject.Inject; diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/adapter/RecordAdapter.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/adapter/RecordAdapter.java index 944592e..95d684e 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/adapter/RecordAdapter.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/adapter/RecordAdapter.java @@ -19,7 +19,6 @@ import butterknife.Bind; import butterknife.ButterKnife; -import timber.log.Timber; /** * Custom adapter class for {@link Record} entity. diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/controller/base/BaseController.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/controller/base/BaseController.java index a41d9c5..fde34f4 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/controller/base/BaseController.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/controller/base/BaseController.java @@ -3,7 +3,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import com.blogspot.e_kanivets.moneytracker.entity.ExchangeRatePair; import com.blogspot.e_kanivets.moneytracker.repo.base.IRepo; import java.util.List; diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/base/BaseEntity.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/base/BaseEntity.java index c96a7f8..3bd7e87 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/base/BaseEntity.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/base/BaseEntity.java @@ -19,12 +19,12 @@ protected boolean equals(String str1, String str2) { else return str1.equals(str2); } - protected int getInteger(double value) { - return (int) value; + protected long getLong(double value) { + return (long) value; } - protected int getDecimal(double value) { + protected long getDecimal(double value) { // Strange calculation because of double type precision issue - return (int) Math.round(value * 100 - getInteger(value) * 100); + return (long) Math.round(value * 100 - getLong(value) * 100); } } diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Account.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Account.java index 61bd958..4b6d7b4 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Account.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Account.java @@ -13,11 +13,11 @@ */ public class Account extends BaseEntity implements Parcelable { private final String title; - private int curSum; + private long curSum; private final String currency; - private int decimals; + private long decimals; - public Account(long id, String title, int curSum, String currency, int decimals) { + public Account(long id, String title, long curSum, String currency, long decimals) { this.id = id; this.title = title; this.curSum = curSum; @@ -29,16 +29,16 @@ public Account(String title, double curSum, String currency) { this.id = -1; this.title = title; this.currency = currency; - this.curSum = getInteger(curSum); + this.curSum = getLong(curSum); this.decimals = getDecimal(curSum); } protected Account(Parcel in) { id = in.readLong(); title = in.readString(); - curSum = in.readInt(); + curSum = in.readLong(); currency = in.readString(); - decimals = in.readInt(); + decimals = in.readLong(); } public static final Creator CREATOR = new Creator() { @@ -57,11 +57,11 @@ public String getTitle() { return title; } - public int getCurSum() { + public long getCurSum() { return curSum; } - public int getDecimals() { + public long getDecimals() { return decimals; } @@ -76,14 +76,14 @@ public String getCurrency() { public void put(double amount) { double sum = curSum + decimals / 100.0; sum += amount; - curSum = getInteger(sum); + curSum = getLong(sum); decimals = getDecimal(sum); } public void take(double amount) { double sum = curSum + decimals / 100.0; sum -= amount; - curSum = getInteger(sum); + curSum = getLong(sum); decimals = getDecimal(sum); } @@ -124,8 +124,8 @@ public int describeContents() { public void writeToParcel(Parcel dest, int flags) { dest.writeLong(id); dest.writeString(title); - dest.writeInt(curSum); + dest.writeLong(curSum); dest.writeString(currency); - dest.writeInt(decimals); + dest.writeLong(decimals); } } diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Record.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Record.java index eb643b0..03b29e1 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Record.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Record.java @@ -19,13 +19,13 @@ public class Record extends BaseEntity implements Parcelable { private final int type; private final String title; private final Category category; - private final int price; + private final long price; private final Account account; private final String currency; - private final int decimals; + private final long decimals; - public Record(long id, long time, int type, String title, long categoryId, int price, - long accountId, String currency, int decimals) { + public Record(long id, long time, int type, String title, long categoryId, long price, + long accountId, String currency, long decimals) { this.id = id; this.time = time; this.type = type; @@ -37,8 +37,8 @@ public Record(long id, long time, int type, String title, long categoryId, int p this.decimals = decimals; } - public Record(long id, long time, int type, String title, Category category, int price, - Account account, String currency, int decimals) { + public Record(long id, long time, int type, String title, Category category, long price, + Account account, String currency, long decimals) { this.id = id; this.time = time; this.type = type; @@ -59,7 +59,7 @@ public Record(long id, long time, int type, String title, Category category, dou this.category = category; this.account = account; this.currency = currency; - this.price = getInteger(price); + this.price = getLong(price); this.decimals = getDecimal(price); } @@ -72,7 +72,7 @@ public Record(long time, int type, String title, Category category, double price this.category = category; this.account = account; this.currency = currency; - this.price = getInteger(price); + this.price = getLong(price); this.decimals = getDecimal(price); } @@ -82,10 +82,10 @@ protected Record(Parcel in) { type = in.readInt(); title = in.readString(); category = in.readParcelable(Category.class.getClassLoader()); - price = in.readInt(); + price = in.readLong(); account = in.readParcelable(Account.class.getClassLoader()); currency = in.readString(); - decimals = in.readInt(); + decimals = in.readLong(); } public static final Creator CREATOR = new Creator() { @@ -118,11 +118,11 @@ public Category getCategory() { return category; } - public int getPrice() { + public long getPrice() { return price; } - public int getDecimals() { + public long getDecimals() { return decimals; } @@ -210,9 +210,9 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(type); dest.writeString(title); dest.writeParcelable(category, 0); - dest.writeInt(price); + dest.writeLong(price); dest.writeParcelable(account, 0); dest.writeString(currency); - dest.writeInt(decimals); + dest.writeLong(decimals); } } \ No newline at end of file diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Transfer.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Transfer.java index b674c1f..305fa50 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Transfer.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/entity/data/Transfer.java @@ -15,13 +15,13 @@ public class Transfer extends BaseEntity implements Parcelable { private final long time; private final long fromAccountId; private final long toAccountId; - private final int fromAmount; - private final int toAmount; - private final int fromDecimals; - private final int toDecimals; + private final long fromAmount; + private final long toAmount; + private final long fromDecimals; + private final long toDecimals; - public Transfer(long id, long time, long fromAccountId, long toAccountId, int fromAmount, - int toAmount, int fromDecimals, int toDecimals) { + public Transfer(long id, long time, long fromAccountId, long toAccountId, long fromAmount, + long toAmount, long fromDecimals, long toDecimals) { this.fromDecimals = fromDecimals; this.toDecimals = toDecimals; this.id = id; @@ -36,9 +36,9 @@ public Transfer(long time, long fromAccountId, long toAccountId, double fromAmou this.time = time; this.fromAccountId = fromAccountId; this.toAccountId = toAccountId; - this.fromAmount = getInteger(fromAmount); + this.fromAmount = getLong(fromAmount); this.fromDecimals = getDecimal(fromAmount); - this.toAmount = getInteger(toAmount); + this.toAmount = getLong(toAmount); this.toDecimals = getDecimal(toAmount); } @@ -46,10 +46,10 @@ protected Transfer(Parcel in) { time = in.readLong(); fromAccountId = in.readLong(); toAccountId = in.readLong(); - fromAmount = in.readInt(); - toAmount = in.readInt(); - fromDecimals = in.readInt(); - toDecimals = in.readInt(); + fromAmount = in.readLong(); + toAmount = in.readLong(); + fromDecimals = in.readLong(); + toDecimals = in.readLong(); } public static final Creator CREATOR = new Creator() { @@ -81,19 +81,19 @@ public long getToAccountId() { return toAccountId; } - public int getFromAmount() { + public long getFromAmount() { return fromAmount; } - public int getToAmount() { + public long getToAmount() { return toAmount; } - public int getFromDecimals() { + public long getFromDecimals() { return fromDecimals; } - public int getToDecimals() { + public long getToDecimals() { return toDecimals; } @@ -148,9 +148,9 @@ public void writeToParcel(Parcel dest, int flags) { dest.writeLong(time); dest.writeLong(fromAccountId); dest.writeLong(toAccountId); - dest.writeInt(fromAmount); - dest.writeInt(toAmount); - dest.writeInt(fromDecimals); - dest.writeInt(toDecimals); + dest.writeLong(fromAmount); + dest.writeLong(toAmount); + dest.writeLong(fromDecimals); + dest.writeLong(toDecimals); } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/AccountRepo.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/AccountRepo.java index 4c09827..9200d1a 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/AccountRepo.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/AccountRepo.java @@ -65,9 +65,9 @@ protected List getListFromCursor(@Nullable Cursor cursor) { // Read a account from DB Account account = new Account(cursor.getLong(idColIndex), cursor.getString(titleColIndex), - cursor.getInt(curSumColIndex), + cursor.getLong(curSumColIndex), cursor.getString(currencyColIndex), - cursor.getInt(decimalsColIndex)); + cursor.getLong(decimalsColIndex)); accountList.add(account); } while (cursor.moveToNext()); diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/RecordRepo.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/RecordRepo.java index d7a5acf..d462d2b 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/RecordRepo.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/RecordRepo.java @@ -75,10 +75,10 @@ protected List getListFromCursor(Cursor cursor) { cursor.getInt(typeColIndex), cursor.getString(titleColIndex), cursor.getLong(categoryColIndex), - cursor.getInt(priceColIndex), + cursor.getLong(priceColIndex), cursor.getLong(accountIdColIndex), cursor.getString(currencyColIndex), - cursor.getInt(decimalsColIndex)); + cursor.getLong(decimalsColIndex)); recordList.add(record); } while (cursor.moveToNext()); @@ -86,4 +86,4 @@ protected List getListFromCursor(Cursor cursor) { return recordList; } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/TransferRepo.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/TransferRepo.java index 10864c9..bd96329 100644 --- a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/TransferRepo.java +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/repo/data/TransferRepo.java @@ -73,10 +73,10 @@ protected List getListFromCursor(@Nullable Cursor cursor) { cursor.getLong(idColTime), cursor.getLong(idColFromAccountId), cursor.getLong(idColToAccountId), - cursor.getInt(idColFromAmount), - cursor.getInt(idColToAmount), - cursor.getInt(idColDecimalsFrom), - cursor.getInt(idColDecimalsTo)); + cursor.getLong(idColFromAmount), + cursor.getLong(idColToAmount), + cursor.getLong(idColDecimalsFrom), + cursor.getLong(idColDecimalsTo)); accountList.add(account); } while (cursor.moveToNext()); 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 fc69167..d628b55 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 @@ -19,7 +19,6 @@ import com.blogspot.e_kanivets.moneytracker.ui.presenter.base.BaseSummaryPresenter; import java.util.List; -import java.util.Locale; import javax.inject.Inject; diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/AccountValidator.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/AccountValidator.java new file mode 100644 index 0000000..ab5a409 --- /dev/null +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/AccountValidator.java @@ -0,0 +1,84 @@ +package com.blogspot.e_kanivets.moneytracker.util.validator; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.TextInputLayout; +import android.support.v7.widget.AppCompatSpinner; +import android.view.View; +import android.widget.EditText; + +import com.blogspot.e_kanivets.moneytracker.R; +import com.blogspot.e_kanivets.moneytracker.entity.data.Account; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Util class for Account validation. + * Created on 06.12.2016. + * + * @author Evgenii Kanivets + */ + +public class AccountValidator implements IValidator { + + @NonNull + private final Context context; + + @Bind(R.id.til_title) + TextInputLayout tilTitle; + @Bind(R.id.et_title) + EditText etTitle; + @Bind(R.id.til_init_sum) + TextInputLayout tilInitSum; + @Bind(R.id.et_init_sum) + EditText etInitSum; + @Bind(R.id.spinner) + AppCompatSpinner spinner; + + public AccountValidator(@NonNull Context context, @NonNull View view) { + this.context = context; + ButterKnife.bind(this, view); + initTextWatchers(); + } + + @Nullable + @Override + public Account validate() { + String title = etTitle.getText().toString().trim(); + double initSum = Double.MAX_VALUE; + String currency = (String) spinner.getSelectedItem(); + + try { + initSum = Double.parseDouble(etInitSum.getText().toString().trim()); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + + boolean valid = true; + + if (title.isEmpty()) { + tilTitle.setError(context.getString(R.string.field_cant_be_empty)); + valid = false; + } + + if (initSum == Double.MAX_VALUE) { + tilInitSum.setError(context.getString(R.string.field_cant_be_empty)); + initSum = 0; + valid = false; + } + + if (Math.abs(initSum) > MAX_ABS_VALUE) { + tilInitSum.setError(context.getString(R.string.too_rich_or_poor)); + valid = false; + } + + return valid ? new Account(title, initSum, currency) : null; + } + + private void initTextWatchers() { + etTitle.addTextChangedListener(new ClearErrorTextWatcher(tilTitle)); + etInitSum.addTextChangedListener(new ClearErrorTextWatcher(tilInitSum)); + } +} diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/ClearErrorTextWatcher.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/ClearErrorTextWatcher.java new file mode 100644 index 0000000..eb0c3f7 --- /dev/null +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/ClearErrorTextWatcher.java @@ -0,0 +1,38 @@ +package com.blogspot.e_kanivets.moneytracker.util.validator; + +import android.support.annotation.NonNull; +import android.support.design.widget.TextInputLayout; +import android.text.Editable; +import android.text.TextWatcher; + +/** + * Custom TextWatcher which resets an error when text changed + * Created on 07.12.2016. + * + * @author Evgenii Kanivets + */ + +public class ClearErrorTextWatcher implements TextWatcher { + @NonNull + private TextInputLayout til; + + public ClearErrorTextWatcher(@NonNull TextInputLayout til) { + this.til = til; + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + til.setErrorEnabled(false); + til.setError(null); + } +} diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/ExchangeRatePairValidator.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/ExchangeRatePairValidator.java new file mode 100644 index 0000000..3e15fba --- /dev/null +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/ExchangeRatePairValidator.java @@ -0,0 +1,117 @@ +package com.blogspot.e_kanivets.moneytracker.util.validator; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.TextInputLayout; +import android.support.v7.widget.AppCompatSpinner; +import android.view.View; +import android.widget.EditText; +import android.widget.Toast; + +import com.blogspot.e_kanivets.moneytracker.R; +import com.blogspot.e_kanivets.moneytracker.entity.ExchangeRatePair; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Util class for Transfer validation. + * Created on 13.12.2016. + * + * @author Evgenii Kanivets + */ + +@SuppressWarnings("WeakerAccess") +public class ExchangeRatePairValidator implements IValidator { + + @NonNull + private final Context context; + + @Bind(R.id.spinner_from_currency) + AppCompatSpinner spinnerFromCurrency; + @Bind(R.id.spinner_to_currency) + AppCompatSpinner spinnerToCurrency; + @Bind(R.id.til_buy) + TextInputLayout tilBuy; + @Bind(R.id.et_buy) + EditText etBuy; + @Bind(R.id.til_sell) + TextInputLayout tilSell; + @Bind(R.id.et_sell) + EditText etSell; + + public ExchangeRatePairValidator(@NonNull Context context, @NonNull View view) { + this.context = context; + ButterKnife.bind(this, view); + initTextWatchers(); + } + + @Nullable + @Override + public ExchangeRatePair validate() { + boolean valid = true; + + String fromCurrency = null; + if (spinnerFromCurrency.isEnabled()) { + fromCurrency = (String) spinnerFromCurrency.getSelectedItem(); + } else { + valid = false; + } + + String toCurrency = null; + if (spinnerToCurrency.isEnabled()) { + toCurrency = (String) spinnerToCurrency.getSelectedItem(); + } else { + valid = false; + } + + if (fromCurrency != null && toCurrency != null && fromCurrency.equals(toCurrency)) { + Toast.makeText(context, R.string.same_currencies, Toast.LENGTH_SHORT).show(); + valid = false; + } + + double amountBuy = Double.MAX_VALUE; + try { + amountBuy = Double.parseDouble(etBuy.getText().toString().trim()); + } catch (Exception e) { + e.printStackTrace(); + } + + if (amountBuy == Double.MAX_VALUE) { + tilBuy.setError(context.getString(R.string.field_cant_be_empty)); + amountBuy = 0; + valid = false; + } + + if (amountBuy > MAX_ABS_VALUE) { + tilBuy.setError(context.getString(R.string.too_much_for_exchange)); + valid = false; + } + + double amountSell = Double.MAX_VALUE; + try { + amountSell = Double.parseDouble(etSell.getText().toString().trim()); + } catch (Exception e) { + e.printStackTrace(); + } + + if (amountSell == Double.MAX_VALUE) { + tilSell.setError(context.getString(R.string.field_cant_be_empty)); + amountSell = 0; + valid = false; + } + + if (amountSell > MAX_ABS_VALUE) { + tilSell.setError(context.getString(R.string.too_much_for_exchange)); + valid = false; + } + + return valid ? new ExchangeRatePair(fromCurrency, toCurrency, amountBuy, amountSell) : null; + } + + private void initTextWatchers() { + etBuy.addTextChangedListener(new ClearErrorTextWatcher(tilBuy)); + etSell.addTextChangedListener(new ClearErrorTextWatcher(tilSell)); + } +} diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/IValidator.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/IValidator.java new file mode 100644 index 0000000..7274e01 --- /dev/null +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/IValidator.java @@ -0,0 +1,20 @@ +package com.blogspot.e_kanivets.moneytracker.util.validator; + +import android.support.annotation.Nullable; + +/** + * Interface of validators for data models. It may works with UI elements directly. + * Created on 06.12.2016. + * + * @author Evgenii Kanivets + */ + +public interface IValidator { + long MAX_ABS_VALUE = Integer.MAX_VALUE * 1024L; + + /** + * @return instance of class T if validation passed or null otherwise + */ + @Nullable + T validate(); +} diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/RecordValidator.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/RecordValidator.java new file mode 100644 index 0000000..834b86d --- /dev/null +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/RecordValidator.java @@ -0,0 +1,140 @@ +package com.blogspot.e_kanivets.moneytracker.util.validator; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.TextInputLayout; +import android.support.v7.widget.AppCompatSpinner; +import android.view.View; +import android.widget.EditText; +import android.widget.Toast; + +import com.blogspot.e_kanivets.moneytracker.R; +import com.blogspot.e_kanivets.moneytracker.activity.record.AddRecordActivity; +import com.blogspot.e_kanivets.moneytracker.entity.data.Account; +import com.blogspot.e_kanivets.moneytracker.entity.data.Category; +import com.blogspot.e_kanivets.moneytracker.entity.data.Record; + +import java.util.Date; +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Util class for Account validation. + * Created on 06.12.2016. + * + * @author Evgenii Kanivets + */ + +public class RecordValidator implements IValidator { + + @NonNull + private final Context context; + + private AddRecordActivity.Mode mode; + private List accountList; + private long timestamp; + private long recordId; + private int recordType; + + @Bind(R.id.til_title) + TextInputLayout tilTitle; + @Bind(R.id.et_title) + EditText etTitle; + @Bind(R.id.til_category) + TextInputLayout tilCategory; + @Bind(R.id.et_category) + EditText etCategory; + @Bind(R.id.til_price) + TextInputLayout tilPrice; + @Bind(R.id.et_price) + EditText etPrice; + @Bind(R.id.spinner_account) + AppCompatSpinner spinnerAccount; + + public RecordValidator(@NonNull Context context, @NonNull View view, + @NonNull AddRecordActivity.Mode mode, @NonNull List accountList, + long timestamp, int recordType, long recordId) { + this.context = context; + this.mode = mode; + this.accountList = accountList; + this.timestamp = timestamp; + this.recordType = recordType; + this.recordId = recordId; + + ButterKnife.bind(this, view); + initTextWatchers(); + } + + @Nullable + @Override + public Record validate() { + boolean valid = true; + + String title = etTitle.getText().toString().trim(); + String category = etCategory.getText().toString().trim(); + + if (title.isEmpty()) { + title = category; + } + + if (category.isEmpty()) { + tilCategory.setError(context.getString(R.string.field_cant_be_empty)); + valid = false; + } + + //Check if price is valid + double price = Double.MAX_VALUE; + try { + price = Double.parseDouble(etPrice.getText().toString()); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + + if (price == Double.MAX_VALUE) { + tilPrice.setError(context.getString(R.string.field_cant_be_empty)); + price = 0; + valid = false; + } + + if (price > MAX_ABS_VALUE) { + tilPrice.setError(context.getString(R.string.too_rich)); + valid = false; + } + + long now = new Date().getTime(); + if (timestamp > now) { + Toast.makeText(context, R.string.record_in_future, Toast.LENGTH_SHORT).show(); + valid = false; + } + + Account account = null; + if (spinnerAccount.isEnabled()) { + account = accountList.get(spinnerAccount.getSelectedItemPosition()); + } else { + Toast.makeText(context, R.string.one_account_needed, Toast.LENGTH_SHORT).show(); + valid = false; + } + + Record record = null; + if (account != null) { + if (mode == AddRecordActivity.Mode.MODE_ADD) { + record = new Record(timestamp, recordType, title, new Category(category), + price, account, account.getCurrency()); + } else if (mode == AddRecordActivity.Mode.MODE_EDIT) { + record = new Record(recordId, timestamp, recordType, title, new Category(category), + price, account, account.getCurrency()); + } + } + + return valid ? record : null; + } + + private void initTextWatchers() { + etPrice.addTextChangedListener(new ClearErrorTextWatcher(tilPrice)); + etTitle.addTextChangedListener(new ClearErrorTextWatcher(tilTitle)); + etCategory.addTextChangedListener(new ClearErrorTextWatcher(tilCategory)); + } +} diff --git a/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/TransferValidator.java b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/TransferValidator.java new file mode 100644 index 0000000..b44a598 --- /dev/null +++ b/app/src/main/java/com/blogspot/e_kanivets/moneytracker/util/validator/TransferValidator.java @@ -0,0 +1,122 @@ +package com.blogspot.e_kanivets.moneytracker.util.validator; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.design.widget.TextInputLayout; +import android.support.v7.widget.AppCompatSpinner; +import android.view.View; +import android.widget.EditText; +import android.widget.Toast; + +import com.blogspot.e_kanivets.moneytracker.R; +import com.blogspot.e_kanivets.moneytracker.entity.data.Account; +import com.blogspot.e_kanivets.moneytracker.entity.data.Transfer; + +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; + +/** + * Util class for Transfer validation. + * Created on 07.12.2016. + * + * @author Evgenii Kanivets + */ + +@SuppressWarnings("WeakerAccess") +public class TransferValidator implements IValidator { + + @NonNull + private final Context context; + + @NonNull + private List accountList; + + @Bind(R.id.spinner_from) + AppCompatSpinner spinnerFrom; + @Bind(R.id.spinner_to) + AppCompatSpinner spinnerTo; + @Bind(R.id.til_from_amount) + TextInputLayout tilFromAmount; + @Bind(R.id.et_from_amount) + EditText etFromAmount; + @Bind(R.id.til_to_amount) + TextInputLayout tilToAmount; + @Bind(R.id.et_to_amount) + EditText etToAmount; + + public TransferValidator(@NonNull Context context, @NonNull View view, + @NonNull List accountList) { + this.context = context; + this.accountList = accountList; + ButterKnife.bind(this, view); + initTextWatchers(); + } + + @Nullable + @Override + public Transfer validate() { + boolean valid = true; + + Account fromAccount = null; + if (spinnerFrom.isEnabled()) { + fromAccount = accountList.get(spinnerFrom.getSelectedItemPosition()); + } else { + valid = false; + } + + Account toAccount = null; + if (spinnerTo.isEnabled()) { + toAccount = accountList.get(spinnerTo.getSelectedItemPosition()); + } else { + Toast.makeText(context, R.string.one_account_needed, Toast.LENGTH_SHORT).show(); + valid = false; + } + + double fromAmount = Double.MAX_VALUE; + try { + fromAmount = Double.parseDouble(etFromAmount.getText().toString()); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + + if (fromAmount == Double.MAX_VALUE) { + tilFromAmount.setError(context.getString(R.string.field_cant_be_empty)); + fromAmount = 0; + valid = false; + } + + if (fromAmount > MAX_ABS_VALUE) { + tilFromAmount.setError(context.getString(R.string.too_much_for_transfer)); + valid = false; + } + + double toAmount = Double.MAX_VALUE; + try { + toAmount = Double.parseDouble(etToAmount.getText().toString()); + } catch (NumberFormatException e) { + e.printStackTrace(); + } + + if (toAmount == Double.MAX_VALUE) { + tilToAmount.setError(context.getString(R.string.field_cant_be_empty)); + toAmount = 0; + valid = false; + } + + if (toAmount > MAX_ABS_VALUE) { + tilToAmount.setError(context.getString(R.string.too_much_for_transfer)); + valid = false; + } + + return valid ? new Transfer(System.currentTimeMillis(), fromAccount.getId(), + toAccount.getId(), fromAmount, toAmount) : null; + } + + private void initTextWatchers() { + etFromAmount.addTextChangedListener(new ClearErrorTextWatcher(tilFromAmount)); + etToAmount.addTextChangedListener(new ClearErrorTextWatcher(tilToAmount)); + } +} diff --git a/app/src/main/res/layout/activity_add_exchange_rate.xml b/app/src/main/res/layout/activity_add_exchange_rate.xml index e0a4c67..9a62337 100644 --- a/app/src/main/res/layout/activity_add_exchange_rate.xml +++ b/app/src/main/res/layout/activity_add_exchange_rate.xml @@ -21,6 +21,7 @@ @@ -86,6 +88,7 @@ tools:listitem="@layout/view_spinner_item" /> diff --git a/app/src/main/res/layout/content_add_account.xml b/app/src/main/res/layout/content_add_account.xml index 9f463f7..d29168f 100644 --- a/app/src/main/res/layout/content_add_account.xml +++ b/app/src/main/res/layout/content_add_account.xml @@ -2,6 +2,7 @@ @@ -25,6 +27,7 @@ diff --git a/app/src/main/res/layout/content_add_record.xml b/app/src/main/res/layout/content_add_record.xml index 1ff5702..22124dd 100644 --- a/app/src/main/res/layout/content_add_record.xml +++ b/app/src/main/res/layout/content_add_record.xml @@ -2,6 +2,7 @@ @@ -95,6 +97,7 @@ @@ -108,6 +111,7 @@ diff --git a/app/src/main/res/layout/content_transfer.xml b/app/src/main/res/layout/content_transfer.xml index 6d9e888..d7f427d 100644 --- a/app/src/main/res/layout/content_transfer.xml +++ b/app/src/main/res/layout/content_transfer.xml @@ -2,6 +2,7 @@ @@ -40,10 +42,10 @@ android:layout_height="wrap_content" android:ems="10" android:hint="@string/amount" + android:inputType="numberDecimal" android:maxLines="1" android:nextFocusDown="@+id/et_to_amount" - android:singleLine="true" - android:inputType="numberDecimal" /> + android:singleLine="true" /> @@ -68,6 +70,7 @@ tools:listitem="@layout/view_spinner_item" /> @@ -77,10 +80,10 @@ android:layout_height="wrap_content" android:ems="10" android:hint="@string/amount" + android:inputType="numberDecimal" android:maxLines="1" - android:singleLine="true" - android:inputType="numberDecimal" /> + android:singleLine="true" /> - \ No newline at end of file + diff --git a/app/src/main/res/menu/menu_add_account.xml b/app/src/main/res/menu/menu_add_account.xml new file mode 100644 index 0000000..28fb945 --- /dev/null +++ b/app/src/main/res/menu/menu_add_account.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-xxxhdpi/Thumbs.db b/app/src/main/res/mipmap-xxxhdpi/Thumbs.db new file mode 100644 index 0000000..31ceb23 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/Thumbs.db differ diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 1a74995..fbe6428 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -10,13 +10,11 @@ Добавить расход Добавить - Извините, но введенные данные не верны! Отчет ИЗМЕНИТЬ ДАТУ СУММА Суммарный доход Суммарный расход - Редактировать Удалить День @@ -105,4 +103,14 @@ Версия %1$s (Android %2$s) О приложении Open Money Tracker (OMT) это приложения для ведения личных финансов. Вы легко можете управлять доходами и расходами. Также доступны счета и курсы обмена.\n\nДля того чтобы помочь сделать OMT лучше, пишите о багах на форуме 4PDA; идеи новых функций также приветствуются. Ищите ответы или начинайте обсуждение на форуме.\n\nOMT это проект с открытым исходным кодом, так что каждый может помочь с его разработкой. Не-разработчики также могут помочь. Например, вы можете помочь с переводом, предоставить скриншоты или написать статью в блоге о OMT.\n\nOMT выпущен под GNU-GPL v3 лицензией и исходный код доступен на GitHub.\n\nПрофиль разработчика на LinkedIn. + + Поле не может быть пустым. + Вы не можете быть настолько богаты или бедны. + Вы не можете быть настолько богаты. + Нет + Слишком много для перевода. + Слишком много для обмена. + Нельзя конвертировать валюту в саму себя. + Нельзя создать запись в будущем. + Необходим, по крайней мере, один счет. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 430d366..27eabcf 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -10,13 +10,11 @@ Додати витрату Додати - Пробачте, але введені дані не корректні! Звіт ЗМІНИТИ ДАТУ СУМА Сумарний дохід Сумарна витрата - Редактувати Видалити День @@ -105,4 +103,14 @@ Версія %1$s (Android %2$s) Про додаток Open Money Tracker (OMT) це додаток для обліку персональних фінансів. Ви можете з легкістю керувати доходами та витратами. Також доступні рахунки та курси обміну.\n\nДля того щоб допомогти нам зробити OMT краще, пишіть про баги на форумі 4PDA; ідеї нових функцій також підтримуються. Знайдіть відповіді або розпочніть бесіду на форумі.\n\nOMT це додаток з відкритим сирцевим кодом, тож будь-хто може стати учасником. Не-розробники також можуть допомогти. Наприклад, Ви можете допомогти з перекладом OMT, надати знімки екранів або написати у блозі про OMT.\n\nOMT випущено під GNU-GPL v3 ліцензією і сирцевий код доступний на GitHub.\n\nПрофiль розробника на LinkedIn. + + Поле не може бути порожнім. + Ви не можете бути настільки багаті чи бідні. + Ви не можете бути настільки багаті. + Нема + Занадто багато для трансферу. + Занадто багато для обміну. + Не можна конвертувати валюту у саму себе. + Не можна створити запис у майбутньому. + Необхідний, принаймні, один рахунок. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ced045d..532ee5f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -8,13 +8,11 @@ Add income Add expense Add - Sorry, but entered data is wrong! Report CHANGE THE DATE TOTAL Total income Total expense - Edit Delete Day Week @@ -67,9 +65,9 @@ pref_display_precision Display precision - 9.99$ = 10$ - 9.99$ = 9$ - 9.99$ = 9.99$ + 9.99$ = 10$ + 9.99$ = 9$ + 9.99$ = 9.99$ Import/Export Import @@ -114,5 +112,15 @@ Version %1$s (Android %2$s) About Open Money Tracker (OMT) is an accounting application. You can manage your incomes and expenses in easy way. Accounts and currency exchange rates are also available.\n\nTo help us make OMT better, please report bugs to the 4PDA forum; new feature ideas are very welcome too. Find answers or start a discussion on forum.\n\nOMT is open source software, so everyone is encouraged to become a contributor. Non-developers can also help. For instance, you can help translate OMT, provide screenshots or blog about OMT.\n\nOMT is released under the GNU-GPL v3 license and source code is available on GitHub.\n\nDeveloper profile on LinkedIn. + + Field can\'t be empty. + You can\'t be so rich or so poor. + You can\'t be so rich. + None + It\'s too much for transfer. + It\'s too much for exchange. + Can\'t convert between same currencies. + Can\'t create a record in future. + At least one account is needed. diff --git a/build.gradle b/build.gradle index 04edadd..56b1ec6 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.3' + classpath 'com.android.tools.build:gradle:2.2.3' classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4' classpath 'com.getkeepsafe.dexcount:dexcount-gradle-plugin:0.5.2' }