From 9e2953ac1f0ad493830522ab3d83595899e727e2 Mon Sep 17 00:00:00 2001 From: Mikhail Barashkov Date: Sat, 31 Jul 2021 11:09:49 +0300 Subject: [PATCH 01/17] Fastfile set up --- .gitignore | 5 +++++ fastlane/Appfile | 2 ++ fastlane/Fastfile | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 fastlane/Appfile create mode 100644 fastlane/Fastfile diff --git a/.gitignore b/.gitignore index 5efe1115..b9a7ab27 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,8 @@ app/release/output.json *.aab app/untied/release/output.json app/fdroid/release/output.json +fastlane/.env.default +Keys/financier.properties +Keys/Signing.keystore +fastlane/fastlane_key.json +fastlane/report.xml diff --git a/fastlane/Appfile b/fastlane/Appfile new file mode 100644 index 00000000..54ba85ab --- /dev/null +++ b/fastlane/Appfile @@ -0,0 +1,2 @@ +json_key_file("./fastlane/fastlane_key.json") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one +package_name("com.handydev.financier") # e.g. com.krausefx.app diff --git a/fastlane/Fastfile b/fastlane/Fastfile new file mode 100644 index 00000000..24d99f42 --- /dev/null +++ b/fastlane/Fastfile @@ -0,0 +1,53 @@ +# This file contains the fastlane.tools configuration +# You can find the documentation at https://docs.fastlane.tools +# +# For a list of all available actions, check out +# +# https://docs.fastlane.tools/actions +# +# For a list of all available plugins, check out +# +# https://docs.fastlane.tools/plugins/available-plugins +# + +# Uncomment the line if you want fastlane to automatically update itself +# update_fastlane + +default_platform(:android) + +platform :android do + desc "Runs all the tests" + lane :test do + gradle(task: "test") + end + + desc "Submit a new version to GitHub" + lane :github do + versionName = prompt(text: "Enter version name") + changelog = prompt(text: "Enter release notes") + gradle( + task: 'clean assemble', + build_type: 'release', + flavor: 'untied' + ) + set_github_release( + repository_name: "handydevcom/financier", + api_token: ENV["GITHUB_TOKEN"], + name: versionName, + tag_name: versionName, + description: changelog, + commitish: "master", + upload_assets: ["./app/build/outputs/apk/untied/release/Financier.apk"] + ) + end + + desc "Deploy a new version to the Google Play" + lane :googleplay do + gradle( + task: 'clean assemble', + build_type: 'release', + flavor: 'googleplay' + ) + upload_to_play_store + end +end From 3ebd31892c15a0c11fdff8da49b1a61ee4c91167 Mon Sep 17 00:00:00 2001 From: Mikhail Barashkov Date: Sat, 31 Jul 2021 11:26:48 +0300 Subject: [PATCH 02/17] Fix a lot of warnings; refactor some code to Kotlin --- app/build.gradle | 12 +- .../financier/fragments/MenuListFragment.kt | 34 +- .../financier/fragments/MenuListFragment.kt | 54 +-- app/src/main/AndroidManifest.xml | 1 - .../financier/FinancierApplication.kt | 2 +- .../financier/activity/AccountActivity.java | 433 ----------------- .../financier/activity/AccountActivity.kt | 445 ++++++++++++++++++ .../CCardStatementClosingDayActivity.java | 9 +- .../financier/activity/CategorySelector.kt | 10 +- .../financier/activity/CsvExportActivity.java | 2 +- .../financier/activity/MyEntitySelector.kt | 8 +- .../activity/RequestPermissionActivity.java | 4 +- .../financier/base/AbstractListFragment.kt | 10 +- .../financier/dialog/WebViewDialog.java | 2 +- .../financier/filter/WhereFilter.java | 2 +- .../financier/fragments/AccountsFragment.kt | 66 +-- .../financier/fragments/BlotterFragment.kt | 90 ++-- .../financier/fragments/BudgetListFragment.kt | 26 +- .../fragments/ReportsListFragment.kt | 22 +- .../com/handydev/financier/model/Category.kt | 2 - .../financier/utils/MyPreferences.java | 6 +- .../main/res/layout/position_list_item.xml | 2 +- 22 files changed, 625 insertions(+), 617 deletions(-) delete mode 100644 app/src/main/java/com/handydev/financier/activity/AccountActivity.java create mode 100644 app/src/main/java/com/handydev/financier/activity/AccountActivity.kt diff --git a/app/build.gradle b/app/build.gradle index 6ae2e369..b830e4c3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -181,29 +181,29 @@ dependencies { annotationProcessor "org.androidannotations:androidannotations:$AAVersion" implementation "org.androidannotations:androidannotations-api:$AAVersion" - implementation 'com.google.code.gson:gson:2.8.6' + implementation 'com.google.code.gson:gson:2.8.7' implementation 'net.sf.trove4j:trove4j:3.0.3' implementation 'com.dropbox.core:dropbox-core-sdk:3.1.3' implementation 'com.squareup.okhttp3:okhttp:4.9.1' - implementation 'com.squareup.okio:okio:2.8.0' + implementation 'com.squareup.okio:okio:2.9.0' implementation "org.greenrobot:eventbus:$eventbus_version" kapt "org.greenrobot:eventbus-annotation-processor:$eventbus_version" implementation 'com.wdullaer:materialdatetimepicker:3.6.4' implementation 'commons-io:commons-io:2.6' implementation 'com.mtramin:rxfingerprint:2.2.1' - implementation 'io.reactivex.rxjava2:rxjava:2.2.19' + implementation 'io.reactivex.rxjava2:rxjava:2.2.21' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation 'org.reactivestreams:reactive-streams:1.0.3' implementation 'com.mlsdev.rximagepicker:library:2.1.5' - implementation 'com.github.bumptech.glide:glide:4.11.0' + implementation 'com.github.bumptech.glide:glide:4.12.0' implementation 'com.google.android.material:material:1.4.0' implementation fileTree(include: '**/*.jar', dir: 'libs') - testImplementation 'junit:junit:4.13.1' + testImplementation 'junit:junit:4.13.2' testImplementation 'androidx.test:core:1.4.0' - testImplementation 'org.robolectric:robolectric:4.4' + testImplementation 'org.robolectric:robolectric:4.5.1' implementation "androidx.core:core-ktx:1.6.0" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" } diff --git a/app/src/fdroid/java/com/handydev/financier/fragments/MenuListFragment.kt b/app/src/fdroid/java/com/handydev/financier/fragments/MenuListFragment.kt index d16e379f..15870f7a 100644 --- a/app/src/fdroid/java/com/handydev/financier/fragments/MenuListFragment.kt +++ b/app/src/fdroid/java/com/handydev/financier/fragments/MenuListFragment.kt @@ -41,7 +41,7 @@ class MenuListFragment: ListFragment() { bus = EventBus.getDefault() menuItems = MenuListItem.values() menuItems = menuItems.filter { it != MenuListItem.GOOGLE_DRIVE_BACKUP && it != MenuListItem.GOOGLE_DRIVE_RESTORE }.toTypedArray() - listAdapter = SummaryEntityListAdapter(activity!!, menuItems) + listAdapter = SummaryEntityListAdapter(requireActivity(), menuItems) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -54,7 +54,7 @@ class MenuListFragment: ListFragment() { if(activity == null) { return } - menuItems[position].call(activity!!) + menuItems[position].call(requireActivity()) } fun redirectedActivityResult(requestCode: Int, resultCode: Int, data:Intent?) { @@ -116,7 +116,7 @@ class MenuListFragment: ListFragment() { private fun onCsvExportResult(resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && activity != null) { val options = CsvExportOptions.fromIntent(data) - MenuListItem.doCsvExport(activity!!, options) + MenuListItem.doCsvExport(requireActivity(), options) } } @@ -124,7 +124,7 @@ class MenuListFragment: ListFragment() { private fun onQifExportResult(resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && activity != null) { val options = QifExportOptions.fromIntent(data) - MenuListItem.doQifExport(activity!!, options) + MenuListItem.doQifExport(requireActivity(), options) } } @@ -132,7 +132,7 @@ class MenuListFragment: ListFragment() { private fun onCsvImportResult(resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && activity != null) { val options = CsvImportOptions.fromIntent(data) - MenuListItem.doCsvImport(activity!!, options) + MenuListItem.doCsvImport(requireActivity(), options) } } @@ -140,21 +140,21 @@ class MenuListFragment: ListFragment() { private fun onQifImportResult(resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && activity != null) { val options = QifImportOptions.fromIntent(data) - MenuListItem.doQifImport(activity!!, options) + MenuListItem.doQifImport(requireActivity(), options) } } //@OnActivityResult(MenuListItem.ACTIVITY_CHANGE_PREFERENCES) private fun onChangePreferences() { if(activity != null) { - DailyAutoBackupScheduler.scheduleNextAutoBackup(activity!!) + DailyAutoBackupScheduler.scheduleNextAutoBackup(requireActivity()) } } override fun onPause() { super.onPause() if(activity != null) { - PinProtection.lock(activity!!) + PinProtection.lock(requireActivity()) } bus!!.unregister(this) } @@ -162,7 +162,7 @@ class MenuListFragment: ListFragment() { override fun onResume() { super.onResume() if(activity != null) { - PinProtection.unlock(activity!!) + PinProtection.unlock(requireActivity()) } bus!!.register(this) } @@ -181,7 +181,7 @@ class MenuListFragment: ListFragment() { //@OnActivityResult(RESOLVE_CONNECTION_REQUEST_CODE) private fun onConnectionRequest(resultCode: Int) { if (resultCode == Activity.RESULT_OK && activity != null) { - Toast.makeText(activity!!, R.string.google_drive_connection_resolved, Toast.LENGTH_LONG).show() + Toast.makeText(requireActivity(), R.string.google_drive_connection_resolved, Toast.LENGTH_LONG).show() } } @@ -191,12 +191,12 @@ class MenuListFragment: ListFragment() { val backupFiles = event.files if (backupFiles != null && activity != null) { val selectedDropboxFile = arrayOfNulls(1) - AlertDialog.Builder(activity!!) + AlertDialog.Builder(requireActivity()) .setTitle(R.string.restore_database_online_dropbox) .setPositiveButton(R.string.restore) { _, _ -> if (selectedDropboxFile[0] != null) { - val d = ProgressDialog.show(activity!!, null, getString(R.string.restore_database_inprogress_dropbox), true) - DropboxRestoreTask(activity!!, d, selectedDropboxFile[0]).execute() + val d = ProgressDialog.show(requireActivity(), null, getString(R.string.restore_database_inprogress_dropbox), true) + DropboxRestoreTask(requireActivity(), d, selectedDropboxFile[0]).execute() } } .setSingleChoiceItems(backupFiles, -1, DialogInterface.OnClickListener { dialog: DialogInterface?, which: Int -> @@ -213,8 +213,8 @@ class MenuListFragment: ListFragment() { if(activity == null) { return } - val d = ProgressDialog.show(activity!!, null, this.getString(R.string.backup_database_dropbox_inprogress), true) - DropboxBackupTask(activity!!, d).execute() + val d = ProgressDialog.show(requireActivity(), null, this.getString(R.string.backup_database_dropbox_inprogress), true) + DropboxBackupTask(requireActivity(), d).execute() } @Subscribe(threadMode = ThreadMode.MAIN) @@ -222,8 +222,8 @@ class MenuListFragment: ListFragment() { if(activity == null) { return } - val d = ProgressDialog.show(activity!!, null, this.getString(R.string.dropbox_loading_files), true) - DropboxListFilesTask(activity!!, d).execute() + val d = ProgressDialog.show(requireActivity(), null, this.getString(R.string.dropbox_loading_files), true) + DropboxListFilesTask(requireActivity(), d).execute() } class StartDropboxBackup diff --git a/app/src/googleplay/java/com/handydev/financier/fragments/MenuListFragment.kt b/app/src/googleplay/java/com/handydev/financier/fragments/MenuListFragment.kt index db7d1e01..719822d3 100644 --- a/app/src/googleplay/java/com/handydev/financier/fragments/MenuListFragment.kt +++ b/app/src/googleplay/java/com/handydev/financier/fragments/MenuListFragment.kt @@ -45,7 +45,7 @@ class MenuListFragment: ListFragment() { return } bus = EventBus.getDefault() - listAdapter = SummaryEntityListAdapter(activity!!, MenuListItem.values()) + listAdapter = SummaryEntityListAdapter(requireActivity(), MenuListItem.values()) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -58,7 +58,7 @@ class MenuListFragment: ListFragment() { if(activity == null) { return } - MenuListItem.values()[position].call(activity!!) + MenuListItem.values()[position].call(requireActivity()) } fun redirectedActivityResult(requestCode: Int, resultCode: Int, data:Intent?) { @@ -76,7 +76,7 @@ class MenuListFragment: ListFragment() { private fun onCsvExportResult(resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && activity != null) { val options = CsvExportOptions.fromIntent(data) - MenuListItem.doCsvExport(activity!!, options) + MenuListItem.doCsvExport(requireActivity(), options) } } @@ -84,7 +84,7 @@ class MenuListFragment: ListFragment() { private fun onQifExportResult(resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && activity != null) { val options = QifExportOptions.fromIntent(data) - MenuListItem.doQifExport(activity!!, options) + MenuListItem.doQifExport(requireActivity(), options) } } @@ -92,7 +92,7 @@ class MenuListFragment: ListFragment() { private fun onCsvImportResult(resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && activity != null) { val options = CsvImportOptions.fromIntent(data) - MenuListItem.doCsvImport(activity!!, options) + MenuListItem.doCsvImport(requireActivity(), options) } } @@ -100,21 +100,21 @@ class MenuListFragment: ListFragment() { private fun onQifImportResult(resultCode: Int, data: Intent?) { if (resultCode == Activity.RESULT_OK && activity != null) { val options = QifImportOptions.fromIntent(data) - MenuListItem.doQifImport(activity!!, options) + MenuListItem.doQifImport(requireActivity(), options) } } //@OnActivityResult(MenuListItem.ACTIVITY_CHANGE_PREFERENCES) private fun onChangePreferences() { if(activity != null) { - DailyAutoBackupScheduler.scheduleNextAutoBackup(activity!!) + DailyAutoBackupScheduler.scheduleNextAutoBackup(requireActivity()) } } override fun onPause() { super.onPause() if(activity != null) { - PinProtection.lock(activity!!) + PinProtection.lock(requireActivity()) } bus!!.unregister(this) } @@ -122,7 +122,7 @@ class MenuListFragment: ListFragment() { override fun onResume() { super.onResume() if(activity != null) { - PinProtection.unlock(activity!!) + PinProtection.unlock(requireActivity()) } bus!!.register(this) } @@ -151,7 +151,7 @@ class MenuListFragment: ListFragment() { return } - progressDialog = ProgressDialog.show(activity!!, null, getString(R.string.backup_database_gdocs_inprogress), true) + progressDialog = ProgressDialog.show(requireActivity(), null, getString(R.string.backup_database_gdocs_inprogress), true) bus!!.post(DoDriveBackup()) } @@ -188,7 +188,7 @@ class MenuListFragment: ListFragment() { (activity as? MainActivity)?.googleDriveLogin() return } - progressDialog = ProgressDialog.show(activity!!, null, getString(R.string.google_drive_loading_files), true) + progressDialog = ProgressDialog.show(requireActivity(), null, getString(R.string.google_drive_loading_files), true) bus!!.post(DoDriveListFiles()) } @@ -208,7 +208,7 @@ class MenuListFragment: ListFragment() { } val fileNames = getFileNames(filteredFiles) var selectedDriveFile : File? = null - AlertDialog.Builder(activity!!) + AlertDialog.Builder(requireActivity()) .setTitle(R.string.restore_database_online_google_drive) .setPositiveButton(R.string.restore) { _, _ -> if (selectedDriveFile != null) { @@ -243,13 +243,13 @@ class MenuListFragment: ListFragment() { val connectionResult = event.connectionResult if (connectionResult.hasResolution()) { try { - connectionResult.startResolutionForResult(activity!!, RESOLVE_CONNECTION_REQUEST_CODE) + connectionResult.startResolutionForResult(requireActivity(), RESOLVE_CONNECTION_REQUEST_CODE) } catch (e: SendIntentException) { // Unable to resolve, message user appropriately onDriveBackupError(DriveBackupError(e.message)) } } else { - GooglePlayServicesUtil.getErrorDialog(connectionResult.errorCode, activity!!, 0).show() + GooglePlayServicesUtil.getErrorDialog(connectionResult.errorCode, requireActivity(), 0).show() } } @@ -263,13 +263,13 @@ class MenuListFragment: ListFragment() { /* val status = event.status if (status.hasResolution()) { try { - status.startResolutionForResult(activity!!, RESOLVE_CONNECTION_REQUEST_CODE) + status.startResolutionForResult(requireActivity(), RESOLVE_CONNECTION_REQUEST_CODE) } catch (e: SendIntentException) { // Unable to resolve, message user appropriately onDriveBackupError(DriveBackupError(e.message)) } } else { - GooglePlayServicesUtil.getErrorDialog(status.statusCode, activity!!, 0).show() + GooglePlayServicesUtil.getErrorDialog(status.statusCode, requireActivity(), 0).show() }*/ } @@ -279,7 +279,7 @@ class MenuListFragment: ListFragment() { if(activity == null) { return } - Toast.makeText(activity!!, getString(R.string.google_drive_backup_success, event.fileName), Toast.LENGTH_LONG).show() + Toast.makeText(requireActivity(), getString(R.string.google_drive_backup_success, event.fileName), Toast.LENGTH_LONG).show() } @Subscribe(threadMode = ThreadMode.MAIN) @@ -288,7 +288,7 @@ class MenuListFragment: ListFragment() { if(activity == null) { return } - Toast.makeText(activity!!, R.string.restore_database_success, Toast.LENGTH_LONG).show() + Toast.makeText(requireActivity(), R.string.restore_database_success, Toast.LENGTH_LONG).show() } @Subscribe(threadMode = ThreadMode.MAIN) @@ -297,13 +297,13 @@ class MenuListFragment: ListFragment() { if(activity == null) { return } - Toast.makeText(activity!!, getString(R.string.google_drive_connection_failed, event.message), Toast.LENGTH_LONG).show() + Toast.makeText(requireActivity(), getString(R.string.google_drive_connection_failed, event.message), Toast.LENGTH_LONG).show() } //@OnActivityResult(RESOLVE_CONNECTION_REQUEST_CODE) private fun onConnectionRequest(resultCode: Int) { if (resultCode == Activity.RESULT_OK && activity != null) { - Toast.makeText(activity!!, R.string.google_drive_connection_resolved, Toast.LENGTH_LONG).show() + Toast.makeText(requireActivity(), R.string.google_drive_connection_resolved, Toast.LENGTH_LONG).show() } } @@ -313,12 +313,12 @@ class MenuListFragment: ListFragment() { val backupFiles = event.files if (backupFiles != null && activity != null) { val selectedDropboxFile = arrayOfNulls(1) - AlertDialog.Builder(activity!!) + AlertDialog.Builder(requireActivity()) .setTitle(R.string.restore_database_online_dropbox) .setPositiveButton(R.string.restore) { _, _ -> if (selectedDropboxFile[0] != null) { - val d = ProgressDialog.show(activity!!, null, getString(R.string.restore_database_inprogress_dropbox), true) - DropboxRestoreTask(activity!!, d, selectedDropboxFile[0]).execute() + val d = ProgressDialog.show(requireActivity(), null, getString(R.string.restore_database_inprogress_dropbox), true) + DropboxRestoreTask(requireActivity(), d, selectedDropboxFile[0]).execute() } } .setSingleChoiceItems(backupFiles, -1, DialogInterface.OnClickListener { dialog: DialogInterface?, which: Int -> @@ -335,8 +335,8 @@ class MenuListFragment: ListFragment() { if(activity == null) { return } - val d = ProgressDialog.show(activity!!, null, this.getString(R.string.backup_database_dropbox_inprogress), true) - DropboxBackupTask(activity!!, d).execute() + val d = ProgressDialog.show(requireActivity(), null, this.getString(R.string.backup_database_dropbox_inprogress), true) + DropboxBackupTask(requireActivity(), d).execute() } @Subscribe(threadMode = ThreadMode.MAIN) @@ -344,8 +344,8 @@ class MenuListFragment: ListFragment() { if(activity == null) { return } - val d = ProgressDialog.show(activity!!, null, this.getString(R.string.dropbox_loading_files), true) - DropboxListFilesTask(activity!!, d).execute() + val d = ProgressDialog.show(requireActivity(), null, this.getString(R.string.dropbox_loading_files), true) + DropboxListFilesTask(requireActivity(), d).execute() } class StartDropboxBackup diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cc40d8a4..d9095247 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,7 +19,6 @@ android:normalScreens="true" android:resizeable="true" android:smallScreens="true" /> - diff --git a/app/src/main/java/com/handydev/financier/FinancierApplication.kt b/app/src/main/java/com/handydev/financier/FinancierApplication.kt index acbf14bf..70ebe2d0 100644 --- a/app/src/main/java/com/handydev/financier/FinancierApplication.kt +++ b/app/src/main/java/com/handydev/financier/FinancierApplication.kt @@ -17,7 +17,7 @@ open class FinancierApplication : MultiDexApplication() { super.attachBaseContext(base) val acraPrefExists = PreferenceManager.getDefaultSharedPreferences(this).contains("acra.enable") if(!acraPrefExists) { - PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean("acra.enable", false).commit() + PreferenceManager.getDefaultSharedPreferences(this).edit().putBoolean("acra.enable", false).apply() } initAcra { diff --git a/app/src/main/java/com/handydev/financier/activity/AccountActivity.java b/app/src/main/java/com/handydev/financier/activity/AccountActivity.java deleted file mode 100644 index d408e896..00000000 --- a/app/src/main/java/com/handydev/financier/activity/AccountActivity.java +++ /dev/null @@ -1,433 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2010 Denis Solonenko. - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the GNU Public License v2.0 - * which accompanies this distribution, and is available at - * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html - * - * Contributors: - * Denis Solonenko - initial API and implementation - * Abdsandryk - adding bill filtering parameters - ******************************************************************************/ -package com.handydev.financier.activity; - -import android.content.Intent; -import android.database.Cursor; -import android.os.Bundle; -import androidx.core.content.ContextCompat; -import android.text.InputFilter; -import android.text.InputType; -import android.view.View; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ListAdapter; -import android.widget.TextView; -import android.widget.Toast; - -import com.handydev.financier.R; -import com.handydev.financier.adapter.EntityEnumAdapter; -import com.handydev.financier.model.Account; -import com.handydev.financier.model.AccountType; -import com.handydev.financier.model.CardIssuer; -import com.handydev.financier.model.Currency; -import com.handydev.financier.model.ElectronicPaymentType; -import com.handydev.financier.model.Transaction; -import com.handydev.financier.utils.EntityEnum; -import com.handydev.financier.utils.TransactionUtils; -import com.handydev.financier.utils.Utils; -import com.handydev.financier.widget.AmountInput; -import com.handydev.financier.widget.AmountInput_; - -import static com.handydev.financier.utils.EnumUtils.selectEnum; -import static com.handydev.financier.utils.Utils.text; - -public class AccountActivity extends AbstractActivity { - - public static final String ACCOUNT_ID_EXTRA = "accountId"; - - private static final int NEW_CURRENCY_REQUEST = 1; - - private AmountInput amountInput; - private AmountInput limitInput; - private View limitAmountView; - private EditText accountTitle; - - private Cursor currencyCursor; - private TextView currencyText; - private View accountTypeNode; - private View cardIssuerNode; - private View electronicPaymentNode; - private View issuerNode; - private EditText numberText; - private View numberNode; - private EditText issuerName; - private EditText sortOrderText; - private CheckBox isIncludedIntoTotals; - private EditText noteText; - private EditText closingDayText; - private EditText paymentDayText; - private View closingDayNode; - private View paymentDayNode; - - private EntityEnumAdapter accountTypeAdapter; - private EntityEnumAdapter cardIssuerAdapter; - private EntityEnumAdapter electronicPaymentAdapter; - private ListAdapter currencyAdapter; - - private Account account = new Account(); - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.account); - - accountTitle = new EditText(this); - accountTitle.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); - accountTitle.setSingleLine(); - - issuerName = new EditText(this); - issuerName.setSingleLine(); - - numberText = new EditText(this); - numberText.setHint(R.string.card_number_hint); - numberText.setSingleLine(); - - sortOrderText = new EditText(this); - sortOrderText.setInputType(InputType.TYPE_CLASS_NUMBER); - sortOrderText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(3)}); - sortOrderText.setSingleLine(); - - closingDayText = new EditText(this); - closingDayText.setInputType(InputType.TYPE_CLASS_NUMBER); - closingDayText.setHint(R.string.closing_day_hint); - closingDayText.setSingleLine(); - - paymentDayText = new EditText(this); - paymentDayText.setInputType(InputType.TYPE_CLASS_NUMBER); - paymentDayText.setHint(R.string.payment_day_hint); - paymentDayText.setSingleLine(); - - amountInput = AmountInput_.build(this); - amountInput.setOwner(this); - - limitInput = AmountInput_.build(this); - limitInput.setOwner(this); - - LinearLayout layout = findViewById(R.id.layout); - - accountTypeAdapter = new EntityEnumAdapter<>(this, AccountType.values(), false); - accountTypeNode = activityLayout.addListNodeIcon(layout, R.id.account_type, R.string.account_type, R.string.account_type); - ImageView icon = accountTypeNode.findViewById(R.id.icon); - icon.setColorFilter(ContextCompat.getColor(this, R.color.holo_gray_light)); - - cardIssuerAdapter = new EntityEnumAdapter<>(this, CardIssuer.values(), false); - cardIssuerNode = activityLayout.addListNodeIcon(layout, R.id.card_issuer, R.string.card_issuer, R.string.card_issuer); - setVisibility(cardIssuerNode, View.GONE); - - electronicPaymentAdapter = new EntityEnumAdapter<>(this, ElectronicPaymentType.values(), false); - electronicPaymentNode = activityLayout.addListNodeIcon(layout, R.id.electronic_payment_type, R.string.electronic_payment_type, R.string.card_issuer); - setVisibility(electronicPaymentNode, View.GONE); - - issuerNode = activityLayout.addEditNode(layout, R.string.issuer, issuerName); - setVisibility(issuerNode, View.GONE); - - numberNode = activityLayout.addEditNode(layout, R.string.card_number, numberText); - setVisibility(numberNode, View.GONE); - - closingDayNode = activityLayout.addEditNode(layout, R.string.closing_day, closingDayText); - setVisibility(closingDayNode, View.GONE); - - paymentDayNode = activityLayout.addEditNode(layout, R.string.payment_day, paymentDayText); - setVisibility(paymentDayNode, View.GONE); - - currencyCursor = db.getAllCurrencies("name"); - startManagingCursor(currencyCursor); - currencyAdapter = TransactionUtils.createCurrencyAdapter(this, currencyCursor); - - activityLayout.addEditNode(layout, R.string.title, accountTitle); - currencyText = activityLayout.addListNodePlus(layout, R.id.currency, R.id.currency_add, R.string.currency, R.string.select_currency); - - limitInput.setExpense(); - limitInput.disableIncomeExpenseButton(); - limitAmountView = activityLayout.addEditNode(layout, R.string.limit_amount, limitInput); - setVisibility(limitAmountView, View.GONE); - - Intent intent = getIntent(); - if (intent != null) { - long accountId = intent.getLongExtra(ACCOUNT_ID_EXTRA, -1); - if (accountId != -1) { - this.account = db.getAccount(accountId); - if (this.account == null) { - this.account = new Account(); - } - } else { - selectAccountType(AccountType.valueOf(account.type)); - } - } - - if (account.id == -1) { - activityLayout.addEditNode(layout, R.string.opening_amount, amountInput); - amountInput.setIncome(); - } - - noteText = new EditText(this); - noteText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES); - noteText.setLines(2); - activityLayout.addEditNode(layout, R.string.note, noteText); - - activityLayout.addEditNode(layout, R.string.sort_order, sortOrderText); - isIncludedIntoTotals = activityLayout.addCheckboxNode(layout, - R.id.is_included_into_totals, R.string.is_included_into_totals, - R.string.is_included_into_totals_summary, true); - - if (account.id > 0) { - editAccount(); - } - - Button bOK = findViewById(R.id.bOK); - bOK.setOnClickListener(arg0 -> { - if (account.currency == null) { - Toast.makeText(AccountActivity.this, R.string.select_currency, Toast.LENGTH_SHORT).show(); - return; - } - if (Utils.isEmpty(accountTitle)) { - accountTitle.setError(getString(R.string.title)); - return; - } - AccountType type = AccountType.valueOf(account.type); - if (type.hasIssuer) { - account.issuer = Utils.text(issuerName); - } - if (type.hasNumber) { - account.number = Utils.text(numberText); - } - - /********** validate closing and payment days **********/ - if (type.isCreditCard) { - String closingDay = Utils.text(closingDayText); - account.closingDay = closingDay == null ? 0 : Integer.parseInt(closingDay); - if (account.closingDay != 0) { - if (account.closingDay > 31) { - Toast.makeText(AccountActivity.this, R.string.closing_day_error, Toast.LENGTH_SHORT).show(); - return; - } - } - - String paymentDay = Utils.text(paymentDayText); - account.paymentDay = paymentDay == null ? 0 : Integer.parseInt(paymentDay); - if (account.paymentDay != 0) { - if (account.paymentDay > 31) { - Toast.makeText(AccountActivity.this, R.string.payment_day_error, Toast.LENGTH_SHORT).show(); - return; - } - } - } - - account.title = text(accountTitle); - account.creationDate = System.currentTimeMillis(); - String sortOrder = text(sortOrderText); - account.sortOrder = sortOrder == null ? 0 : Integer.parseInt(sortOrder); - account.isIncludeIntoTotals = isIncludedIntoTotals.isChecked(); - account.limitAmount = -Math.abs(limitInput.getAmount()); - account.note = text(noteText); - - long accountId = db.saveAccount(account); - long amount = amountInput.getAmount(); - if (amount != 0) { - Transaction t = new Transaction(); - t.fromAccountId = accountId; - t.categoryId = 0; - t.note = getResources().getText(R.string.opening_amount) + " (" + account.title + ")"; - t.fromAmount = amount; - db.insertOrUpdate(t, null); - } - AccountWidget.updateWidgets(this); - Intent intent1 = new Intent(); - intent1.putExtra(ACCOUNT_ID_EXTRA, accountId); - setResult(RESULT_OK, intent1); - finish(); - }); - - Button bCancel = findViewById(R.id.bCancel); - bCancel.setOnClickListener(arg0 -> { - setResult(RESULT_CANCELED); - finish(); - }); - - } - - @Override - protected void onClick(View v, int id) { - switch (id) { - case R.id.is_included_into_totals: - isIncludedIntoTotals.performClick(); - break; - case R.id.account_type: - activityLayout.selectPosition(this, R.id.account_type, R.string.account_type, accountTypeAdapter, AccountType.valueOf(account.type).ordinal()); - break; - case R.id.card_issuer: - activityLayout.selectPosition(this, R.id.card_issuer, R.string.card_issuer, cardIssuerAdapter, - account.cardIssuer != null ? CardIssuer.valueOf(account.cardIssuer).ordinal() : 0); - break; - case R.id.electronic_payment_type: - activityLayout.selectPosition(this, R.id.electronic_payment_type, R.string.electronic_payment_type, electronicPaymentAdapter, - selectEnum(ElectronicPaymentType.class, account.cardIssuer, ElectronicPaymentType.PAYPAL).ordinal()); - break; - case R.id.currency: - activityLayout.select(this, R.id.currency, R.string.currency, currencyCursor, currencyAdapter, - "_id", account.currency != null ? account.currency.id : -1); - break; - case R.id.currency_add: - addNewCurrency(); - break; - } - } - - private void addNewCurrency() { - new CurrencySelector(this, db, currencyId -> { - if (currencyId == 0) { - Intent intent = new Intent(AccountActivity.this, CurrencyActivity.class); - startActivityForResult(intent, NEW_CURRENCY_REQUEST); - } else { - currencyCursor.requery(); - selectCurrency(currencyId); - } - }).show(); - } - - @Override - public void onSelectedId(int id, long selectedId) { - switch (id) { - case R.id.currency: - selectCurrency(selectedId); - break; - } - } - - @Override - public void onSelectedPos(int id, int selectedPos) { - switch (id) { - case R.id.account_type: - AccountType type = AccountType.values()[selectedPos]; - selectAccountType(type); - break; - case R.id.card_issuer: - CardIssuer issuer = CardIssuer.values()[selectedPos]; - selectCardIssuer(issuer); - break; - case R.id.electronic_payment_type: - ElectronicPaymentType paymentType = ElectronicPaymentType.values()[selectedPos]; - selectElectronicType(paymentType); - break; - } - } - - private void selectAccountType(AccountType type) { - ImageView icon = accountTypeNode.findViewById(R.id.icon); - icon.setImageResource(type.iconId); - TextView label = accountTypeNode.findViewById(R.id.label); - label.setText(type.titleId); - - setVisibility(cardIssuerNode, type.isCard ? View.VISIBLE : View.GONE); - setVisibility(issuerNode, type.hasIssuer ? View.VISIBLE : View.GONE); - setVisibility(electronicPaymentNode, type.isElectronic ? View.VISIBLE : View.GONE); - setVisibility(numberNode, type.hasNumber ? View.VISIBLE : View.GONE); - setVisibility(closingDayNode, type.isCreditCard ? View.VISIBLE : View.GONE); - setVisibility(paymentDayNode, type.isCreditCard ? View.VISIBLE : View.GONE); - - setVisibility(limitAmountView, type == AccountType.CREDIT_CARD ? View.VISIBLE : View.GONE); - account.type = type.name(); - if (type.isCard) { - selectCardIssuer(selectEnum(CardIssuer.class, account.cardIssuer, CardIssuer.DEFAULT)); - } else if (type.isElectronic) { - selectElectronicType(selectEnum(ElectronicPaymentType.class, account.cardIssuer, ElectronicPaymentType.PAYPAL)); - } else { - account.cardIssuer = null; - } - } - - private void selectCardIssuer(CardIssuer issuer) { - updateNode(cardIssuerNode, issuer); - account.cardIssuer = issuer.name(); - } - - private void selectElectronicType(ElectronicPaymentType paymentType) { - updateNode(electronicPaymentNode, paymentType); - account.cardIssuer = paymentType.name(); - } - - private void updateNode(View note, EntityEnum enumItem) { - ImageView icon = note.findViewById(R.id.icon); - icon.setImageResource(enumItem.getIconId()); - TextView label = note.findViewById(R.id.label); - label.setText(enumItem.getTitleId()); - } - - private void selectCurrency(long currencyId) { - Currency c = db.get(Currency.class, currencyId); - if (c != null) { - selectCurrency(c); - } - } - - private void selectCurrency(Currency c) { - currencyText.setText(c.name); - amountInput.setCurrency(c); - limitInput.setCurrency(c); - account.currency = c; - } - - private void editAccount() { - selectAccountType(AccountType.valueOf(account.type)); - selectCurrency(account.currency); - accountTitle.setText(account.title); - issuerName.setText(account.issuer); - numberText.setText(account.number); - sortOrderText.setText(String.valueOf(account.sortOrder)); - - /******** bill filtering ********/ - if (account.closingDay > 0) { - closingDayText.setText(String.valueOf(account.closingDay)); - } - if (account.paymentDay > 0) { - paymentDayText.setText(String.valueOf(account.paymentDay)); - } - /********************************/ - - isIncludedIntoTotals.setChecked(account.isIncludeIntoTotals); - if (account.limitAmount != 0) { - limitInput.setAmount(-Math.abs(account.limitAmount)); - } - noteText.setText(account.note); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (resultCode == RESULT_OK) { - switch (requestCode) { - case NEW_CURRENCY_REQUEST: - currencyCursor.requery(); - long currencyId = data.getLongExtra(CurrencyActivity.CURRENCY_ID_EXTRA, -1); - if (currencyId != -1) { - selectCurrency(currencyId); - } - break; - } - } - } - - @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - } - -} diff --git a/app/src/main/java/com/handydev/financier/activity/AccountActivity.kt b/app/src/main/java/com/handydev/financier/activity/AccountActivity.kt new file mode 100644 index 00000000..54ed9aa5 --- /dev/null +++ b/app/src/main/java/com/handydev/financier/activity/AccountActivity.kt @@ -0,0 +1,445 @@ +/******************************************************************************* + * Copyright (c) 2010 Denis Solonenko. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the GNU Public License v2.0 + * which accompanies this distribution, and is available at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * + * Contributors: + * Denis Solonenko - initial API and implementation + * Abdsandryk - adding bill filtering parameters + */ +package com.handydev.financier.activity + +import com.handydev.financier.activity.ActivityLayout.addListNodeIcon +import com.handydev.financier.activity.ActivityLayout.addEditNode +import com.handydev.financier.utils.TransactionUtils.createCurrencyAdapter +import com.handydev.financier.activity.ActivityLayout.addListNodePlus +import com.handydev.financier.activity.ActivityLayout.addCheckboxNode +import com.handydev.financier.db.DatabaseAdapter.insertOrUpdate +import com.handydev.financier.activity.ActivityLayout.selectPosition +import com.handydev.financier.activity.ActivityLayout.select +import com.handydev.financier.activity.AbstractActivity +import com.handydev.financier.widget.AmountInput +import com.handydev.financier.adapter.EntityEnumAdapter +import android.os.Bundle +import com.handydev.financier.R +import android.text.InputType +import android.text.InputFilter +import android.text.InputFilter.LengthFilter +import com.handydev.financier.widget.AmountInput_ +import androidx.core.content.ContextCompat +import com.handydev.financier.utils.TransactionUtils +import android.content.Intent +import com.handydev.financier.activity.AccountActivity +import com.handydev.financier.activity.AccountWidget +import android.app.Activity +import android.database.Cursor +import android.view.View +import android.widget.* +import com.handydev.financier.utils.EnumUtils +import com.handydev.financier.activity.CurrencySelector +import com.handydev.financier.activity.CurrencySelector.OnCurrencyCreatedListener +import com.handydev.financier.activity.CurrencyActivity +import com.handydev.financier.model.* +import com.handydev.financier.utils.EntityEnum +import com.handydev.financier.utils.Utils + +class AccountActivity : AbstractActivity() { + private var amountInput: AmountInput? = null + private var limitInput: AmountInput? = null + private var limitAmountView: View? = null + private var accountTitle: EditText? = null + private var currencyCursor: Cursor? = null + private var currencyText: TextView? = null + private var accountTypeNode: View? = null + private var cardIssuerNode: View? = null + private var electronicPaymentNode: View? = null + private var issuerNode: View? = null + private var numberText: EditText? = null + private var numberNode: View? = null + private var issuerName: EditText? = null + private var sortOrderText: EditText? = null + private var isIncludedIntoTotals: CheckBox? = null + private var noteText: EditText? = null + private var closingDayText: EditText? = null + private var paymentDayText: EditText? = null + private var closingDayNode: View? = null + private var paymentDayNode: View? = null + private var accountTypeAdapter: EntityEnumAdapter? = null + private var cardIssuerAdapter: EntityEnumAdapter? = null + private var electronicPaymentAdapter: EntityEnumAdapter? = null + private var currencyAdapter: ListAdapter? = null + private var account: Account? = Account() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.account) + accountTitle = EditText(this) + accountTitle!!.inputType = + InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES + accountTitle!!.setSingleLine() + issuerName = EditText(this) + issuerName!!.setSingleLine() + numberText = EditText(this) + numberText!!.setHint(R.string.card_number_hint) + numberText!!.setSingleLine() + sortOrderText = EditText(this) + sortOrderText!!.inputType = InputType.TYPE_CLASS_NUMBER + sortOrderText!!.filters = arrayOf(LengthFilter(3)) + sortOrderText!!.setSingleLine() + closingDayText = EditText(this) + closingDayText!!.inputType = InputType.TYPE_CLASS_NUMBER + closingDayText!!.setHint(R.string.closing_day_hint) + closingDayText!!.setSingleLine() + paymentDayText = EditText(this) + paymentDayText!!.inputType = InputType.TYPE_CLASS_NUMBER + paymentDayText!!.setHint(R.string.payment_day_hint) + paymentDayText!!.setSingleLine() + amountInput = AmountInput_.build(this) + amountInput.setOwner(this) + limitInput = AmountInput_.build(this) + limitInput.setOwner(this) + val layout = findViewById(R.id.layout) + accountTypeAdapter = EntityEnumAdapter(this, AccountType.values(), false) + accountTypeNode = activityLayout.addListNodeIcon( + layout, + R.id.account_type, + R.string.account_type, + R.string.account_type + ) + val icon = accountTypeNode!!.findViewById(R.id.icon) + icon.setColorFilter(ContextCompat.getColor(this, R.color.holo_gray_light)) + cardIssuerAdapter = EntityEnumAdapter(this, CardIssuer.values(), false) + cardIssuerNode = activityLayout.addListNodeIcon( + layout, + R.id.card_issuer, + R.string.card_issuer, + R.string.card_issuer + ) + setVisibility(cardIssuerNode, View.GONE) + electronicPaymentAdapter = EntityEnumAdapter(this, ElectronicPaymentType.values(), false) + electronicPaymentNode = activityLayout.addListNodeIcon( + layout, + R.id.electronic_payment_type, + R.string.electronic_payment_type, + R.string.card_issuer + ) + setVisibility(electronicPaymentNode, View.GONE) + issuerNode = activityLayout.addEditNode(layout, R.string.issuer, issuerName) + setVisibility(issuerNode, View.GONE) + numberNode = activityLayout.addEditNode(layout, R.string.card_number, numberText) + setVisibility(numberNode, View.GONE) + closingDayNode = activityLayout.addEditNode(layout, R.string.closing_day, closingDayText) + setVisibility(closingDayNode, View.GONE) + paymentDayNode = activityLayout.addEditNode(layout, R.string.payment_day, paymentDayText) + setVisibility(paymentDayNode, View.GONE) + currencyCursor = db.getAllCurrencies("name") + startManagingCursor(currencyCursor) + currencyAdapter = createCurrencyAdapter(this, currencyCursor) + activityLayout.addEditNode(layout, R.string.title, accountTitle) + currencyText = activityLayout.addListNodePlus( + layout, + R.id.currency, + R.id.currency_add, + R.string.currency, + R.string.select_currency + ) + limitInput.setExpense() + limitInput.disableIncomeExpenseButton() + limitAmountView = activityLayout.addEditNode(layout, R.string.limit_amount, limitInput) + setVisibility(limitAmountView, View.GONE) + val intent = intent + if (intent != null) { + val accountId = intent.getLongExtra(ACCOUNT_ID_EXTRA, -1) + if (accountId != -1L) { + account = db.getAccount(accountId) + if (account == null) { + account = Account() + } + } else { + selectAccountType(AccountType.valueOf(account!!.type)) + } + } + if (account!!.id == -1L) { + activityLayout.addEditNode(layout, R.string.opening_amount, amountInput) + amountInput.setIncome() + } + noteText = EditText(this) + noteText!!.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_CAP_SENTENCES + noteText!!.setLines(2) + activityLayout.addEditNode(layout, R.string.note, noteText) + activityLayout.addEditNode(layout, R.string.sort_order, sortOrderText) + isIncludedIntoTotals = activityLayout.addCheckboxNode( + layout, + R.id.is_included_into_totals, R.string.is_included_into_totals, + R.string.is_included_into_totals_summary, true + ) + if (account!!.id > 0) { + editAccount() + } + val bOK = findViewById