From 1a7dfd2166661dbb5eb72176c4262549d415b803 Mon Sep 17 00:00:00 2001 From: Avneet Singh Date: Wed, 14 Feb 2024 02:57:36 +0530 Subject: [PATCH] refactor #2511: migrated savings account detail screen to compose --- .../mobile/ui/activities/HomeActivity.kt | 3 +- .../SavingsAccountContainerActivity.kt | 15 +- .../mobile/ui/fragments/AccountsFragment.kt | 12 +- .../ui/fragments/AddGuarantorFragment.kt | 18 +- .../BeneficiaryApplicationFragment.kt | 25 +- .../ui/fragments/BeneficiaryDetailFragment.kt | 4 +- .../ui/fragments/BeneficiaryListFragment.kt | 6 +- .../ui/fragments/ClientAccountsFragment.kt | 6 +- .../ui/fragments/ClientChargeFragment.kt | 15 +- .../ui/fragments/GuarantorDetailFragment.kt | 3 +- .../fragments/LoanAccountSummaryFragment.kt | 3 +- .../LoanAccountTransactionFragment.kt | 9 +- .../fragments/LoanAccountWithdrawFragment.kt | 3 +- .../fragments/LoanAccountsDetailFragment.kt | 3 +- .../ui/fragments/LoanApplicationFragment.kt | 17 +- .../LoanRepaymentScheduleFragment.kt | 8 +- .../ui/fragments/QrCodeDisplayFragment.kt | 2 + .../ui/fragments/QrCodeImportFragment.kt | 5 +- .../fragments/RecentTransactionsFragment.kt | 6 +- .../ReviewLoanApplicationFragment.kt | 8 +- .../fragments/SavingAccountsDetailFragment.kt | 467 ------------------ .../SavingAccountsTransactionFragment.kt | 11 +- .../SavingsAccountApplicationFragment.kt | 15 +- .../SavingsAccountWithdrawFragment.kt | 9 +- .../fragments/SavingsMakeTransferFragment.kt | 11 +- .../fragments/ThirdPartyTransferFragment.kt | 17 +- .../ui/fragments/TransferProcessFragment.kt | 13 +- .../SavingAccountsDetailFragment.kt | 213 ++++++++ .../SavingAccountsDetailViewModel.kt | 75 +++ .../SavingsAccountDetailContent.kt | 403 +++++++++++++++ .../SavingsAccountDetailScreen.kt | 117 +++++ .../SavingsAccountDetailTopBar.kt | 89 ++++ .../ui/user_profile/UserProfileFragment.kt | 6 +- .../utils/ParcelableAndSerializableUtils.kt | 32 ++ .../SavingAccountsDetailViewModel.kt | 44 -- .../SavingAccountsDetailViewModelTest.kt | 1 + .../mobile/core/ui/component/EmptyDataView.kt | 6 +- .../core/ui/component/MifosRoundIcon.kt | 31 ++ .../mobile/core/ui/component/NoInternet.kt | 26 +- .../org/mifos/mobile/core/ui/theme/Color.kt | 7 +- 40 files changed, 1186 insertions(+), 578 deletions(-) delete mode 100644 app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsDetailFragment.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/savings_account/SavingAccountsDetailFragment.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/savings_account/SavingAccountsDetailViewModel.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailContent.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailScreen.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailTopBar.kt create mode 100644 app/src/main/java/org/mifos/mobile/utils/ParcelableAndSerializableUtils.kt delete mode 100644 app/src/main/java/org/mifos/mobile/viewModels/SavingAccountsDetailViewModel.kt create mode 100644 ui/src/main/java/org/mifos/mobile/core/ui/component/MifosRoundIcon.kt diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/HomeActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/HomeActivity.kt index 0783ea881..8c0113d89 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/HomeActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/HomeActivity.kt @@ -46,6 +46,7 @@ import org.mifos.mobile.utils.UserDetailUiState import org.mifos.mobile.utils.fcm.RegistrationIntentService import org.mifos.mobile.ui.user_profile.UserDetailViewModel import org.mifos.mobile.ui.user_profile.UserProfileActivity +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import javax.inject.Inject /** @@ -96,7 +97,7 @@ class HomeActivity : viewModel.userImage showUserImage(null) } else { - client = savedInstanceState.getParcelable(Constants.USER_DETAILS) + client = savedInstanceState.getCheckedParcelable(Client::class.java, Constants.USER_DETAILS) viewModel.setUserProfile(preferencesHelper?.userProfileImage) showUserDetails(client) } diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/SavingsAccountContainerActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/SavingsAccountContainerActivity.kt index 197871b99..14637aa44 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/SavingsAccountContainerActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/SavingsAccountContainerActivity.kt @@ -1,10 +1,11 @@ package org.mifos.mobile.ui.activities import android.os.Bundle +import android.view.View import org.mifos.mobile.R import org.mifos.mobile.databinding.ActivityContainerBinding import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.fragments.SavingAccountsDetailFragment +import org.mifos.mobile.ui.savings_account.SavingAccountsDetailFragment import org.mifos.mobile.utils.Constants /** @@ -35,6 +36,18 @@ class SavingsAccountContainerActivity : BaseActivity() { } } + fun hideToolbar() { + binding.apply { + toolbar?.visibility = View.GONE + } + } + + fun showToolbar() { + binding.apply { + toolbar?.visibility = View.VISIBLE + } + } + companion object { var transferSuccess = false } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt index 229e53dda..c2911c495 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt @@ -28,6 +28,7 @@ import org.mifos.mobile.ui.adapters.SavingAccountsListAdapter import org.mifos.mobile.ui.adapters.ShareAccountsListAdapter import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.* +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedArrayListFromParcelable import org.mifos.mobile.viewModels.AccountsViewModel import java.util.* @@ -137,14 +138,18 @@ class AccountsFragment : BaseFragment(), OnRefreshListener { when (accountType) { Constants.SAVINGS_ACCOUNTS -> { val savingAccountList: List = - savedInstanceState.getParcelableArrayList(Constants.SAVINGS_ACCOUNTS) + savedInstanceState.getCheckedArrayListFromParcelable( + SavingAccount::class.java, + Constants.SAVINGS_ACCOUNTS + ) ?: listOf() showSavingsAccounts(savingAccountList) } Constants.LOAN_ACCOUNTS -> { val loanAccountList: List = - savedInstanceState.getParcelableArrayList( + savedInstanceState.getCheckedArrayListFromParcelable( + LoanAccount::class.java, Constants.LOAN_ACCOUNTS, ) ?: listOf() showLoanAccounts(loanAccountList) @@ -152,7 +157,8 @@ class AccountsFragment : BaseFragment(), OnRefreshListener { Constants.SHARE_ACCOUNTS -> { val shareAccountList: List = - savedInstanceState.getParcelableArrayList( + savedInstanceState.getCheckedArrayListFromParcelable( + ShareAccount::class.java, Constants.SHARE_ACCOUNTS, ) ?: listOf() showShareAccounts(shareAccountList) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/AddGuarantorFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/AddGuarantorFragment.kt index 653a50330..8663881a1 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/AddGuarantorFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/AddGuarantorFragment.kt @@ -23,6 +23,8 @@ import org.mifos.mobile.ui.enums.GuarantorState import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.GuarantorUiState +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedSerializable import org.mifos.mobile.utils.RxBus.publish import org.mifos.mobile.utils.RxEvent.AddGuarantorEvent import org.mifos.mobile.utils.RxEvent.UpdateGuarantorEvent @@ -51,16 +53,12 @@ class AddGuarantorFragment : BaseFragment() { super.onCreate(savedInstanceState) if (arguments != null) { loanId = arguments?.getLong(Constants.LOAN_ID) - guarantorState = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - arguments?.getSerializable(Constants.GUARANTOR_STATE, GuarantorState::class.java) - } else { - arguments?.getSerializable(Constants.GUARANTOR_STATE) as GuarantorState? - } - payload = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - arguments?.getParcelable(Constants.PAYLOAD, GuarantorPayload::class.java) - } else { - arguments?.getParcelable(Constants.PAYLOAD) as GuarantorPayload? - } + guarantorState = requireArguments().getCheckedSerializable( + GuarantorState::class.java, + Constants.GUARANTOR_STATE + ) as GuarantorState + payload = + arguments?.getCheckedParcelable(GuarantorPayload::class.java, Constants.PAYLOAD) index = arguments?.getInt(Constants.INDEX) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryApplicationFragment.kt index e6e769c25..63097d506 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryApplicationFragment.kt @@ -23,6 +23,8 @@ import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.BeneficiaryUiState import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedSerializable import org.mifos.mobile.utils.Toaster import org.mifos.mobile.viewModels.BeneficiaryApplicationViewModel @@ -47,16 +49,24 @@ class BeneficiaryApplicationFragment : BaseFragment() { super.onCreate(savedInstanceState) setToolbarTitle(getString(R.string.add_beneficiary)) if (arguments != null) { - beneficiaryState = requireArguments() - .getSerializable(Constants.BENEFICIARY_STATE) as BeneficiaryState + beneficiaryState = requireArguments().getCheckedSerializable( + BeneficiaryState::class.java, + Constants.BENEFICIARY_STATE + ) as BeneficiaryState when (beneficiaryState) { BeneficiaryState.UPDATE -> { - beneficiary = arguments?.getParcelable(Constants.BENEFICIARY) + beneficiary = arguments?.getCheckedParcelable( + Beneficiary::class.java, + Constants.BENEFICIARY + ) setToolbarTitle(getString(R.string.update_beneficiary)) } BeneficiaryState.CREATE_QR -> { - beneficiary = arguments?.getParcelable(Constants.BENEFICIARY) + beneficiary = arguments?.getCheckedParcelable( + Beneficiary::class.java, + Constants.BENEFICIARY + ) setToolbarTitle(getString(R.string.add_beneficiary)) } @@ -140,7 +150,12 @@ class BeneficiaryApplicationFragment : BaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { - showBeneficiaryTemplate(savedInstanceState.getParcelable(Constants.TEMPLATE) as BeneficiaryTemplate) + showBeneficiaryTemplate( + savedInstanceState.getCheckedParcelable( + BeneficiaryTemplate::class.java, + Constants.TEMPLATE + ) + ) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryDetailFragment.kt index 80b825d20..caf3f288a 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryDetailFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryDetailFragment.kt @@ -24,6 +24,7 @@ import org.mifos.mobile.utils.BeneficiaryUiState import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.CurrencyUtil import org.mifos.mobile.utils.MaterialDialog +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.Toaster import org.mifos.mobile.viewModels.BeneficiaryDetailViewModel @@ -42,7 +43,8 @@ class BeneficiaryDetailFragment : BaseFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (arguments != null) { - beneficiary = arguments?.getParcelable(Constants.BENEFICIARY) + beneficiary = + arguments?.getCheckedParcelable(Beneficiary::class.java, Constants.BENEFICIARY) } setHasOptionsMenu(true) } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryListFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryListFragment.kt index 9ed078b73..21b921fcf 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryListFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryListFragment.kt @@ -28,6 +28,7 @@ import org.mifos.mobile.utils.BeneficiaryUiState import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.DividerItemDecoration import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedArrayListFromParcelable import org.mifos.mobile.viewModels.BeneficiaryListViewModel /** @@ -114,7 +115,10 @@ class BeneficiaryListFragment : BaseFragment(), OnRefreshListener { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { val beneficiaries: List = - savedInstanceState.getParcelableArrayList(Constants.BENEFICIARY) ?: listOf() + savedInstanceState.getCheckedArrayListFromParcelable( + Beneficiary::class.java, + Constants.BENEFICIARY + ) ?: listOf() showBeneficiaryList(beneficiaries) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt index bf6963169..0c569a9db 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt @@ -32,6 +32,7 @@ import org.mifos.mobile.ui.adapters.ViewPagerAdapter import org.mifos.mobile.ui.enums.AccountType import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedSerializable import org.mifos.mobile.utils.StatusUtils import org.mifos.mobile.viewModels.AccountsViewModel import javax.inject.Inject @@ -56,7 +57,10 @@ class ClientAccountsFragment : BaseFragment() { super.onCreate(savedInstanceState) setHasOptionsMenu(true) if (arguments != null) { - accountType = arguments?.getSerializable(Constants.ACCOUNT_TYPE) as AccountType + accountType = arguments?.getCheckedSerializable( + AccountType::class.java, + Constants.ACCOUNT_TYPE + ) as AccountType } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/ClientChargeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/ClientChargeFragment.kt index 59db3f0a4..30f47da4b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/ClientChargeFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/ClientChargeFragment.kt @@ -17,12 +17,15 @@ import kotlinx.coroutines.launch import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentClientChargeBinding import org.mifos.mobile.models.Charge +import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity import org.mifos.mobile.ui.adapters.ClientChargeAdapter import org.mifos.mobile.ui.enums.ChargeType import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.ClientChargeUiState import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedArrayListFromParcelable +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedSerializable import org.mifos.mobile.utils.Toaster import org.mifos.mobile.viewModels.ClientChargeViewModel @@ -46,9 +49,13 @@ class ClientChargeFragment : BaseFragment() { private var sweetUIErrorHandler: SweetUIErrorHandler? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + (activity as? SavingsAccountContainerActivity)?.showToolbar() if (arguments != null) { id = arguments?.getLong(Constants.CLIENT_ID) - chargeType = arguments?.getSerializable(Constants.CHARGE_TYPE) as ChargeType + chargeType = arguments?.getCheckedSerializable( + ChargeType::class.java, + Constants.CHARGE_TYPE + ) as ChargeType } } @@ -121,8 +128,10 @@ class ClientChargeFragment : BaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { - val charges: List = - savedInstanceState.getParcelableArrayList(Constants.CHARGES) ?: listOf() + val charges: List = savedInstanceState.getCheckedArrayListFromParcelable( + Charge::class.java, + Constants.CHARGES + ) ?: listOf() showClientCharges(charges) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorDetailFragment.kt index 83ee6b22c..8a7b98b9b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorDetailFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/GuarantorDetailFragment.kt @@ -17,6 +17,7 @@ import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.enums.GuarantorState import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.* +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.RxBus.listen import org.mifos.mobile.utils.RxBus.publish import org.mifos.mobile.utils.RxEvent.DeleteGuarantorEvent @@ -44,7 +45,7 @@ class GuarantorDetailFragment : BaseFragment() { super.onCreate(savedInstanceState) if (arguments != null) { loanId = arguments?.getLong(Constants.LOAN_ID) - payload = arguments?.getParcelable(Constants.GUARANTOR_DETAILS) + payload = arguments?.getCheckedParcelable(GuarantorPayload::class.java, Constants.GUARANTOR_DETAILS) index = arguments?.getInt(Constants.INDEX) guarantorId = payload?.id } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountSummaryFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountSummaryFragment.kt index 38e7052fa..f286511ae 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountSummaryFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountSummaryFragment.kt @@ -11,6 +11,7 @@ import org.mifos.mobile.models.accounts.loan.LoanWithAssociations import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.CurrencyUtil +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable /* ~This project is licensed under the open source MPL V2. @@ -26,7 +27,7 @@ class LoanAccountSummaryFragment : BaseFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (arguments != null) { - loanWithAssociations = arguments?.getParcelable(Constants.LOAN_ACCOUNT) + loanWithAssociations = arguments?.getCheckedParcelable(LoanWithAssociations::class.java, Constants.LOAN_ACCOUNT) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountTransactionFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountTransactionFragment.kt index e4096c48f..8b7cdfd48 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountTransactionFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountTransactionFragment.kt @@ -24,6 +24,7 @@ import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.LoanUiState import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.viewModels.LoanAccountTransactionViewModel import javax.inject.Inject @@ -78,8 +79,12 @@ class LoanAccountTransactionFragment : BaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { - showLoanTransactions(savedInstanceState.getParcelable(Constants.LOAN_ACCOUNT) as LoanWithAssociations) - } + showLoanTransactions( + savedInstanceState.getCheckedParcelable( + LoanWithAssociations::class.java, + Constants.LOAN_ACCOUNT + ) + ) } } /** diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountWithdrawFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountWithdrawFragment.kt index 672e86550..ee04917d0 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountWithdrawFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountWithdrawFragment.kt @@ -18,6 +18,7 @@ import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.DateHelper import org.mifos.mobile.utils.LoanUiState +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.Toaster import org.mifos.mobile.viewModels.LoanAccountWithdrawViewModel @@ -36,7 +37,7 @@ class LoanAccountWithdrawFragment : BaseFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (arguments != null) { - loanWithAssociations = arguments?.getParcelable(Constants.LOAN_ACCOUNT) + loanWithAssociations = arguments?.getCheckedParcelable(LoanWithAssociations::class.java, Constants.LOAN_ACCOUNT) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountsDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountsDetailFragment.kt index ed2a8c9d6..9fcdcdd26 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountsDetailFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanAccountsDetailFragment.kt @@ -21,6 +21,7 @@ import org.mifos.mobile.ui.enums.ChargeType import org.mifos.mobile.ui.enums.LoanState import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.* +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.viewModels.LoanAccountsDetailViewModel import javax.inject.Inject @@ -78,7 +79,7 @@ class LoanAccountsDetailFragment : BaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { - showLoanAccountsDetail(savedInstanceState.getParcelable(Constants.LOAN_ACCOUNT) as LoanWithAssociations) + showLoanAccountsDetail(savedInstanceState.getCheckedParcelable(LoanWithAssociations::class.java, Constants.LOAN_ACCOUNT)) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanApplicationFragment.kt index 0a8cfb0a2..9dead7b45 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanApplicationFragment.kt @@ -24,6 +24,8 @@ import org.mifos.mobile.ui.enums.LoanState import org.mifos.mobile.ui.fragments.ReviewLoanApplicationFragment.Companion.newInstance import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.* +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedSerializable import org.mifos.mobile.viewModels.LoanApplicationViewModel import java.text.SimpleDateFormat import java.time.Instant @@ -99,12 +101,18 @@ class LoanApplicationFragment : BaseFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (arguments != null) { - loanState = arguments?.getSerializable(Constants.LOAN_STATE) as LoanState + loanState = arguments?.getCheckedSerializable( + LoanState::class.java, + Constants.LOAN_STATE + ) as LoanState if (loanState == LoanState.CREATE) { setToolbarTitle(getString(R.string.apply_for_loan)) } else { setToolbarTitle(getString(R.string.update_loan)) - loanWithAssociations = arguments?.getParcelable(Constants.LOAN_ACCOUNT) + loanWithAssociations = arguments?.getCheckedParcelable( + LoanWithAssociations::class.java, + Constants.LOAN_ACCOUNT + ) } } } @@ -131,7 +139,10 @@ class LoanApplicationFragment : BaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { - val template: LoanTemplate? = savedInstanceState.getParcelable(Constants.TEMPLATE) + val template: LoanTemplate? = savedInstanceState.getCheckedParcelable( + LoanTemplate::class.java, + Constants.TEMPLATE + ) if (loanState == LoanState.CREATE) { showLoanTemplate(template) } else { diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanRepaymentScheduleFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanRepaymentScheduleFragment.kt index 64c61abfa..e4d095326 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/LoanRepaymentScheduleFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/LoanRepaymentScheduleFragment.kt @@ -27,6 +27,7 @@ import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.DateHelper import org.mifos.mobile.utils.LoanUiState import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.viewModels.LoanRepaymentScheduleViewModel import javax.inject.Inject @@ -106,7 +107,12 @@ class LoanRepaymentScheduleFragment : BaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { - showLoanRepaymentSchedule(savedInstanceState.getParcelable(Constants.LOAN_ACCOUNT) as LoanWithAssociations) + showLoanRepaymentSchedule( + savedInstanceState.getCheckedParcelable( + LoanWithAssociations::class.java, + Constants.LOAN_ACCOUNT + ) + ) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeDisplayFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeDisplayFragment.kt index a8f2d966b..e3b7bf290 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeDisplayFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeDisplayFragment.kt @@ -12,6 +12,7 @@ import android.view.ViewGroup import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentQrCodeDisplayBinding +import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.QrCodeGenerator @@ -29,6 +30,7 @@ class QrCodeDisplayFragment : BaseFragment() { private var json: String? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + (activity as? SavingsAccountContainerActivity)?.showToolbar() if (arguments != null) { json = arguments?.getString(Constants.QR_DATA) } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt index cd8472f80..696f8e683 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt @@ -26,6 +26,7 @@ import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.enums.BeneficiaryState import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.QrCodeUiState import org.mifos.mobile.utils.Toaster import org.mifos.mobile.viewModels.QrCodeImportViewModel @@ -120,8 +121,8 @@ class QrCodeImportFragment : BaseFragment() { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { // restore data - mFrameRect = savedInstanceState.getParcelable(Constants.FRAME_RECT) - qrUri = savedInstanceState.getParcelable(Constants.SOURCE_URI)!! + mFrameRect = savedInstanceState.getCheckedParcelable(RectF::class.java, Constants.FRAME_RECT) + qrUri = savedInstanceState.getCheckedParcelable(Uri::class.java, Constants.SOURCE_URI)!! } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/RecentTransactionsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/RecentTransactionsFragment.kt index 7f98534f0..dae06d6cb 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/RecentTransactionsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/RecentTransactionsFragment.kt @@ -25,6 +25,7 @@ import org.mifos.mobile.ui.adapters.RecentTransactionListAdapter import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.* import org.mifos.mobile.utils.Network.isConnected +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedArrayListFromParcelable import org.mifos.mobile.viewModels.RecentTransactionViewModel import javax.inject.Inject @@ -116,7 +117,10 @@ class RecentTransactionsFragment : BaseFragment(), OnRefreshListener { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { val transactions: List = - savedInstanceState.getParcelableArrayList(Constants.RECENT_TRANSACTIONS) ?: listOf() + savedInstanceState.getCheckedArrayListFromParcelable( + Transaction::class.java, + Constants.RECENT_TRANSACTIONS, + ) ?: listOf() showRecentTransactions(transactions) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/ReviewLoanApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/ReviewLoanApplicationFragment.kt index 668c6729a..b32cbd441 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/ReviewLoanApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/ReviewLoanApplicationFragment.kt @@ -17,6 +17,8 @@ import org.mifos.mobile.ui.enums.LoanState import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.MFErrorParser import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedSerializable import org.mifos.mobile.utils.ReviewLoanApplicationUiState import org.mifos.mobile.utils.Toaster import org.mifos.mobile.viewModels.ReviewLoanApplicationViewModel @@ -80,11 +82,11 @@ class ReviewLoanApplicationFragment : BaseFragment() { savedInstanceState: Bundle?, ): View { _binding = FragmentReviewLoanApplicationBinding.inflate(inflater, container, false) - val loanState = arguments?.getSerializable(LOAN_STATE) as LoanState + val loanState = arguments?.getCheckedSerializable(LoanState::class.java, LOAN_STATE) as LoanState if (loanState == LoanState.CREATE) { viewModel.insertData( loanState, - arguments?.getParcelable(LOANS_PAYLOAD)!!, + arguments?.getCheckedParcelable(LoansPayload::class.java, LOANS_PAYLOAD)!!, arguments?.getString(LOAN_NAME)!!, arguments?.getString(ACCOUNT_NO)!!, ) @@ -92,7 +94,7 @@ class ReviewLoanApplicationFragment : BaseFragment() { viewModel.insertData( loanState, arguments?.getLong(LOAN_ID)!!, - arguments?.getParcelable(LOANS_PAYLOAD)!!, + arguments?.getCheckedParcelable(LoansPayload::class.java, LOANS_PAYLOAD)!!, arguments?.getString(LOAN_NAME)!!, arguments?.getString(ACCOUNT_NO)!!, ) diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsDetailFragment.kt deleted file mode 100644 index 08a8d1a4b..000000000 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsDetailFragment.kt +++ /dev/null @@ -1,467 +0,0 @@ -package org.mifos.mobile.ui.fragments - -import android.content.Intent -import android.net.Uri -import android.os.Bundle -import android.os.Parcelable -import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.viewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import org.mifos.mobile.R -import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.databinding.FragmentSavingAccountDetailsBinding -import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations -import org.mifos.mobile.models.accounts.savings.Status -import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.AccountType -import org.mifos.mobile.ui.enums.ChargeType -import org.mifos.mobile.ui.enums.SavingsAccountState -import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.CurrencyUtil -import org.mifos.mobile.utils.DateHelper -import org.mifos.mobile.utils.Network -import org.mifos.mobile.utils.QrCodeGenerator -import org.mifos.mobile.utils.SavingsAccountUiState -import org.mifos.mobile.utils.SymbolsUtils -import org.mifos.mobile.utils.Toaster -import org.mifos.mobile.utils.Utils -import org.mifos.mobile.viewModels.SavingAccountsDetailViewModel -import javax.inject.Inject - -/** - * @author Vishwajeet - * @since 18/8/16. - */ -@AndroidEntryPoint -class SavingAccountsDetailFragment : BaseFragment() { - - private var _binding: FragmentSavingAccountDetailsBinding? = null - private val binding get() = _binding!! - - @JvmField - @Inject - var preferencesHelper: PreferencesHelper? = null - private val viewModel: SavingAccountsDetailViewModel by viewModels() - private var savingsId: Long? = 0 - private var status: Status? = null - private var savingsWithAssociations: SavingsWithAssociations? = null - private var sweetUIErrorHandler: SweetUIErrorHandler? = null - private var isMenuVisible: Boolean? = false - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - if (arguments != null) { - savingsId = arguments?.getLong(Constants.SAVINGS_ID) - } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = FragmentSavingAccountDetailsBinding.inflate(inflater, container, false) - setToolbarTitle(getString(R.string.saving_account_details)) - sweetUIErrorHandler = SweetUIErrorHandler(context, binding.root) - if (savedInstanceState == null && this.savingsWithAssociations == null) { - viewModel.loadSavingsWithAssociations(savingsId) - } else { - showSavingAccountsDetail(this.savingsWithAssociations) - } - setHasOptionsMenu(true) - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - with(binding) { - tvHelpLineNumber.setOnClickListener { - dialHelpLineNumber() - } - - tvDeposit.setOnClickListener { - deposit() - } - - tvMakeATransfer.setOnClickListener { - transfer() - } - - layoutError.btnTryAgain.setOnClickListener { - onRetry() - } - - llSavingsTransactions.setOnClickListener { - transactionsClicked() - } - - llSavingsCharges.setOnClickListener { - chargeClicked() - } - - llSavingsQrCode.setOnClickListener { - qrCodeClicked() - } - } - - viewLifecycleOwner.lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.savingAccountsDetailUiState.collect { state -> - when (state) { - SavingsAccountUiState.Loading -> showProgress() - - SavingsAccountUiState.Error -> { - hideProgress() - showErrorFetchingSavingAccountsDetail( - context?.getString(R.string.error_saving_account_details_loading), - ) - } - - is SavingsAccountUiState.SuccessLoadingSavingsWithAssociations -> { - hideProgress() - showSavingAccountsDetail(state.savingAccount) - } - - is SavingsAccountUiState.Initial -> {} - - else -> throw IllegalStateException("Unexpected State: $state") - } - } - } - } - - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putParcelable(Constants.SAVINGS_ACCOUNTS, savingsWithAssociations) - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - if (savedInstanceState != null) { - showSavingAccountsDetail(savedInstanceState.getParcelable(Constants.SAVINGS_ACCOUNTS) as SavingsWithAssociations) - } - } - - /** - * Opens up Phone Dialer - */ - private fun dialHelpLineNumber() { - val intent = Intent(Intent.ACTION_DIAL) - intent.data = Uri.parse("tel:" + getString(R.string.help_line_number)) - startActivity(intent) - } - - /** - * Opens [SavingsMakeTransferFragment] if status is ACTIVE else shows a - * {@link Snackbar} that Account should be Active - */ - fun deposit() { - if (status?.active == true) { - (activity as BaseActivity?)?.replaceFragment( - SavingsMakeTransferFragment.newInstance( - savingsId, - Constants.TRANSFER_PAY_TO, - ), - true, - R.id.container, - ) - } else { - Toaster.show(binding.root, getString(R.string.account_not_active_to_perform_deposit)) - } - } - - /** - * Opens [SavingsMakeTransferFragment] if status is ACTIVE else shows a - * {@link Snackbar} that Account should be Active - */ - fun transfer() { - if (status?.active == true) { - (activity as BaseActivity?)?.replaceFragment( - SavingsMakeTransferFragment.newInstance( - savingsId, - Constants.TRANSFER_PAY_FROM, - ), - true, - R.id.container, - ) - } else { - Toaster.show(binding.root, getString(R.string.account_not_active_to_perform_transfer)) - } - } - - /** - * Sets Saving account basic info fetched from the server - * - * @param savingsWithAssociations object containing details of a saving account - */ - private fun showSavingAccountsDetail(savingsWithAssociations: SavingsWithAssociations?) { - if (savingsWithAssociations?.status?.submittedAndPendingApproval == true) { - sweetUIErrorHandler?.showSweetCustomErrorUI( - getString(R.string.approval_pending), - R.drawable.ic_assignment_turned_in_black_24dp, - binding.llAccount, - binding.layoutError.root, - ) - isMenuVisible = (savingsWithAssociations.status?.submittedAndPendingApproval == true) - } else { - binding.llAccount.visibility = View.VISIBLE - val currencySymbol = savingsWithAssociations?.currency?.displaySymbol - val accountBalance = savingsWithAssociations?.summary?.accountBalance - binding.tvAccountStatus.text = savingsWithAssociations?.clientName - if (savingsWithAssociations?.minRequiredOpeningBalance != null) { - binding.tvMinReqBal.text = getString( - R.string.string_and_string, - currencySymbol, - CurrencyUtil.formatCurrency( - activity, - savingsWithAssociations.minRequiredOpeningBalance!!, - ), - ) - } else { - binding.tvMinRequiredBalance.visibility = View.GONE - binding.tvMinReqBal.visibility = View.GONE - } - if (savingsWithAssociations?.summary?.totalWithdrawals != null) { - binding.tvTotalWithdrawals.text = getString( - R.string.string_and_string, - currencySymbol, - CurrencyUtil.formatCurrency( - activity, - savingsWithAssociations.summary?.totalWithdrawals!!, - ), - ) - } else { - binding.tvTotalWithdrawals.setText(R.string.no_withdrawals) - } - binding.tvAccBalance.text = getString( - R.string.string_and_string, - currencySymbol, - CurrencyUtil.formatCurrency(activity, accountBalance!!), - ) - binding.tvNominalInterestRate.text = getString( - R.string.double_and_string, - savingsWithAssociations.getNominalAnnualInterestRate(), - SymbolsUtils.PERCENT, - ) - binding.tvSavingAccountNumber.text = savingsWithAssociations.accountNo.toString() - if (savingsWithAssociations.summary?.totalDeposits != null) { - binding.tvTotalDeposits.text = getString( - R.string.string_and_string, - currencySymbol, - CurrencyUtil.formatCurrency( - activity, - savingsWithAssociations.summary?.totalDeposits!!, - ), - ) - } else { - binding.tvTotalDeposits.text = getString(R.string.not_available) - } - if (savingsWithAssociations.transactions.isNotEmpty()) { - binding.tvLastTransaction.text = getString( - R.string.string_and_double, - currencySymbol, - savingsWithAssociations.transactions[0].amount, - ) - binding.tvMadeOn.text = DateHelper.getDateAsString( - savingsWithAssociations.lastActiveTransactionDate, - ) - } else { - binding.tvLastTransaction.setText(R.string.no_transaction) - binding.tvMadeOn.visibility = View.GONE - binding.madeOn.visibility = View.GONE - } - showAccountStatus(savingsWithAssociations) - } - this.savingsWithAssociations = savingsWithAssociations - activity?.invalidateOptionsMenu() - showAccountStatus(savingsWithAssociations) - } - - /** - * It is called whenever any error occurs while executing a request - * - * @param message Error message that tells the user about the problem. - */ - private fun showErrorFetchingSavingAccountsDetail(message: String?) { - if (!Network.isConnected(context)) { - sweetUIErrorHandler?.showSweetNoInternetUI(binding.llAccount, binding.layoutError.root) - Toast.makeText( - context, - getString(R.string.internet_not_connected), - Toast.LENGTH_SHORT, - ).show() - } else { - sweetUIErrorHandler?.showSweetErrorUI( - message, - binding.llAccount, - binding.layoutError.root, - ) - Toast.makeText(context, message, Toast.LENGTH_SHORT).show() - } - } - - private fun onRetry() { - if (!Network.isConnected(context)) { - Toast.makeText( - context, - getString(R.string.internet_not_connected), - Toast.LENGTH_SHORT, - ).show() - } else { - sweetUIErrorHandler?.hideSweetErrorLayoutUI(binding.llAccount, binding.layoutError.root) - viewModel.loadSavingsWithAssociations(savingsId) - } - } - - /** - * Sets the status of account i.e. `tvAccountStatus` and `ivCircularStatus` color - * according to `savingsWithAssociations` - * - * @param savingsWithAssociations object containing details of a saving account - */ - private fun showAccountStatus(savingsWithAssociations: SavingsWithAssociations?) { - status = savingsWithAssociations?.status - when { - status?.active == true -> { - binding.ivCircleStatus.setImageDrawable( - Utils.setCircularBackground(R.color.deposit_green, activity), - ) - binding.tvAccountStatus.setText(R.string.active) - } - - status?.approved == true -> { - binding.ivCircleStatus.setImageDrawable( - Utils.setCircularBackground(R.color.blue, activity), - ) - binding.tvAccountStatus.setText(R.string.need_approval) - } - - status?.submittedAndPendingApproval == true -> { - binding.ivCircleStatus.setImageDrawable( - Utils.setCircularBackground(R.color.light_yellow, activity), - ) - binding.tvAccountStatus.setText(R.string.pending) - } - - status?.matured == true -> { - binding.ivCircleStatus.setImageDrawable( - Utils.setCircularBackground(R.color.red_light, activity), - ) - binding.tvAccountStatus.setText(R.string.matured) - } - - else -> { - binding.ivCircleStatus.setImageDrawable( - Utils.setCircularBackground(R.color.black, activity), - ) - binding.tvAccountStatus.setText(R.string.closed) - } - } - activity?.invalidateOptionsMenu() - } - - fun showProgress() { - binding.llAccount.visibility = View.GONE - showProgressBar() - } - - fun hideProgress() { - binding.llAccount.visibility = View.VISIBLE - hideProgressBar() - } - - override fun onDestroyView() { - super.onDestroyView() - hideProgressBar() - _binding = null - } - - private fun transactionsClicked() { - (activity as BaseActivity?)?.replaceFragment( - SavingAccountsTransactionFragment.newInstance( - savingsId, - ), - true, - R.id.container, - ) - } - - private fun chargeClicked() { - (activity as BaseActivity?)?.replaceFragment( - ClientChargeFragment.newInstance( - savingsId, - ChargeType.SAVINGS, - ), - true, - R.id.container, - ) - } - - private fun qrCodeClicked() { - val accountDetailsInJson = QrCodeGenerator.getAccountDetailsInString( - savingsWithAssociations?.accountNo, - preferencesHelper?.officeName, - AccountType.SAVINGS, - ) - (activity as BaseActivity?)?.replaceFragment( - QrCodeDisplayFragment.newInstance( - accountDetailsInJson, - ), - true, - R.id.container, - ) - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.menu_savings_account_detail, menu) - if (isMenuVisible == true) { - menu.findItem(R.id.menu_withdraw_savings_account).isVisible = true - menu.findItem(R.id.menu_update_savings_account).isVisible = true - } - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - when (item.itemId) { - R.id.menu_withdraw_savings_account -> (activity as BaseActivity?)?.replaceFragment( - SavingsAccountWithdrawFragment.newInstance(savingsWithAssociations), - true, - R.id.container, - ) - - R.id.menu_update_savings_account -> (activity as BaseActivity?)?.replaceFragment( - SavingsAccountApplicationFragment.newInstance( - SavingsAccountState.UPDATE, - savingsWithAssociations, - ), - true, - R.id.container, - ) - } - return super.onOptionsItemSelected(item) - } - - companion object { - @JvmStatic - fun newInstance(savingsId: Long): SavingAccountsDetailFragment { - val fragment = SavingAccountsDetailFragment() - val args = Bundle() - args.putLong(Constants.SAVINGS_ID, savingsId) - fragment.arguments = args - return fragment - } - } -} diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt index 387a6b78e..c25d2d829 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt @@ -30,6 +30,7 @@ import org.mifos.mobile.databinding.FragmentSavingAccountTransactionsBinding import org.mifos.mobile.models.CheckboxStatus import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations import org.mifos.mobile.models.accounts.savings.Transactions +import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity import org.mifos.mobile.ui.adapters.CheckBoxAdapter import org.mifos.mobile.ui.adapters.SavingAccountsTransactionListAdapter import org.mifos.mobile.ui.fragments.base.BaseFragment @@ -39,6 +40,7 @@ import org.mifos.mobile.utils.DateHelper import org.mifos.mobile.utils.DatePick import org.mifos.mobile.utils.DividerItemDecoration import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.SavingsAccountUiState import org.mifos.mobile.utils.StatusUtils import org.mifos.mobile.utils.Toaster @@ -79,6 +81,7 @@ class SavingAccountsTransactionFragment : BaseFragment() { private var selectedRadioButtonId = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + (activity as? SavingsAccountContainerActivity)?.showToolbar() setHasOptionsMenu(true) setToolbarTitle(getString(R.string.saving_account_transactions_details)) if (arguments != null) savingsId = arguments?.getLong(Constants.SAVINGS_ID)!! @@ -155,8 +158,12 @@ class SavingAccountsTransactionFragment : BaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { - showSavingAccountsDetail(savedInstanceState.getParcelable(Constants.SAVINGS_ACCOUNTS) as SavingsWithAssociations) - } + showSavingAccountsDetail( + savedInstanceState.getCheckedParcelable( + SavingsWithAssociations::class.java, + Constants.SAVINGS_ACCOUNTS + ) + ) } } /** diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountApplicationFragment.kt index 475c11372..0c23f6deb 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountApplicationFragment.kt @@ -19,10 +19,13 @@ import org.mifos.mobile.models.accounts.savings.SavingsAccountUpdatePayload import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations import org.mifos.mobile.models.templates.savings.ProductOptions import org.mifos.mobile.models.templates.savings.SavingsAccountTemplate +import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity import org.mifos.mobile.ui.enums.SavingsAccountState import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.DateHelper +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedSerializable import org.mifos.mobile.utils.SavingsAccountUiState import org.mifos.mobile.utils.Toaster import org.mifos.mobile.utils.getTodayFormatted @@ -50,10 +53,16 @@ class SavingsAccountApplicationFragment : BaseFragment() { private val productIdList: MutableList = ArrayList() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + (activity as? SavingsAccountContainerActivity)?.showToolbar() if (arguments != null) { - state = requireArguments() - .getSerializable(Constants.SAVINGS_ACCOUNT_STATE) as SavingsAccountState - savingsWithAssociations = arguments?.getParcelable(Constants.SAVINGS_ACCOUNTS) + state = requireArguments().getCheckedSerializable( + SavingsAccountState::class.java, + Constants.SAVINGS_ACCOUNT_STATE + ) as SavingsAccountState + savingsWithAssociations = arguments?.getCheckedParcelable( + SavingsWithAssociations::class.java, + Constants.SAVINGS_ACCOUNTS + ) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountWithdrawFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountWithdrawFragment.kt index b1f501419..49a8725fb 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountWithdrawFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsAccountWithdrawFragment.kt @@ -14,8 +14,10 @@ import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentSavingsAccountWithdrawFragmentBinding import org.mifos.mobile.models.accounts.savings.SavingsAccountWithdrawPayload import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.SavingsAccountUiState import org.mifos.mobile.utils.Toaster import org.mifos.mobile.utils.getTodayFormatted @@ -34,9 +36,12 @@ class SavingsAccountWithdrawFragment : BaseFragment() { private var payload: SavingsAccountWithdrawPayload? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + (activity as? SavingsAccountContainerActivity)?.showToolbar() if (arguments != null) { - savingsWithAssociations = arguments?.getParcelable(Constants.SAVINGS_ACCOUNTS) - } + savingsWithAssociations = arguments?.getCheckedParcelable( + SavingsWithAssociations::class.java, + Constants.SAVINGS_ACCOUNTS + ) } } override fun onCreateView( diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsMakeTransferFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsMakeTransferFragment.kt index 06ba092a8..cba514aeb 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsMakeTransferFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/SavingsMakeTransferFragment.kt @@ -22,6 +22,7 @@ import org.mifos.mobile.databinding.FragmentSavingsMakeTransferBinding import org.mifos.mobile.models.payload.TransferPayload import org.mifos.mobile.models.templates.account.AccountOption import org.mifos.mobile.models.templates.account.AccountOptionsTemplate +import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.adapters.AccountsSpinnerAdapter import org.mifos.mobile.ui.enums.TransferType @@ -29,6 +30,7 @@ import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.DateHelper import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.SavingsAccountUiState import org.mifos.mobile.utils.Toaster import org.mifos.mobile.utils.Utils @@ -59,6 +61,7 @@ class SavingsMakeTransferFragment : BaseFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + (activity as? SavingsAccountContainerActivity)?.showToolbar() if (arguments != null) { accountId = arguments?.getLong(Constants.ACCOUNT_ID) transferType = arguments?.getString(Constants.TRANSFER_TYPE) @@ -147,8 +150,12 @@ class SavingsMakeTransferFragment : BaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { - showSavingsAccountTemplate(savedInstanceState.getParcelable(Constants.TEMPLATE) as AccountOptionsTemplate) - } + showSavingsAccountTemplate( + savedInstanceState.getCheckedParcelable( + AccountOptionsTemplate::class.java, + Constants.TEMPLATE + ) + ) } } /** diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/ThirdPartyTransferFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/ThirdPartyTransferFragment.kt index 7cce24fc7..4c8c9814f 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/ThirdPartyTransferFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/ThirdPartyTransferFragment.kt @@ -35,6 +35,8 @@ import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.DateHelper import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedArrayListFromParcelable +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.ThirdPartyTransferUiState import org.mifos.mobile.utils.Toaster import org.mifos.mobile.utils.Utils @@ -159,10 +161,17 @@ class ThirdPartyTransferFragment : BaseFragment(), OnItemSelectedListener { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { - showThirdPartyTransferTemplate(savedInstanceState.getParcelable(Constants.TEMPLATE) as AccountOptionsTemplate) - val tempBeneficiaries: List = savedInstanceState.getParcelableArrayList( - Constants.BENEFICIARY, - ) ?: listOf() + showThirdPartyTransferTemplate( + savedInstanceState.getCheckedParcelable( + AccountOptionsTemplate::class.java, + Constants.TEMPLATE + ) + ) + val tempBeneficiaries: List = + savedInstanceState.getCheckedArrayListFromParcelable( + Beneficiary::class.java, + Constants.BENEFICIARY, + ) ?: listOf() showBeneficiaryList(tempBeneficiaries) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt index 38c02cdcb..ab486839a 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt @@ -23,6 +23,8 @@ import org.mifos.mobile.utils.CurrencyUtil import org.mifos.mobile.utils.DateHelper import org.mifos.mobile.utils.MFErrorParser import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedSerializable import org.mifos.mobile.utils.Toaster import org.mifos.mobile.utils.TransferUiState import org.mifos.mobile.utils.getTodayFormatted @@ -48,8 +50,15 @@ class TransferProcessFragment : BaseFragment() { super.onCreate(savedInstanceState) if (activity != null) { payload = arguments?.getParcelable(Constants.PAYLOAD) - transferType = arguments?.getSerializable(Constants.TRANSFER_TYPE) as TransferType - } + payload = + arguments?.getCheckedParcelable( + TransferPayload::class.java, + Constants.PAYLOAD + ) + transferType = arguments?.getCheckedSerializable( + TransferType::class.java, + Constants.TRANSFER_TYPE + ) as TransferType } } override fun onCreateView( diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingAccountsDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingAccountsDetailFragment.kt new file mode 100644 index 000000000..dc32c83d7 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingAccountsDetailFragment.kt @@ -0,0 +1,213 @@ +package org.mifos.mobile.ui.savings_account + +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy +import androidx.fragment.app.viewModels +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.R +import org.mifos.mobile.api.local.PreferencesHelper +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity +import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.ui.enums.AccountType +import org.mifos.mobile.ui.enums.ChargeType +import org.mifos.mobile.ui.enums.SavingsAccountState +import org.mifos.mobile.ui.fragments.ClientChargeFragment +import org.mifos.mobile.ui.fragments.QrCodeDisplayFragment +import org.mifos.mobile.ui.fragments.SavingAccountsTransactionFragment +import org.mifos.mobile.ui.fragments.SavingsAccountApplicationFragment +import org.mifos.mobile.ui.fragments.SavingsAccountWithdrawFragment +import org.mifos.mobile.ui.fragments.SavingsMakeTransferFragment +import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.utils.Constants +import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.QrCodeGenerator +import javax.inject.Inject + +/** + * @author Vishwajeet + * @since 18/8/16. + */ +@AndroidEntryPoint +class SavingAccountsDetailFragment : BaseFragment() { + + @Inject + lateinit var preferencesHelper: PreferencesHelper + private val viewModel: SavingAccountsDetailViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (arguments != null) { + viewModel.setSavingsId(arguments?.getLong(Constants.SAVINGS_ID)) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + viewModel.loadSavingsWithAssociations(viewModel.savingsId) + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + MifosMobileTheme { + SavingsAccountDetailScreen( + uiState = viewModel.savingAccountsDetailUiState.value, + navigateBack = { activity?.finish() }, + updateSavingsAccount = { updateSavingsAccount(it) }, + withdrawSavingsAccount = { withdrawSavingsAccount(it) }, + makeTransfer = { transfer(it) }, + viewTransaction = { transactionsClicked() }, + viewCharges = { chargeClicked() }, + viewQrCode = { qrCodeClicked(it) }, + callUs = { dialHelpLineNumber() }, + deposit = { deposit(it) }, + retryConnection = { onRetry() } + ) + } + } + } + } + + override fun onResume() { + super.onResume() + (activity as? SavingsAccountContainerActivity)?.hideToolbar() + } + + /** + * Opens up Phone Dialer + */ + private fun dialHelpLineNumber() { + val intent = Intent(Intent.ACTION_DIAL) + intent.data = Uri.parse("tel:" + getString(R.string.help_line_number)) + startActivity(intent) + } + + /** + * Opens [SavingsMakeTransferFragment] if status is ACTIVE else shows a + * {@link Snackbar} that Account should be Active + */ + fun deposit(isStatusActive: Boolean) { + if (isStatusActive) { + (activity as BaseActivity?)?.replaceFragment( + SavingsMakeTransferFragment.newInstance( + viewModel.savingsId, + Constants.TRANSFER_PAY_TO, + ), + true, + R.id.container, + ) + } else { + Toast.makeText( + context, + getString(R.string.account_not_active_to_perform_deposit), + Toast.LENGTH_SHORT + ).show() + } + } + + /** + * Opens [SavingsMakeTransferFragment] if status is ACTIVE else shows a + * {@link Snackbar} that Account should be Active + */ + fun transfer(isStatusActive: Boolean) { + if (isStatusActive) { + (activity as BaseActivity?)?.replaceFragment( + SavingsMakeTransferFragment.newInstance( + viewModel.savingsId, + Constants.TRANSFER_PAY_FROM, + ), + true, + R.id.container, + ) + } else { + Toast.makeText( + context, + getString(R.string.account_not_active_to_perform_transfer), + Toast.LENGTH_SHORT + ).show() + } + } + + private fun onRetry() { + if (!Network.isConnected(context)) { + Toast.makeText( + context, + getString(R.string.internet_not_connected), + Toast.LENGTH_SHORT, + ).show() + } else { + viewModel.loadSavingsWithAssociations(viewModel.savingsId) + } + } + + private fun transactionsClicked() { + (activity as BaseActivity?)?.replaceFragment( + SavingAccountsTransactionFragment.newInstance(viewModel.savingsId), + true, + R.id.container, + ) + } + + private fun chargeClicked() { + (activity as BaseActivity?)?.replaceFragment( + ClientChargeFragment.newInstance(viewModel.savingsId, ChargeType.SAVINGS), + true, + R.id.container, + ) + } + + private fun qrCodeClicked(savingsWithAssociations: SavingsWithAssociations) { + val accountDetailsInJson = QrCodeGenerator.getAccountDetailsInString( + savingsWithAssociations.accountNo, + preferencesHelper.officeName, + AccountType.SAVINGS, + ) + (activity as BaseActivity?)?.replaceFragment( + QrCodeDisplayFragment.newInstance( + accountDetailsInJson, + ), + true, + R.id.container, + ) + } + + private fun withdrawSavingsAccount(savingsWithAssociations: SavingsWithAssociations?) { + (activity as BaseActivity?)?.replaceFragment( + SavingsAccountWithdrawFragment.newInstance(savingsWithAssociations), + true, + R.id.container, + ) + } + + private fun updateSavingsAccount(savingsWithAssociations: SavingsWithAssociations?) { + (activity as BaseActivity?)?.replaceFragment( + SavingsAccountApplicationFragment.newInstance( + SavingsAccountState.UPDATE, + savingsWithAssociations, + ), + true, + R.id.container, + ) + } + + companion object { + @JvmStatic + fun newInstance(savingsId: Long): SavingAccountsDetailFragment { + val fragment = SavingAccountsDetailFragment() + val args = Bundle() + args.putLong(Constants.SAVINGS_ID, savingsId) + fragment.arguments = args + return fragment + } + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingAccountsDetailViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingAccountsDetailViewModel.kt new file mode 100644 index 000000000..5e208e6f6 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingAccountsDetailViewModel.kt @@ -0,0 +1,75 @@ +package org.mifos.mobile.ui.savings_account + +import androidx.compose.runtime.State +import androidx.compose.runtime.mutableStateOf +import androidx.compose.ui.graphics.Color +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.launch +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.theme.Blue +import org.mifos.mobile.core.ui.theme.DepositGreen +import org.mifos.mobile.core.ui.theme.LightYellow +import org.mifos.mobile.core.ui.theme.RedLight +import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.models.accounts.savings.Status +import org.mifos.mobile.repositories.SavingsAccountRepository +import org.mifos.mobile.utils.Constants +import javax.inject.Inject + +@HiltViewModel +class SavingAccountsDetailViewModel @Inject constructor(private val savingsAccountRepositoryImp: SavingsAccountRepository) : + ViewModel() { + + private val _savingAccountsDetailUiState = + mutableStateOf(SavingsAccountDetailUiState.Loading) + val savingAccountsDetailUiState: State + get() = _savingAccountsDetailUiState + + private var _savingsId: Long? = 0 + val savingsId: Long? get() = _savingsId + + /** + * Load details of a particular saving account from the server and notify the view + * to display it. Notify the view, in case there is any error in fetching + * the details from server. + * + * @param accountId Id of Savings Account + */ + fun loadSavingsWithAssociations(accountId: Long?) { + viewModelScope.launch { + _savingAccountsDetailUiState.value = SavingsAccountDetailUiState.Loading + savingsAccountRepositoryImp.getSavingsWithAssociations( + accountId, Constants.TRANSACTIONS, + ).catch { + _savingAccountsDetailUiState.value = SavingsAccountDetailUiState.Error + }.collect { + _savingAccountsDetailUiState.value = SavingsAccountDetailUiState.Success(it) + } + } + } + + fun setSavingsId(savingsId: Long?) { + _savingsId = savingsId + } +} + +sealed class SavingsAccountDetailUiState { + data object Loading : SavingsAccountDetailUiState() + data object Error : SavingsAccountDetailUiState() + data class Success(val savingAccount: SavingsWithAssociations) : SavingsAccountDetailUiState() +} + +fun Status.getStatusColorAndText(): Pair { + return when { + this.active == true -> Pair(DepositGreen, R.string.active) + this.approved == true -> Pair(Blue, R.string.need_approval) + this.submittedAndPendingApproval == true -> Pair(LightYellow, R.string.pending) + this.matured == true -> Pair(RedLight, R.string.matured) + else -> Pair(Color.Black, R.string.closed) + } +} + + diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailContent.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailContent.kt new file mode 100644 index 000000000..a1b7cdadb --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailContent.kt @@ -0,0 +1,403 @@ +package org.mifos.mobile.ui.savings_account + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedButton +import androidx.compose.material3.OutlinedCard +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.MifosLinkText +import org.mifos.mobile.core.ui.component.MifosRoundIcon +import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.models.accounts.savings.Status +import org.mifos.mobile.utils.CurrencyUtil +import org.mifos.mobile.utils.DateHelper +import org.mifos.mobile.utils.SymbolsUtils + +@Composable +fun SavingsAccountDetailContent( + savingsAccount: SavingsWithAssociations, + deposit: (Boolean) -> Unit, + makeTransfer: (Boolean) -> Unit, + viewTransaction: () -> Unit, + viewCharges: () -> Unit, + viewQrCode: (SavingsWithAssociations) -> Unit, + callUs: () -> Unit +) { + val scrollState = rememberScrollState() + val currencySymbol = savingsAccount.currency?.displaySymbol ?: "$" + + Column( + modifier = Modifier + .fillMaxWidth() + .verticalScroll(scrollState) + .padding(16.dp) + ) { + AccountDetailsCard( + makeTransfer = makeTransfer, + deposit = deposit, + savingsAccount = savingsAccount, + currencySymbol = currencySymbol + ) + + Spacer(modifier = Modifier.height(20.dp)) + + LastTransactionCard( + savingsWithAssociations = savingsAccount, + currencySymbol = currencySymbol + ) + + Spacer(modifier = Modifier.height(20.dp)) + + SavingsMonitorComponent( + viewTransaction = viewTransaction, + viewCharges = viewCharges, + viewQrCode = { viewQrCode.invoke(savingsAccount) } + ) + + Spacer(modifier = Modifier.height(20.dp)) + + Row(verticalAlignment = Alignment.CenterVertically) { + Text( + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface, + text = stringResource(id = R.string.need_help) + ) + Spacer(modifier = Modifier.width(5.dp)) + MifosLinkText( + text = stringResource(id = R.string.help_line_number), + onClick = { callUs.invoke() }, + isUnderlined = false + ) + } + } +} + +@Composable +fun AccountDetailsCard( + modifier: Modifier = Modifier, + savingsAccount: SavingsWithAssociations, + deposit: (Boolean) -> Unit, + makeTransfer: (Boolean) -> Unit, + currencySymbol: String +) { + val context = LocalContext.current + OutlinedCard(modifier = modifier) { + Column(modifier = Modifier.padding(14.dp)) { + DetailField( + title = stringResource(id = R.string.account_balance), + description = stringResource( + id = R.string.string_and_string, + currencySymbol, + CurrencyUtil.formatCurrency( + context = context, + amt = savingsAccount.summary?.accountBalance ?: 0.0 + ) + ), + descriptionStyle = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.Bold) + ) + + Spacer(modifier = Modifier.height(8.dp)) + + StatusField( + title = stringResource(id = R.string.account_status), + accountStatus = savingsAccount.status ?: Status() + ) + + Spacer(modifier = Modifier.height(8.dp)) + + DetailField( + title = stringResource(id = R.string.account_number), + description = savingsAccount.accountNo ?: "", + descriptionStyle = MaterialTheme.typography.bodyLarge, + ) + + Spacer(modifier = Modifier.height(8.dp)) + + DetailField( + title = stringResource(id = R.string.nominal_interest_rate), + description = stringResource( + id = R.string.double_and_string, + savingsAccount.getNominalAnnualInterestRate(), + SymbolsUtils.PERCENT + ), + descriptionStyle = MaterialTheme.typography.bodyLarge + ) + + Spacer(modifier = Modifier.height(8.dp)) + + DetailField( + title = stringResource(id = R.string.total_deposits), + description = if (savingsAccount.summary?.totalDeposits != null) { + stringResource( + id = R.string.string_and_string, + currencySymbol, + CurrencyUtil.formatCurrency( + context = context, + amt = savingsAccount.summary?.totalDeposits, + ) + ) + } else { + stringResource(id = R.string.not_available) + }, + descriptionStyle = MaterialTheme.typography.bodyLarge + ) + + Spacer(modifier = Modifier.height(8.dp)) + + DetailField( + title = stringResource(id = R.string.total_withdrawal), + descriptionStyle = MaterialTheme.typography.bodyLarge, + description = if (savingsAccount.summary?.totalDeposits != null) { + stringResource( + id = R.string.string_and_string, currencySymbol, + CurrencyUtil.formatCurrency( + context = context, + amt = savingsAccount.summary?.totalWithdrawals, + ), + ) + } else { + stringResource(id = R.string.no_withdrawals) + } + ) + + Spacer(modifier = Modifier.height(8.dp)) + + Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { + OutlinedButton(onClick = { + deposit.invoke( + savingsAccount.status?.active ?: false + ) + }) { Text(text = stringResource(id = R.string.deposit)) } + + Spacer(modifier = Modifier.width(8.dp)) + + OutlinedButton(onClick = { + makeTransfer.invoke( + savingsAccount.status?.active ?: false + ) + }) { Text(text = stringResource(id = R.string.make_transfer)) } + } + } + } +} + +@Composable +fun LastTransactionCard( + savingsWithAssociations: SavingsWithAssociations, + currencySymbol: String, + modifier: Modifier = Modifier +) { + val context = LocalContext.current + val isTransactionEmpty = savingsWithAssociations.transactions.isEmpty() + + Column(modifier = modifier.fillMaxWidth()) { + Text( + text = stringResource(id = R.string.last_trans), + style = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.Bold), + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.fillMaxWidth() + ) + + Spacer(modifier = Modifier.height(8.dp)) + + OutlinedCard(modifier = Modifier.fillMaxWidth()) { + Column(modifier = Modifier.padding(14.dp)) { + DetailField( + title = stringResource(id = R.string.last_transaction), + descriptionStyle = MaterialTheme.typography.bodyLarge, + description = if (isTransactionEmpty) { + stringResource(id = R.string.no_transaction) + } else { + stringResource( + id = R.string.string_and_double, + currencySymbol, + savingsWithAssociations.transactions[0].amount ?: 0.0 + ) + } + ) + + if (!isTransactionEmpty) { + Spacer(modifier = Modifier.height(8.dp)) + DetailField( + title = stringResource(id = R.string.made_on), + descriptionStyle = MaterialTheme.typography.bodyLarge, + description = DateHelper.getDateAsString( + savingsWithAssociations.lastActiveTransactionDate, + ) + ) + } + + if (savingsWithAssociations.minRequiredOpeningBalance != null) { + Spacer(modifier = Modifier.height(8.dp)) + DetailField( + title = stringResource(id = R.string.min_required_balance), + descriptionStyle = MaterialTheme.typography.bodyLarge, + description = stringResource( + id = R.string.string_and_string, currencySymbol, + CurrencyUtil.formatCurrency( + context = context, + amt = savingsWithAssociations.minRequiredOpeningBalance, + ), + ) + ) + } + } + } + } +} + +@Composable +fun SavingsMonitorComponent( + modifier: Modifier = Modifier, + viewTransaction: () -> Unit, + viewCharges: () -> Unit, + viewQrCode: () -> Unit, +) { + Column(modifier = modifier.fillMaxWidth()) { + Text( + text = stringResource(id = R.string.monitor), + style = MaterialTheme.typography.bodyLarge.copy(fontWeight = FontWeight.Bold), + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.fillMaxWidth(), + ) + + Spacer(modifier = Modifier.height(8.dp)) + + MonitorListItemWithIcon( + titleId = R.string.transactions, + subTitleId = R.string.view_transactions, + iconId = R.drawable.ic_compare_arrows_black_24dp, + onClick = viewTransaction + ) + MonitorListItemWithIcon( + titleId = R.string.savings_charges, + subTitleId = R.string.view_charges, + iconId = R.drawable.ic_charges, + onClick = viewCharges + ) + MonitorListItemWithIcon( + titleId = R.string.qr_code, + subTitleId = R.string.view_qr_code, + iconId = R.drawable.ic_qrcode_scan, + onClick = viewQrCode + ) + } +} + +@Composable +fun MonitorListItemWithIcon( + modifier: Modifier = Modifier, + titleId: Int, + subTitleId: Int, + iconId: Int, + onClick: () -> Unit +) { + Row( + modifier = modifier + .clickable { onClick.invoke() } + .padding(8.dp), + verticalAlignment = Alignment.CenterVertically + ) { + MifosRoundIcon( + iconId = iconId, + modifier = Modifier.size(39.dp) + ) + Spacer(modifier = Modifier.width(8.dp)) + Column { + Text( + text = stringResource(id = titleId), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier.fillMaxWidth(), + ) + Text( + text = stringResource(id = subTitleId), + style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurface, + modifier = Modifier + .alpha(0.7f) + .fillMaxWidth(), + ) + } + } +} + +@Composable +fun DetailField( + title: String, + description: String, + descriptionStyle: TextStyle, +) { + Column(modifier = Modifier.fillMaxWidth()) { + Text( + text = title, + style = MaterialTheme.typography.labelMedium, + modifier = Modifier + .alpha(0.7f) + .fillMaxWidth() + ) + Text( + text = description, + style = descriptionStyle, + modifier = Modifier.fillMaxWidth() + ) + } +} + +@Composable +fun StatusField( + title: String, + accountStatus: Status +) { + val (color, textResId) = accountStatus.getStatusColorAndText() + + Column(modifier = Modifier.fillMaxWidth()) { + Text( + text = title, + style = MaterialTheme.typography.labelMedium, + modifier = Modifier + .alpha(0.7f) + .fillMaxWidth() + ) + + Row(verticalAlignment = Alignment.CenterVertically) { + Box( + modifier = Modifier + .clip(CircleShape) + .background(color = color) + .size(15.dp) + ) + Spacer(modifier = Modifier.width(4.dp)) + Text( + text = stringResource(id = textResId), + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.fillMaxWidth() + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailScreen.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailScreen.kt new file mode 100644 index 000000000..9d40a5fa2 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailScreen.kt @@ -0,0 +1,117 @@ +package org.mifos.mobile.ui.savings_account + +import android.widget.Toast +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.EmptyDataView +import org.mifos.mobile.core.ui.component.MifosProgressIndicator +import org.mifos.mobile.core.ui.component.NoInternet +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.utils.Network + +@Composable +fun SavingsAccountDetailScreen( + uiState: SavingsAccountDetailUiState, + navigateBack: () -> Unit, + updateSavingsAccount: (SavingsWithAssociations?) -> Unit, + withdrawSavingsAccount: (SavingsWithAssociations?) -> Unit, + makeTransfer: (Boolean) -> Unit, + viewTransaction: () -> Unit, + viewCharges: () -> Unit, + viewQrCode: (SavingsWithAssociations) -> Unit, + callUs: () -> Unit, + deposit: (Boolean) -> Unit, + retryConnection: () -> Unit +) { + Column { + SavingsAccountDetailTopBar( + navigateBack = navigateBack, + updateSavingsAccount = { + updateSavingsAccount.invoke( + (uiState as? SavingsAccountDetailUiState.Success)?.savingAccount + ) + }, + withdrawSavingsAccount = { + withdrawSavingsAccount.invoke( + (uiState as? SavingsAccountDetailUiState.Success)?.savingAccount + ) + }, + ) + when (uiState) { + is SavingsAccountDetailUiState.Error -> { + ErrorComponent(retryConnection = retryConnection) + } + + is SavingsAccountDetailUiState.Loading -> { + MifosProgressIndicator(modifier = Modifier.fillMaxSize()) + } + + is SavingsAccountDetailUiState.Success -> { + if (uiState.savingAccount.status?.submittedAndPendingApproval == true) { + EmptyDataView( + modifier = Modifier.fillMaxSize(), + icon = R.drawable.ic_assignment_turned_in_black_24dp, + error = R.string.approval_pending + ) + } else { + SavingsAccountDetailContent( + savingsAccount = uiState.savingAccount, + makeTransfer = makeTransfer, + viewCharges = viewCharges, + viewTransaction = viewTransaction, + viewQrCode = viewQrCode, + callUs = callUs, + deposit = deposit + ) + } + } + } + } +} + +@Composable +fun ErrorComponent( + retryConnection: () -> Unit +) { + val context = LocalContext.current + if (!Network.isConnected(context)) { + NoInternet( + icon = R.drawable.ic_portable_wifi_off_black_24dp, + error = R.string.no_internet_connection, + isRetryEnabled = true, + retry = retryConnection + ) + Toast.makeText( + context, stringResource(R.string.internet_not_connected), Toast.LENGTH_SHORT, + ).show() + } else { + EmptyDataView( + icon = R.drawable.ic_error_black_24dp, + error = R.string.error_saving_account_details_loading + ) + Toast.makeText( + context, + stringResource(id = R.string.error_saving_account_details_loading), + Toast.LENGTH_SHORT + ).show() + } +} + + +@Preview(showSystemUi = true) +@Composable +fun SavingsAccountDetailScreenPreview() { + MifosMobileTheme { + SavingsAccountDetailScreen( + uiState = SavingsAccountDetailUiState.Loading, + {}, {}, {}, {}, {}, {}, {}, {}, {}, {} + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailTopBar.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailTopBar.kt new file mode 100644 index 000000000..47d3ba87d --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account/SavingsAccountDetailTopBar.kt @@ -0,0 +1,89 @@ +package org.mifos.mobile.ui.savings_account + +import androidx.compose.foundation.background +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.MoreVert +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.theme.MifosMobileTheme + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SavingsAccountDetailTopBar( + navigateBack: () -> Unit, + updateSavingsAccount: () -> Unit, + withdrawSavingsAccount: () -> Unit +) { + var showMenu by remember { mutableStateOf(false) } + + TopAppBar( + modifier = Modifier, + title = { Text(text = stringResource(id = R.string.saving_account_details)) }, + navigationIcon = { + IconButton( + onClick = { navigateBack.invoke() } + ) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = "Back Arrow", + tint = MaterialTheme.colorScheme.onSurface + ) + } + }, + colors = TopAppBarDefaults.topAppBarColors( + containerColor = MaterialTheme.colorScheme.background + ), + actions = { + IconButton(onClick = { showMenu = !showMenu }) { + Icon( + imageVector = Icons.Filled.MoreVert, + contentDescription = "Menu", + tint = MaterialTheme.colorScheme.onSurface + ) + } + + DropdownMenu( + expanded = showMenu, + onDismissRequest = { showMenu = false } + ) { + DropdownMenuItem( + text = { + Text(text = stringResource(id = R.string.update_savings_account)) + }, + onClick = { updateSavingsAccount.invoke() } + ) + DropdownMenuItem( + text = { + Text(text = stringResource(id = R.string.withdraw_savings_account)) + }, + onClick = { withdrawSavingsAccount.invoke() } + ) + } + } + ) +} + +@Preview +@Composable +fun SavingsAccountDetailTopBarPreview() { + MifosMobileTheme { + SavingsAccountDetailTopBar({}, {}, {}) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/user_profile/UserProfileFragment.kt b/app/src/main/java/org/mifos/mobile/ui/user_profile/UserProfileFragment.kt index 0ed1aa942..fdbd4d37b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/user_profile/UserProfileFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/user_profile/UserProfileFragment.kt @@ -27,6 +27,7 @@ import org.mifos.mobile.ui.getThemeAttributeColor import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.DateHelper import org.mifos.mobile.utils.Network +import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.TextDrawable import org.mifos.mobile.utils.Toaster import org.mifos.mobile.utils.UserDetailUiState @@ -116,7 +117,10 @@ class UserProfileFragment : BaseFragment() { override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { - client = savedInstanceState.getParcelable(Constants.USER_DETAILS) + client = savedInstanceState.getCheckedParcelable( + Client::class.java, + Constants.USER_DETAILS + ) viewModel.setUserProfile(preferencesHelper?.userProfileImage) showUserDetails(client) } diff --git a/app/src/main/java/org/mifos/mobile/utils/ParcelableAndSerializableUtils.kt b/app/src/main/java/org/mifos/mobile/utils/ParcelableAndSerializableUtils.kt new file mode 100644 index 000000000..13420ed0d --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/utils/ParcelableAndSerializableUtils.kt @@ -0,0 +1,32 @@ +package org.mifos.mobile.utils + +import android.os.Build +import android.os.Bundle +import java.io.Serializable + +object ParcelableAndSerializableUtils { + + fun Bundle.getCheckedArrayListFromParcelable(classType: Class, key: String): List? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.getParcelableArrayList(key, classType) + } else { + this.getParcelableArrayList(key) + } + } + + fun Bundle.getCheckedParcelable(classType: Class, key: String): T? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.getParcelable(key, classType) + } else { + this.getParcelable(key) + } + } + + fun Bundle.getCheckedSerializable(classType: Class, key: String): Any? { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + this.getSerializable(key, classType) + } else { + this.getSerializable(key) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/SavingAccountsDetailViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/SavingAccountsDetailViewModel.kt deleted file mode 100644 index 765df430d..000000000 --- a/app/src/main/java/org/mifos/mobile/viewModels/SavingAccountsDetailViewModel.kt +++ /dev/null @@ -1,44 +0,0 @@ -package org.mifos.mobile.viewModels - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import dagger.hilt.android.lifecycle.HiltViewModel -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.launch -import org.mifos.mobile.repositories.SavingsAccountRepository -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.SavingsAccountUiState -import javax.inject.Inject - -@HiltViewModel -class SavingAccountsDetailViewModel @Inject constructor(private val savingsAccountRepositoryImp: SavingsAccountRepository) : - ViewModel() { - - private val _savingAccountsDetailUiState = - MutableStateFlow(SavingsAccountUiState.Initial) - val savingAccountsDetailUiState: StateFlow get() = _savingAccountsDetailUiState - - /** - * Load details of a particular saving account from the server and notify the view - * to display it. Notify the view, in case there is any error in fetching - * the details from server. - * - * @param accountId Id of Savings Account - */ - fun loadSavingsWithAssociations(accountId: Long?) { - viewModelScope.launch { - _savingAccountsDetailUiState.value = SavingsAccountUiState.Loading - savingsAccountRepositoryImp.getSavingsWithAssociations( - accountId, - Constants.TRANSACTIONS, - ).catch { - _savingAccountsDetailUiState.value = SavingsAccountUiState.Error - }.collect { - _savingAccountsDetailUiState.value = - SavingsAccountUiState.SuccessLoadingSavingsWithAssociations(it) - } - } - } -} \ No newline at end of file diff --git a/app/src/test/java/org/mifos/mobile/viewModels/SavingAccountsDetailViewModelTest.kt b/app/src/test/java/org/mifos/mobile/viewModels/SavingAccountsDetailViewModelTest.kt index 934384797..f04a22ad1 100644 --- a/app/src/test/java/org/mifos/mobile/viewModels/SavingAccountsDetailViewModelTest.kt +++ b/app/src/test/java/org/mifos/mobile/viewModels/SavingAccountsDetailViewModelTest.kt @@ -13,6 +13,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mifos.mobile.FakeRemoteDataSource import org.mifos.mobile.repositories.SavingsAccountRepository +import org.mifos.mobile.ui.savings_account.SavingAccountsDetailViewModel import org.mifos.mobile.util.RxSchedulersOverrideRule import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.SavingsAccountUiState diff --git a/ui/src/main/java/org/mifos/mobile/core/ui/component/EmptyDataView.kt b/ui/src/main/java/org/mifos/mobile/core/ui/component/EmptyDataView.kt index 9c89c407b..d8a81b54b 100644 --- a/ui/src/main/java/org/mifos/mobile/core/ui/component/EmptyDataView.kt +++ b/ui/src/main/java/org/mifos/mobile/core/ui/component/EmptyDataView.kt @@ -1,6 +1,5 @@ package org.mifos.mobile.core.ui.component -import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.padding @@ -11,10 +10,10 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -41,7 +40,8 @@ fun EmptyDataView( Text( text = stringResource(id = error), style = TextStyle(fontSize = 20.sp), - color = MaterialTheme.colorScheme.onSecondary + color = MaterialTheme.colorScheme.onSecondary, + textAlign = TextAlign.Center ) } } \ No newline at end of file diff --git a/ui/src/main/java/org/mifos/mobile/core/ui/component/MifosRoundIcon.kt b/ui/src/main/java/org/mifos/mobile/core/ui/component/MifosRoundIcon.kt new file mode 100644 index 000000000..7ab3d7a7a --- /dev/null +++ b/ui/src/main/java/org/mifos/mobile/core/ui/component/MifosRoundIcon.kt @@ -0,0 +1,31 @@ +package org.mifos.mobile.core.ui.component + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp + +@Composable +fun MifosRoundIcon( + iconId: Int, + contentDescription: String? = null, + modifier: Modifier = Modifier +) { + Surface( + color = MaterialTheme.colorScheme.surfaceVariant, + modifier = modifier + .clip(CircleShape) + ) { + Image( + modifier = Modifier.padding(all = 6.dp), + painter = painterResource(id = iconId), + contentDescription = contentDescription + ) + } +} \ No newline at end of file diff --git a/ui/src/main/java/org/mifos/mobile/core/ui/component/NoInternet.kt b/ui/src/main/java/org/mifos/mobile/core/ui/component/NoInternet.kt index 0e048fd9a..7de06c1f2 100644 --- a/ui/src/main/java/org/mifos/mobile/core/ui/component/NoInternet.kt +++ b/ui/src/main/java/org/mifos/mobile/core/ui/component/NoInternet.kt @@ -1,22 +1,29 @@ package org.mifos.mobile.core.ui.component -import androidx.compose.foundation.isSystemInDarkTheme +import android.content.res.Configuration import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.AccessTime +import androidx.compose.material3.FilledTonalButton import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import org.mifos.mobile.core.ui.theme.MifosMobileTheme /** * @author pratyush @@ -26,7 +33,9 @@ import androidx.compose.ui.unit.sp @Composable fun NoInternet( icon: Int, - error: Int + error: Int, + isRetryEnabled: Boolean = true, + retry: () -> Unit = {} ) { Column( modifier = Modifier.fillMaxSize(), @@ -39,13 +48,20 @@ fun NoInternet( .padding(bottom = 12.dp), painter = painterResource(id = icon), contentDescription = null, - tint = if (isSystemInDarkTheme()) Color.White else Color.Black + tint = MaterialTheme.colorScheme.onSecondary ) Text( text = stringResource(id = error), style = TextStyle(fontSize = 20.sp), - color = if (isSystemInDarkTheme()) Color.White else Color.Black + color = MaterialTheme.colorScheme.onSecondary ) + + Spacer(modifier = Modifier.height(12.dp)) + if(isRetryEnabled) { + FilledTonalButton(onClick = { retry.invoke() }) { + Text(text = "Retry") + } + } } } \ No newline at end of file diff --git a/ui/src/main/java/org/mifos/mobile/core/ui/theme/Color.kt b/ui/src/main/java/org/mifos/mobile/core/ui/theme/Color.kt index c56cff0fa..bb84ed304 100644 --- a/ui/src/main/java/org/mifos/mobile/core/ui/theme/Color.kt +++ b/ui/src/main/java/org/mifos/mobile/core/ui/theme/Color.kt @@ -13,4 +13,9 @@ val BackgroundDark = Color(0xFF1B1B1F) val RedErrorDark = Color(0xFFB00020) val LightPrimary = Color(0xFF325ca8) -val DarkPrimary = Color(0xFF9bb1e3) \ No newline at end of file +val DarkPrimary = Color(0xFF9bb1e3) + +val DepositGreen = Color(0xff14c416) +val Blue = Color(0xFF003FFF) +val RedLight = Color(0xFFFF4444) +val LightYellow = Color(0xFFF9AC06) \ No newline at end of file