From cbc8d5af14ff1999adc8c7a5301ad962d1201151 Mon Sep 17 00:00:00 2001 From: Saifuddin Adenwala Date: Sat, 15 Jun 2024 00:31:23 +0530 Subject: [PATCH] A migrate transfer process screen to compose screen #2583 (#2585) refactor: qr code display migration (#2609) Migrate Beneficiary List from XML to compose (#2607) "Added MIfos Logo to RegistrationScreen" (#2613) * Added Image to RegistrationScreen * "Added Image to RegistrationScreen" Bug: Resolved Swipe Refresh Not Working in RecentTransaction Screen Compose (#2617) * "Resolved Swipe Refresh Not Working" * Resolved Swipe Refresh Not Working * Centered the Swipe Refresh And Added Padding migrate saving accounts transaction screen to compose #2588 (#2596) * migrate saving accounts transaction screen to compose #2588 * Update SavingAccountsTransactionTopBar.kt * init * init * refactor: savings accounts screen migration * refactor: savings accounts screen migration --------- Co-authored-by: Avneet Singh fix#2615 Missing TopAppBar navigation back implementation in AddBeneficiaryScreen (#2616) fix#2610: Scrolling Disabled in TransferProcessFragment (#2611) fix#2610: Scrolling Disabled in TransferProcessFragment fix#2610: Scrolling Disabled in TransferProcessFragment Beneficiary application (#2618) Settings screen migration (#2619) refactor: Registration Module --- app/build.gradle.kts | 23 + .../org/mifos/mobile/api/ObserveUiState.kt | 16 - app/src/main/AndroidManifest.xml | 21 +- .../org/mifos/mobile/MifosSelfServiceApp.kt | 8 +- .../org/mifos/mobile/di/ApplicationModule.kt | 32 +- .../models/AccountOptionAndBeneficiary.kt | 13 - .../models/accounts/loan/tableview/Cell.kt | 3 - .../accounts/loan/tableview/ColumnHeader.kt | 3 - .../accounts/loan/tableview/RowHeader.kt | 3 - .../mifos/mobile/ui/about/AboutUsActivity.kt | 1 - .../mifos/mobile/ui/about/AboutUsFragment.kt | 9 +- .../mifos/mobile/ui/about/AboutUsScreen.kt | 2 +- .../mifos/mobile/ui/about/AboutUsViewModel.kt | 6 +- .../AccountsFragment.kt | 7 +- .../mifos/mobile/ui/account/AccountsScreen.kt | 244 +++++ .../account}/AccountsViewModel.kt | 189 +++- .../mobile/ui/account/LoanAccountContent.kt | 180 ++++ .../ui/account/SavingsAccountContent.kt | 172 ++++ .../mobile/ui/account/ShareAccountContent.kt | 151 +++ .../ui/activities/BiometricAuthentication.kt | 2 +- .../mobile/ui/activities/HomeActivity.kt | 36 +- .../LoanAccountContainerActivity.kt | 4 +- .../ui/activities/LoanApplicationActivity.kt | 2 +- .../mobile/ui/activities/PassCodeActivity.kt | 8 +- .../SavingsAccountApplicationActivity.kt | 2 +- .../SavingsAccountContainerActivity.kt | 3 +- .../mobile/ui/activities/SplashActivity.kt | 2 +- .../mobile/ui/activities/base/BaseActivity.kt | 2 +- .../ui/adapters/AccountsSpinnerAdapter.kt | 3 +- .../ui/adapters/BeneficiaryListAdapter.kt | 2 +- .../ui/adapters/BeneficiarySpinnerAdapter.kt | 2 +- .../mobile/ui/adapters/CheckBoxAdapter.kt | 2 +- .../mobile/ui/adapters/ClientChargeAdapter.kt | 6 +- .../mobile/ui/adapters/ClientListAdapter.kt | 2 +- .../ui/adapters/GuarantorListAdapter.kt | 4 +- .../ui/adapters/LoanAccountsListAdapter.kt | 6 +- .../adapters/LoanRepaymentScheduleAdapter.kt | 12 +- .../mobile/ui/adapters/NotificationAdapter.kt | 6 +- .../adapters/RecentTransactionListAdapter.kt | 12 +- .../ui/adapters/SavingAccountsListAdapter.kt | 6 +- .../SavingAccountsTransactionListAdapter.kt | 8 +- .../ui/adapters/ShareAccountsListAdapter.kt | 2 +- .../BeneficiaryAddOptionsFragment.kt | 146 +-- .../presentation/BeneficiaryScreen.kt | 83 -- .../BeneficiaryApplicationComposeFragment.kt | 70 ++ .../BeneficiaryDetailFragment.kt | 12 +- .../BeneficiaryListComposeFragment.kt | 63 ++ .../ClientAccountFilterDialog.kt | 124 +++ .../ClientAccountScreenTopBar.kt | 122 +++ .../ClientAccountsComposeFragment.kt | 77 ++ .../ClientAccountsFragment.kt | 9 +- .../client_accounts/ClientAccountsScreen.kt | 250 +++++ .../ClientChargeComposeFragment.kt | 6 +- .../ui/client_charge/ClientChargeFragment.kt | 26 - .../ui/client_charge/ClientChargeScreen.kt | 8 +- .../ui/client_charge/ClientChargeViewModel.kt | 17 +- .../BeneficiaryApplicationFragment.kt | 380 -------- .../ui/fragments/BeneficiaryListFragment.kt | 272 ------ .../ui/fragments/QrCodeReaderFragment.kt | 134 --- .../mobile/ui/fragments/base/BaseFragment.kt | 4 +- .../guarantor/navigation/GuarantorScreen.kt | 39 - .../org/mifos/mobile/ui/help/HelpActivity.kt | 1 - .../org/mifos/mobile/ui/help/HelpFragment.kt | 2 +- .../org/mifos/mobile/ui/help/HelpScreen.kt | 2 +- .../org/mifos/mobile/ui/help/HelpViewModel.kt | 2 +- .../org/mifos/mobile/ui/home/HomeContent.kt | 2 +- .../mifos/mobile/ui/home/HomeOldFragment.kt | 17 +- .../org/mifos/mobile/ui/home/HomeViewModel.kt | 8 +- .../LoanAccountsDetailFragment.kt | 24 +- .../LoanApplicationFragment.kt | 40 +- .../LoanAccountSummaryFragment.kt | 11 +- .../LoanAccountTransactionFragment.kt | 4 +- .../LoanAccountWithdrawFragment.kt | 19 +- .../LoanRepaymentScheduleFragment.kt | 3 +- .../ReviewLoanApplicationFragment.kt | 10 +- .../mifos/mobile/ui/login/LoginActivity.kt | 5 +- .../mifos/mobile/ui/login/LoginViewModel.kt | 4 +- .../ui/notification/NotificationFragment.kt | 17 - .../ui/notification/NotificationScreen.kt | 14 +- .../ui/notification/NotificationViewModel.kt | 5 +- .../org/mifos/mobile/ui/qr/BarcodeCamera.kt | 114 +++ .../mobile/ui/qr/QrCodeReaderFragment.kt | 66 ++ .../mifos/mobile/ui/qr/QrCodeReaderScreen.kt | 90 ++ .../QrCodeDisplayComposeFragment.kt | 48 + .../QrCodeDisplayFragment.kt | 7 +- .../ui/qr_code_display/QrCodeDisplayScreen.kt | 163 ++++ .../qr_code_display/QrCodeDisplayViewModel.kt | 63 ++ .../QrCodeImportComposeFragment.kt | 91 ++ .../ui/qr_code_import/QrCodeImportContent.kt | 161 ++++ .../QrCodeImportFragment.kt | 38 +- .../ui/qr_code_import/QrCodeImportScreen.kt | 288 ++++++ .../qr_code_import/QrCodeImportViewModel.kt | 65 ++ .../RecentTransactionScreen.kt | 128 +-- .../RecentTransactionViewModel.kt | 6 +- .../RecentTransactionsComposeFragment.kt | 2 - .../RecentTransactionsFragment.kt | 27 - .../ui/registration/RegistrationActivity.kt | 35 +- .../RegistrationComposeFragment.kt | 47 + .../ui/registration/RegistrationFragment.kt | 23 +- .../ui/registration/RegistrationScreen.kt | 276 ------ ...RegistrationVerificationComposeFragment.kt | 40 + .../RegistrationVerificationFragment.kt | 87 +- .../RegistrationVerificationFragment_Old.kt | 106 --- .../ui/registration/RegistrationViewModel.kt | 94 -- .../SavingAccountsDetailFragment.kt | 29 +- .../SavingAccountsDetailViewModel.kt | 9 +- .../SavingsAccountDetailContent.kt | 49 +- .../SavingsAccountDetailScreen.kt | 4 +- .../SavingsAccountApplicationContent.kt | 4 +- .../SavingsAccountApplicationFragment.kt | 13 +- .../SavingsAccountApplicationScreen.kt | 6 +- .../SavingsAccountApplicationViewModel.kt | 22 +- .../SavingAccountTransactionContent.kt | 154 ++++ .../SavingAccountsTransactionFilterDialog.kt | 280 ++++++ .../SavingAccountsTransactionFragment.kt | 101 +-- .../SavingAccountsTransactionScreen.kt | 161 ++++ .../SavingAccountsTransactionViewModel.kt | 203 +++++ ...avingsAccountTransactionComposeFragment.kt | 51 ++ .../SavingsAccountWithdrawFragment.kt | 9 +- .../SavingsAccountWithdrawScreen.kt | 6 +- .../SavingsAccountWithdrawViewModel.kt | 10 +- .../SavingsMakeTransferComposeFragment.kt | 36 +- .../SavingsMakeTransferContent.kt | 6 +- .../SavingsMakeTransferFragment.kt | 856 +++++++++--------- .../SavingsMakeTransferScreen.kt | 11 +- .../SavingsMakeTransferViewModel.kt | 13 +- .../SettingsActivity.kt | 26 +- .../ui/settings/SettingsComposeFragment.kt | 89 ++ .../SettingsFragment.kt | 21 +- .../mobile/ui/settings/SettingsScreen.kt | 273 ++++++ .../mobile/ui/settings/SettingsViewModel.kt | 122 +++ .../ui/settings/UpdateEndpointDialog.kt | 100 ++ .../ThirdPartyTransferComposeFragment.kt | 12 +- .../ThirdPartyTransferContent.kt | 4 +- .../ThirdPartyTransferFragment.kt | 17 +- .../ThirdPartyTransferScreen.kt | 2 +- .../ThirdPartyTransferViewModel.kt | 18 +- .../TransferProcessComposeFragment.kt | 76 ++ .../TransferProcessFragment.kt | 36 +- .../transfer_process/TransferProcessScreen.kt | 274 ++++++ .../TransferProcessViewModel.kt | 72 ++ .../update_password/UpdatePasswordScreen.kt | 16 +- .../UpdatePasswordViewModel.kt | 19 +- .../ui/user_profile/UserDetailViewModel.kt | 8 +- .../ui/user_profile/UserProfileActivity.kt | 1 - .../ui/user_profile/UserProfileFragment.kt | 19 +- .../ui/widgets/ChargeWidgetDataProvider.kt | 4 +- .../mobile/utils/AccountTypeItemIndicator.kt | 57 ++ .../mifos/mobile/utils/AccountsFilterUtil.kt | 21 +- .../org/mifos/mobile/utils/AccountsUiState.kt | 13 - .../mifos/mobile/utils/BeneficiaryUiState.kt | 19 - .../utils/CheckSelfPermissionAndRequest.kt | 4 +- .../mifos/mobile/utils/ClientChargeUiState.kt | 4 - .../mifos/mobile/utils/ComparatorBasedOnId.kt | 2 +- .../ConfigurationDialogFragmentCompat.kt | 2 +- .../mobile/utils/ConfigurationPreference.kt | 2 +- .../org/mifos/mobile/utils}/FakeJsonName.kt | 2 +- .../mobile/utils}/FakeRemoteDataSource.kt | 61 +- .../mifos/mobile/utils/GuarantorUiState.kt | 6 +- .../org/mifos/mobile/utils/HelpUiState.kt | 2 +- .../org/mifos/mobile/utils/LoanUiState.kt | 16 - .../org/mifos/mobile/utils/MFErrorParser.kt | 2 +- .../mifos/mobile/utils/NotificationUiState.kt | 3 - .../org/mifos/mobile/utils/QrCodeAnalyzer.kt | 63 ++ .../org/mifos/mobile/utils/QrCodeGenerator.kt | 7 +- .../org/mifos/mobile/utils/QrCodeUiState.kt | 10 - .../mobile/utils/RecentTransactionUiState.kt | 3 - .../mifos/mobile/utils/RegistrationUiState.kt | 8 - .../org/mifos/mobile/utils}/RetrofitUtils.kt | 2 +- .../java/org/mifos/mobile/utils/RxEvent.kt | 2 +- .../mobile/utils/SavingsAccountUiState.kt | 8 +- .../org/mifos/mobile/utils/StatusUtils.kt | 2 +- .../mifos/mobile/utils}/TestDataFactory.kt | 2 +- .../mobile/utils/ThirdPartyTransferUiState.kt | 4 +- .../org/mifos/mobile/utils/TransferUiState.kt | 9 - .../mifos/mobile/utils/UserDetailUiState.kt | 2 +- .../fcm/MifosFirebaseMessagingService.kt | 8 +- .../utils/fcm/RegistrationIntentService.kt | 5 +- .../BeneficiaryApplicationViewModel.kt | 66 -- .../viewModels/BeneficiaryListViewModel.kt | 33 - .../viewModels/QrCodeImportViewModel.kt | 79 -- .../SavingAccountsTransactionViewModel.kt | 152 ---- .../viewModels/TransferProcessViewModel.kt | 66 -- .../res/layout/fragment_qr_code_import.xml | 2 +- app/src/main/res/values/strings.xml | 20 +- .../repositories/ClientRepositoryImpTest.kt | 13 +- .../SavingsAccountRepositoryImpTest.kt | 5 +- .../repositories/TransferRepositoryImpTest.kt | 10 +- .../repositories/UserAuthRepositoryImpTest.kt | 9 +- .../viewModels/AccountsViewModelTest.kt | 7 +- .../viewModels/AddGuarantorViewModelTest.kt | 8 +- .../BeneficiaryApplicationViewModelTest.kt | 10 +- .../LoanAccountTransactionViewModelTest.kt | 8 +- .../LoanAccountsDetailViewModelTest.kt | 12 +- .../LoanApplicationViewModelTest.kt | 14 +- .../LoanRepaymentScheduleViewModelTest.kt | 6 +- .../mobile/viewModels/LoginViewModelTest.kt | 12 +- .../viewModels/RegistrationViewModelTest.kt | 38 +- .../SavingAccountsDetailViewModelTest.kt | 11 +- .../SavingAccountsTransactionViewModelTest.kt | 11 +- .../SavingsAccountApplicationViewModelTest.kt | 16 +- .../ThirdPartyTransferViewModelTest.kt | 10 +- .../TransferProcessViewModelTest.kt | 30 +- .../viewModels/UpdatePasswordViewModelTest.kt | 18 +- build.gradle.kts | 1 + core/common/.gitignore | 1 + core/common/build.gradle.kts | 22 + core/common/consumer-rules.pro | 0 core/common/proguard-rules.pro | 21 + .../core/common/ExampleInstrumentedTest.kt | 24 + core/common/src/main/AndroidManifest.xml | 4 + .../mifos/mobile/core/common}/ApiEndPoints.kt | 2 +- .../mifos/mobile/core/common}/Constants.kt | 12 +- .../org/mifos/mobile/core/common}/Network.kt | 2 +- .../mobile/core/common}/utils/CurrencyUtil.kt | 2 +- .../mobile/core/common}/utils/DateHelper.kt | 2 +- .../core/common}/utils/LanguageHelper.kt | 6 +- .../mobile/core/common}/utils/MFDatePicker.kt | 2 +- .../utils/ParcelableAndSerializableUtils.kt | 2 +- .../core/common}/utils/ProgressBarHandler.kt | 2 +- .../mifos/mobile/core/common}/utils/Utils.kt | 4 +- .../main/res/drawable/circular_background.xml | 0 core/common/src/main/res/layout/toolbar.xml | 8 + core/common/src/main/res/values/strings.xml | 26 + .../mobile/core/common/ExampleUnitTest.kt | 17 + core/data/.gitignore | 1 + core/data/build.gradle.kts | 35 + core/data/consumer-rules.pro | 0 core/data/proguard-rules.pro | 21 + .../core/data/ExampleInstrumentedTest.kt | 24 + core/data/src/main/AndroidManifest.xml | 4 + .../mobile/core/data}/di/RepositoryModule.kt | 27 +- .../data}/repositories/AccountsRepository.kt | 4 +- .../repositories/AccountsRepositoryImp.kt | 6 +- .../repositories/BeneficiaryRepository.kt | 10 +- .../repositories/BeneficiaryRepositoryImp.kt | 12 +- .../repositories/ClientChargeRepository.kt | 6 +- .../repositories/ClientChargeRepositoryImp.kt | 11 +- .../data}/repositories/ClientRepository.kt | 8 +- .../data}/repositories/ClientRepositoryImp.kt | 21 +- .../data}/repositories/GuarantorRepository.kt | 8 +- .../repositories/GuarantorRepositoryImp.kt | 39 +- .../core/data}/repositories/HomeRepository.kt | 6 +- .../data}/repositories/HomeRepositoryImp.kt | 11 +- .../core/data}/repositories/LoanRepository.kt | 8 +- .../data}/repositories/LoanRepositoryImp.kt | 13 +- .../repositories/NotificationRepository.kt | 4 +- .../repositories/NotificationRepositoryImp.kt | 6 +- .../RecentTransactionRepository.kt | 6 +- .../RecentTransactionRepositoryImp.kt | 12 +- .../ReviewLoanApplicationRepository.kt | 6 +- .../ReviewLoanApplicationRepositoryImpl.kt | 10 +- .../repositories/SavingsAccountRepository.kt | 14 +- .../SavingsAccountRepositoryImp.kt | 16 +- .../ThirdPartyTransferRepository.kt | 4 +- .../ThirdPartyTransferRepositoryImp.kt | 7 +- .../data}/repositories/TransferRepository.kt | 4 +- .../repositories/TransferRepositoryImp.kt | 9 +- .../data}/repositories/UserAuthRepository.kt | 4 +- .../repositories/UserAuthRepositoryImp.kt | 14 +- .../repositories/UserDetailRepository.kt | 6 +- .../repositories/UserDetailRepositoryImp.kt | 8 +- .../mifos/mobile/core/data/ExampleUnitTest.kt | 17 + core/datastore/.gitignore | 1 + core/datastore/build.gradle.kts | 32 + core/datastore/consumer-rules.pro | 0 core/datastore/proguard-rules.pro | 21 + .../core/datastore/ExampleInstrumentedTest.kt | 24 + .../mifos/mobile/core/datastore}/BaseURL.kt | 2 +- .../core/datastore}/SelfServiceInterceptor.kt | 4 +- .../src/debug/res/values/api_keys.xml | 5 + core/datastore/src/main/AndroidManifest.xml | 4 + .../mobile/core/datastore}/DatabaseHelper.kt | 15 +- .../core/datastore}/PreferencesHelper.kt | 90 +- .../core/datastore}/SelfServiceDatabase.kt | 3 +- .../mobile/core/datastore/model}/Charge.kt | 8 +- .../datastore/model}/ChargeListResponse.kt | 4 +- .../datastore/model}/MifosNotification.kt | 4 +- .../utils/NotificationComparator.kt | 4 +- .../mifos/mobile/core/datastore}/BaseURL.kt | 0 .../core/datastore}/SelfServiceInterceptor.kt | 0 .../src/release/res/values/api_keys.xml | 5 + .../mobile/core/datastore/ExampleUnitTest.kt | 17 + core/logs/.gitignore | 1 + core/logs/build.gradle.kts | 21 + core/logs/consumer-rules.pro | 0 core/logs/proguard-rules.pro | 21 + .../core/logs/ExampleInstrumentedTest.kt | 22 + core/logs/src/main/AndroidManifest.xml | 4 + .../mifos/mobile/core/logs/AnalyticsEvent.kt | 41 + .../mifos/mobile/core/logs/AnalyticsHelper.kt | 10 + .../mobile/core/logs/di/AnalyticsModule.kt | 27 + .../core/logs/di/FirebaseAnalyticsHelper.kt | 26 + .../mifos/mobile/core/logs/ExampleUnitTest.kt | 17 + core/model/.gitignore | 1 + core/model/build.gradle.kts | 24 + core/model/consumer-rules.pro | 0 core/model/proguard-rules.pro | 21 + .../core/model/ExampleInstrumentedTest.kt | 24 + core/model/src/main/AndroidManifest.xml | 4 + .../mobile/core/model/entity}/AboutUsItem.kt | 4 +- .../entity/AccountOptionAndBeneficiary.kt | 13 + .../model/entity}/ChargeCalculationType.kt | 2 +- .../core/model/entity}/ChargeTimeType.kt | 2 +- .../core/model/entity}/CheckboxStatus.kt | 2 +- .../mobile/core/model/entity}/Currency.kt | 2 +- .../mifos/mobile/core/model/entity}/FAQ.kt | 2 +- .../mifos/mobile/core/model/entity}/Page.kt | 2 +- .../mobile/core/model/entity}/Timeline.kt | 2 +- .../mobile/core/model/entity}/Transaction.kt | 7 +- .../model/entity}/UpdatePasswordPayload.kt | 2 +- .../mifos/mobile/core/model/entity}/User.kt | 2 +- .../core/model/entity}/accounts/Account.kt | 2 +- .../accounts/LoanAccountsListResponse.kt | 4 +- .../accounts/SavingAccountsListResponse.kt | 4 +- .../entity}/accounts/loan/AmortizationType.kt | 2 +- .../model/entity}/accounts/loan/Currency.kt | 2 +- .../entity}/accounts/loan/DaysInMonthType.kt | 2 +- .../entity}/accounts/loan/DaysInYearType.kt | 2 +- .../loan/InterestCalculationPeriodType.kt | 2 +- .../loan/InterestRateFrequencyType.kt | 2 +- .../InterestRecalculationCompoundingType.kt | 2 +- .../loan/InterestRecalculationData.kt | 6 +- .../entity}/accounts/loan/InterestType.kt | 2 +- .../entity}/accounts/loan/LoanAccount.kt | 4 +- .../model/entity}/accounts/loan/LoanType.kt | 2 +- .../accounts/loan/LoanWithAssociations.kt | 4 +- .../entity}/accounts/loan/LoanWithdraw.kt | 2 +- .../model/entity}/accounts/loan/Periods.kt | 2 +- .../RecalculationCompoundingFrequencyType.kt | 2 +- .../loan/RecalculationRestFrequencyType.kt | 2 +- .../accounts/loan/RepaymentFrequencyType.kt | 2 +- .../accounts/loan/RepaymentSchedule.kt | 2 +- .../accounts/loan/RescheduleStrategyType.kt | 2 +- .../model/entity}/accounts/loan/Status.kt | 2 +- .../model/entity}/accounts/loan/Summary.kt | 2 +- .../accounts/loan/TermPeriodFrequencyType.kt | 2 +- .../model/entity}/accounts/loan/Timeline.kt | 2 +- .../loan/calendardata/CalendarData.kt | 2 +- .../accounts/loan/calendardata/EntityType.kt | 2 +- .../accounts/loan/calendardata/Frequency.kt | 2 +- .../calendardata/RepeatsOnNthDayOfMonth.kt | 2 +- .../accounts/loan/calendardata/Type.kt | 2 +- .../entity/accounts/loan/tableview/Cell.kt | 3 + .../accounts/loan/tableview/ColumnHeader.kt | 3 + .../accounts/loan/tableview/RowHeader.kt | 3 + .../entity}/accounts/savings/Currency.kt | 2 +- .../accounts/savings/PaymentDetailData.kt | 2 +- .../entity}/accounts/savings/PaymentType.kt | 2 +- .../entity}/accounts/savings/SavingAccount.kt | 6 +- .../SavingsAccountApplicationPayload.kt | 2 +- .../savings/SavingsAccountUpdatePayload.kt | 2 +- .../savings/SavingsAccountWithdrawPayload.kt | 2 +- .../savings/SavingsWithAssociations.kt | 6 +- .../model/entity}/accounts/savings/Status.kt | 2 +- .../model/entity}/accounts/savings/Summary.kt | 2 +- .../entity}/accounts/savings/TimeLine.kt | 2 +- .../accounts/savings/TransactionType.kt | 2 +- .../entity}/accounts/savings/Transactions.kt | 2 +- .../entity}/accounts/share/ShareAccount.kt | 9 +- .../model/entity}/accounts/share/Status.kt | 2 +- .../model/entity}/accounts/share/Timeline.kt | 2 +- .../model/entity}/beneficiary/Beneficiary.kt | 4 +- .../entity}/beneficiary/BeneficiaryDetail.kt | 2 +- .../entity}/beneficiary/BeneficiaryPayload.kt | 2 +- .../beneficiary/BeneficiaryUpdatePayload.kt | 2 +- .../core/model/entity}/client/Client.kt | 4 +- .../model/entity}/client/ClientAccounts.kt | 11 +- .../entity}/client/ClientClassification.kt | 2 +- .../core/model/entity}/client/ClientType.kt | 2 +- .../core/model/entity}/client/Currency.kt | 2 +- .../core/model/entity}/client/DepositType.kt | 7 +- .../core/model/entity}/client/Gender.kt | 2 +- .../mobile/core/model/entity}/client/Group.kt | 2 +- .../core/model/entity}/client/Status.kt | 2 +- .../mobile/core/model/entity}/client/Type.kt | 2 +- .../guarantor/GuarantorApplicationPayload.kt | 2 +- .../entity}/guarantor/GuarantorPayload.kt | 2 +- .../guarantor/GuarantorTemplatePayload.kt | 2 +- .../model/entity}/guarantor/GuarantorType.kt | 2 +- .../core/model/entity}/mifoserror/Arg.kt | 2 +- .../core/model/entity}/mifoserror/Errors.kt | 2 +- .../model/entity}/mifoserror/MifosError.kt | 2 +- .../NotificationRegisterPayload.kt | 2 +- .../notification/NotificationUserDetail.kt | 2 +- .../model/entity}/payload/AccountDetail.kt | 2 +- .../model/entity}/payload/LoansPayload.kt | 2 +- .../model/entity}/payload/LoginPayload.kt | 2 +- .../model/entity}/payload/TransferPayload.kt | 2 +- .../model/entity}/register/RegisterPayload.kt | 2 +- .../core/model/entity}/register/UserVerify.kt | 2 +- .../templates/account/AccountOption.kt | 2 +- .../account/AccountOptionsTemplate.kt | 2 +- .../entity}/templates/account/AccountType.kt | 2 +- .../beneficiary/AccountTypeOption.kt | 2 +- .../beneficiary/BeneficiaryTemplate.kt | 2 +- .../templates/loans/AccountLinkingOptions.kt | 2 +- .../entity}/templates/loans/AccountingRule.kt | 2 +- .../loans/AllowAttributeOverrides.kt | 2 +- .../loans/AmortizationTypeOptions.kt | 2 +- .../templates/loans/ChargeAppliesTo.kt | 2 +- .../entity}/templates/loans/ChargeOptions.kt | 8 +- .../templates/loans/ChargePaymentMode.kt | 2 +- .../model/entity}/templates/loans/Currency.kt | 2 +- .../entity}/templates/loans/FundOptions.kt | 2 +- .../loans/InterestRateFrequencyTypeOptions.kt | 2 +- .../templates/loans/InterestTypeOptions.kt | 2 +- .../templates/loans/LoanCollateralOptions.kt | 2 +- .../templates/loans/LoanOfficerOptions.kt | 2 +- .../templates/loans/LoanPurposeOptions.kt | 2 +- .../entity}/templates/loans/LoanTemplate.kt | 13 +- .../model/entity}/templates/loans/Product.kt | 13 +- .../entity}/templates/loans/ProductOptions.kt | 2 +- ...RepaymentFrequencyDaysOfWeekTypeOptions.kt | 2 +- .../RepaymentFrequencyNthDayTypeOptions.kt | 2 +- .../loans/RepaymentFrequencyTypeOptions.kt | 2 +- .../model/entity}/templates/loans/TaxGroup.kt | 2 +- .../loans/TermFrequencyTypeOptions.kt | 2 +- .../model/entity}/templates/loans/Timeline.kt | 2 +- .../TransactionProcessingStrategyOptions.kt | 2 +- .../templates/savings/ChargeAppliesTo.kt | 2 +- .../savings/ChargeCalculationType.kt | 2 +- .../templates/savings/ChargeOptions.kt | 4 +- .../templates/savings/ChargePaymentMode.kt | 2 +- .../templates/savings/ChargeTimeType.kt | 2 +- .../templates/savings/ProductOptions.kt | 2 +- .../savings/SavingsAccountTemplate.kt | 2 +- .../core/model}/enums/AboutUsListItemId.kt | 2 +- .../mobile/core/model}/enums/AccountType.kt | 2 +- .../mifos/mobile/core/model/enums/AppTheme.kt | 11 + .../core/model}/enums/BeneficiaryState.kt | 2 +- .../core/model}/enums/BiometricCapability.kt | 2 +- .../mobile/core/model}/enums/ChargeType.kt | 2 +- .../core/model}/enums/GuarantorState.kt | 2 +- .../mobile/core/model}/enums/LoanState.kt | 2 +- .../core/model/enums/MifosAppLanguage.kt | 32 + .../core/model}/enums/RequestAccessType.kt | 4 +- .../core/model}/enums/SavingsAccountState.kt | 2 +- .../mobile/core/model}/enums/TransferType.kt | 2 +- .../mobile/core/model/ExampleUnitTest.kt | 17 + core/network/.gitignore | 1 + core/network/build.gradle.kts | 34 + core/network/consumer-rules.pro | 0 core/network/proguard-rules.pro | 21 + .../core/network/ExampleInstrumentedTest.kt | 24 + core/network/src/main/AndroidManifest.xml | 4 + .../mobile/core/network}/BaseApiManager.kt | 17 +- .../mifos/mobile/core/network}/DataManager.kt | 142 +-- .../org/mifos/mobile/core/network}/Result.kt | 3 +- .../core/network}/SelfServiceOkHttpClient.kt | 5 +- .../mobile/core/network}/di/NetworkModule.kt | 21 +- .../services/AuthenticationService.kt | 8 +- .../network}/services/BeneficiaryService.kt | 12 +- .../network}/services/ClientChargeService.kt | 9 +- .../core/network}/services/ClientService.kt | 11 +- .../network}/services/GuarantorService.kt | 8 +- .../services/LoanAccountsListService.kt | 17 +- .../network}/services/NotificationService.kt | 9 +- .../services/RecentTransactionsService.kt | 8 +- .../network}/services/RegistrationService.kt | 10 +- .../services/SavingAccountsListService.kt | 19 +- .../services/ThirdPartyTransferService.kt | 10 +- .../network}/services/UserDetailsService.kt | 6 +- .../mobile/core/network/ExampleUnitTest.kt | 17 + feature/beneficiary/.gitignore | 1 + feature/beneficiary/build.gradle.kts | 21 + feature/beneficiary/consumer-rules.pro | 0 feature/beneficiary/proguard-rules.pro | 21 + .../beneficiary/ExampleInstrumentedTest.kt | 24 + .../beneficiary/src/main/AndroidManifest.xml | 4 + .../BeneficiaryApplicationContent.kt | 192 ++++ .../BeneficiaryApplicationScreen.kt | 125 +++ .../BeneficiaryApplicationViewModel.kt | 97 ++ .../BeneficiaryDetailContent.kt | 6 +- .../BeneficiaryDetailScreen.kt | 6 +- .../BeneficiaryDetailViewModel.kt | 11 +- .../BeneficiaryListContent.kt | 108 +++ .../beneficiary_list/BeneficiaryListScreen.kt | 202 +++++ .../BeneficiaryListViewModel.kt | 53 ++ .../presentation/BeneficiaryScreen.kt | 83 ++ .../presentation/BeneficiaryScreenIcons.kt | 6 +- .../presentation/RenderIconAndText.kt | 4 +- .../main/res/drawable/ic_add_white_24dp.xml | 9 + .../res/drawable/ic_beneficiary_add_48px.xml | 10 + .../main/res/drawable/ic_error_black_24dp.xml | 9 + .../drawable/ic_file_upload_black_24dp.xml | 11 + .../res/drawable/ic_qrcode_scan_gray_dark.xml | 10 + .../src/main/res/values/strings.xml | 66 ++ .../feature/beneficiary/ExampleUnitTest.kt | 17 + feature/guarantor/.gitignore | 1 + feature/guarantor/build.gradle.kts | 19 + feature/guarantor/consumer-rules.pro | 0 feature/guarantor/proguard-rules.pro | 21 + .../guarantor/src/main/AndroidManifest.xml | 4 + .../guarantor/navigation/GuarantorNavGraph.kt | 26 +- .../guarantor/navigation/GuarantorScreen.kt | 25 + .../guarantor/screens}/GuarantorActivity.kt | 10 +- .../guarantor_add/AddGuarantorScreen.kt | 14 +- .../guarantor_add/AddGuarantorViewModel.kt | 24 +- .../GuarantorDetailContent.kt | 7 +- .../GuarantorDetailScreen.kt | 19 +- .../GuarantorDetailTopBar.kt | 4 +- .../GuarantorDetailViewModel.kt | 22 +- .../guarantor_list/GuarantorListScreen.kt | 14 +- .../guarantor_list/GuarantorListViewModel.kt | 12 +- .../guarantor/src/main/res/values/strings.xml | 27 + feature/loan/.gitignore | 1 + feature/loan/build.gradle.kts | 19 + feature/loan/consumer-rules.pro | 0 feature/loan/proguard-rules.pro | 21 + .../feature/loan/ExampleInstrumentedTest.kt | 24 + feature/loan/src/main/AndroidManifest.xml | 4 + .../loan_account/LoanAccountDetailContent.kt | 12 +- .../loan_account/LoanAccountDetailScreen.kt | 9 +- .../loan_account/LoanAccountDetailTopBar.kt | 4 +- .../LoanAccountsDetailViewModel.kt | 9 +- .../LoanApplicationContent.kt | 11 +- .../LoanApplicationScreen.kt | 15 +- .../LoanApplicationViewModel.kt | 25 +- .../LoanAccountSummaryScreen.kt | 6 +- .../LoanAccountTransactionScreen.kt | 25 +- .../LoanAccountTransactionViewModel.kt | 13 +- .../LoanAccountWithdrawScreen.kt | 11 +- .../LoanAccountWithdrawViewModel.kt | 13 +- .../LoanRepaymentScheduleScreen.kt | 13 +- .../LoanRepaymentScheduleViewModel.kt | 19 +- .../ReviewLoanApplicationContent.kt | 4 +- .../ReviewLoanApplicationScreen.kt | 13 +- .../ReviewLoanApplicationViewModel.kt | 10 +- .../ic_assignment_turned_in_black_24dp.xml | 10 + .../loan/src/main/res/drawable/ic_charges.xml | 46 + .../drawable/ic_check_circle_green_24px.xml | 20 + .../drawable/ic_compare_arrows_black_24dp.xml | 9 + .../main/res/drawable/ic_edit_black_24dp.xml | 9 + .../main/res/drawable/ic_error_black_24dp.xml | 9 + .../res/drawable/ic_local_atm_black_24dp.xml | 10 + .../src/main/res/drawable/ic_qrcode_scan.xml | 9 + .../drawable/ic_report_problem_red_24px.xml | 12 + .../src/main/res/drawable/ic_surveys_48px.xml | 0 feature/loan/src/main/res/values/strings.xml | 87 ++ .../mobile/feature/loan/ExampleUnitTest.kt | 17 + feature/registration/.gitignore | 1 + feature/registration/build.gradle.kts | 27 + feature/registration/consumer-rules.pro | 0 feature/registration/proguard-rules.pro | 21 + .../registration/ExampleInstrumentedTest.kt | 24 + .../registration/src/main/AndroidManifest.xml | 4 + .../navigation/RegistrationNavGraph.kt | 53 ++ .../navigation/RegistrationScreen.kt | 15 + .../screens/RegistrationScreen.kt | 583 ++++++++++++ .../RegistrationVerificationScreen.kt | 42 +- .../registration}/utils/PasswordStrength.kt | 4 +- .../registration/utils/RegistrationState.kt | 8 + .../viewmodel/RegistrationViewModel.kt | 69 ++ .../src/main/res/drawable/mifos_logo.png | Bin 0 -> 60004 bytes .../src/main/res/values/strings.xml | 43 + .../src/main/res/values/validations.xml | 5 + .../src/main/res/values/values.xml | 5 + .../feature/registration/ExampleUnitTest.kt | 17 + gradle/libs.versions.toml | 11 + settings.gradle.kts | 10 + .../mobile/core/ui/component/EmptyDataView.kt | 4 +- .../core/ui/component/MifosAlertDialog.kt | 9 +- .../mobile/core/ui/component/MifosCheckBox.kt | 46 + .../core/ui/component/MifosErrorComponent.kt | 33 + .../mobile/core/ui/component/MifosIcons.kt | 20 + .../ui/component/MifosOutlinedTextField.kt | 8 +- .../core/ui/component/MifosRadioButton.kt | 39 + .../component/MifosRadioButtonAlertDialog.kt | 86 ++ .../mobile/core/ui/component/MifosScaffold.kt | 8 +- .../mobile/core/ui/component/MifosTabPager.kt | 70 ++ .../core/ui/component/MifosTextButton.kt | 29 + .../mobile/core/ui/component/MifosTopBar.kt | 3 + .../ui/component/MonitorListItemWithIcon.kt | 56 ++ .../mobile/core/ui/component/NoInternet.kt | 13 +- .../org/mifos/mobile/core/ui/theme/Color.kt | 4 +- .../org/mifos/mobile/core/ui/theme/Theme.kt | 6 +- .../mobile/core/ui}/utils/SelectableDates.kt | 2 +- 578 files changed, 10486 insertions(+), 4266 deletions(-) delete mode 100644 app/src/debug/java/org/mifos/mobile/api/ObserveUiState.kt delete mode 100644 app/src/main/java/org/mifos/mobile/models/AccountOptionAndBeneficiary.kt delete mode 100644 app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/Cell.kt delete mode 100644 app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/ColumnHeader.kt delete mode 100644 app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/RowHeader.kt rename app/src/main/java/org/mifos/mobile/ui/{fragments => account}/AccountsFragment.kt (99%) create mode 100644 app/src/main/java/org/mifos/mobile/ui/account/AccountsScreen.kt rename app/src/main/java/org/mifos/mobile/{viewModels => ui/account}/AccountsViewModel.kt (65%) create mode 100644 app/src/main/java/org/mifos/mobile/ui/account/LoanAccountContent.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/account/SavingsAccountContent.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/account/ShareAccountContent.kt delete mode 100644 app/src/main/java/org/mifos/mobile/ui/beneficiary/presentation/BeneficiaryScreen.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/beneficiary_application/BeneficiaryApplicationComposeFragment.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/beneficiary_list/BeneficiaryListComposeFragment.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountFilterDialog.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountScreenTopBar.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsComposeFragment.kt rename app/src/main/java/org/mifos/mobile/ui/{fragments => client_accounts}/ClientAccountsFragment.kt (98%) create mode 100644 app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsScreen.kt delete mode 100644 app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryApplicationFragment.kt delete mode 100644 app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryListFragment.kt delete mode 100644 app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeReaderFragment.kt delete mode 100644 app/src/main/java/org/mifos/mobile/ui/guarantor/navigation/GuarantorScreen.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/qr/BarcodeCamera.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/qr/QrCodeReaderFragment.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/qr/QrCodeReaderScreen.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayComposeFragment.kt rename app/src/main/java/org/mifos/mobile/ui/{fragments => qr_code_display}/QrCodeDisplayFragment.kt (93%) create mode 100644 app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayScreen.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayViewModel.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportComposeFragment.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportContent.kt rename app/src/main/java/org/mifos/mobile/ui/{fragments => qr_code_import}/QrCodeImportFragment.kt (82%) create mode 100644 app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportScreen.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportViewModel.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/registration/RegistrationComposeFragment.kt delete mode 100644 app/src/main/java/org/mifos/mobile/ui/registration/RegistrationScreen.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationComposeFragment.kt delete mode 100644 app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationFragment_Old.kt delete mode 100644 app/src/main/java/org/mifos/mobile/ui/registration/RegistrationViewModel.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountTransactionContent.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionFilterDialog.kt rename app/src/main/java/org/mifos/mobile/ui/{fragments => savings_account_transaction}/SavingAccountsTransactionFragment.kt (86%) create mode 100644 app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionScreen.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionViewModel.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingsAccountTransactionComposeFragment.kt rename app/src/main/java/org/mifos/mobile/ui/{activities => settings}/SettingsActivity.kt (57%) create mode 100644 app/src/main/java/org/mifos/mobile/ui/settings/SettingsComposeFragment.kt rename app/src/main/java/org/mifos/mobile/ui/{fragments => settings}/SettingsFragment.kt (90%) create mode 100644 app/src/main/java/org/mifos/mobile/ui/settings/SettingsScreen.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/settings/SettingsViewModel.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/settings/UpdateEndpointDialog.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessComposeFragment.kt rename app/src/main/java/org/mifos/mobile/ui/{fragments => transfer_process}/TransferProcessFragment.kt (89%) create mode 100644 app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessScreen.kt create mode 100644 app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessViewModel.kt create mode 100644 app/src/main/java/org/mifos/mobile/utils/AccountTypeItemIndicator.kt delete mode 100644 app/src/main/java/org/mifos/mobile/utils/AccountsUiState.kt delete mode 100644 app/src/main/java/org/mifos/mobile/utils/BeneficiaryUiState.kt delete mode 100644 app/src/main/java/org/mifos/mobile/utils/ClientChargeUiState.kt rename app/src/{commonTest/java/org/mifos/mobile => main/java/org/mifos/mobile/utils}/FakeJsonName.kt (98%) rename app/src/{commonTest/java/org/mifos/mobile => main/java/org/mifos/mobile/utils}/FakeRemoteDataSource.kt (77%) delete mode 100644 app/src/main/java/org/mifos/mobile/utils/LoanUiState.kt delete mode 100644 app/src/main/java/org/mifos/mobile/utils/NotificationUiState.kt create mode 100644 app/src/main/java/org/mifos/mobile/utils/QrCodeAnalyzer.kt delete mode 100644 app/src/main/java/org/mifos/mobile/utils/QrCodeUiState.kt delete mode 100644 app/src/main/java/org/mifos/mobile/utils/RecentTransactionUiState.kt delete mode 100644 app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt rename app/src/{commonTest/java/org/mifos/mobile => main/java/org/mifos/mobile/utils}/RetrofitUtils.kt (96%) rename app/src/{commonTest/java/org/mifos/mobile => main/java/org/mifos/mobile/utils}/TestDataFactory.kt (98%) delete mode 100644 app/src/main/java/org/mifos/mobile/utils/TransferUiState.kt delete mode 100644 app/src/main/java/org/mifos/mobile/viewModels/BeneficiaryApplicationViewModel.kt delete mode 100644 app/src/main/java/org/mifos/mobile/viewModels/BeneficiaryListViewModel.kt delete mode 100644 app/src/main/java/org/mifos/mobile/viewModels/QrCodeImportViewModel.kt delete mode 100644 app/src/main/java/org/mifos/mobile/viewModels/SavingAccountsTransactionViewModel.kt delete mode 100644 app/src/main/java/org/mifos/mobile/viewModels/TransferProcessViewModel.kt create mode 100644 core/common/.gitignore create mode 100644 core/common/build.gradle.kts create mode 100644 core/common/consumer-rules.pro create mode 100644 core/common/proguard-rules.pro create mode 100644 core/common/src/androidTest/java/org/mifos/mobile/core/common/ExampleInstrumentedTest.kt create mode 100644 core/common/src/main/AndroidManifest.xml rename {app/src/main/java/org/mifos/mobile/api => core/common/src/main/java/org/mifos/mobile/core/common}/ApiEndPoints.kt (94%) rename {app/src/main/java/org/mifos/mobile/utils => core/common/src/main/java/org/mifos/mobile/core/common}/Constants.kt (91%) rename {app/src/main/java/org/mifos/mobile/utils => core/common/src/main/java/org/mifos/mobile/core/common}/Network.kt (99%) rename {app/src/main/java/org/mifos/mobile => core/common/src/main/java/org/mifos/mobile/core/common}/utils/CurrencyUtil.kt (98%) rename {app/src/main/java/org/mifos/mobile => core/common/src/main/java/org/mifos/mobile/core/common}/utils/DateHelper.kt (99%) rename {app/src/main/java/org/mifos/mobile => core/common/src/main/java/org/mifos/mobile/core/common}/utils/LanguageHelper.kt (95%) rename {app/src/main/java/org/mifos/mobile => core/common/src/main/java/org/mifos/mobile/core/common}/utils/MFDatePicker.kt (97%) rename {app/src/main/java/org/mifos/mobile => core/common/src/main/java/org/mifos/mobile/core/common}/utils/ParcelableAndSerializableUtils.kt (95%) rename {app/src/main/java/org/mifos/mobile => core/common/src/main/java/org/mifos/mobile/core/common}/utils/ProgressBarHandler.kt (96%) rename {app/src/main/java/org/mifos/mobile => core/common/src/main/java/org/mifos/mobile/core/common}/utils/Utils.kt (97%) rename {app => core/common}/src/main/res/drawable/circular_background.xml (100%) create mode 100644 core/common/src/main/res/layout/toolbar.xml create mode 100644 core/common/src/main/res/values/strings.xml create mode 100644 core/common/src/test/java/org/mifos/mobile/core/common/ExampleUnitTest.kt create mode 100644 core/data/.gitignore create mode 100644 core/data/build.gradle.kts create mode 100644 core/data/consumer-rules.pro create mode 100644 core/data/proguard-rules.pro create mode 100644 core/data/src/androidTest/java/org/mifos/mobile/core/data/ExampleInstrumentedTest.kt create mode 100644 core/data/src/main/AndroidManifest.xml rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/di/RepositoryModule.kt (80%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/AccountsRepository.kt (55%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/AccountsRepositoryImp.kt (70%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/BeneficiaryRepository.kt (60%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/BeneficiaryRepositoryImp.kt (75%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/ClientChargeRepository.kt (69%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/ClientChargeRepositoryImp.kt (79%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/ClientRepository.kt (61%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/ClientRepositoryImp.kt (71%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/GuarantorRepository.kt (69%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/GuarantorRepositoryImp.kt (51%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/HomeRepository.kt (61%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/HomeRepositoryImp.kt (74%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/LoanRepository.kt (63%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/LoanRepositoryImp.kt (73%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/NotificationRepository.kt (56%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/NotificationRepositoryImp.kt (70%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/RecentTransactionRepository.kt (56%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/RecentTransactionRepositoryImp.kt (53%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/ReviewLoanApplicationRepository.kt (61%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/ReviewLoanApplicationRepositoryImpl.kt (69%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/SavingsAccountRepository.kt (59%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/SavingsAccountRepositoryImp.kt (74%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/ThirdPartyTransferRepository.kt (54%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/ThirdPartyTransferRepositoryImp.kt (70%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/TransferRepository.kt (87%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/TransferRepositoryImp.kt (89%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/UserAuthRepository.kt (87%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/UserAuthRepositoryImp.kt (84%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/UserDetailRepository.kt (65%) rename {app/src/main/java/org/mifos/mobile => core/data/src/main/java/org/mifos/mobile/core/data}/repositories/UserDetailRepositoryImp.kt (77%) create mode 100644 core/data/src/test/java/org/mifos/mobile/core/data/ExampleUnitTest.kt create mode 100644 core/datastore/.gitignore create mode 100644 core/datastore/build.gradle.kts create mode 100644 core/datastore/consumer-rules.pro create mode 100644 core/datastore/proguard-rules.pro create mode 100644 core/datastore/src/androidTest/java/org/mifos/mobile/core/datastore/ExampleInstrumentedTest.kt rename {app/src/debug/java/org/mifos/mobile/api => core/datastore/src/debug/java/org/mifos/mobile/core/datastore}/BaseURL.kt (92%) rename {app/src/debug/java/org/mifos/mobile/api => core/datastore/src/debug/java/org/mifos/mobile/core/datastore}/SelfServiceInterceptor.kt (91%) create mode 100644 core/datastore/src/debug/res/values/api_keys.xml create mode 100644 core/datastore/src/main/AndroidManifest.xml rename {app/src/main/java/org/mifos/mobile/api/local => core/datastore/src/main/java/org/mifos/mobile/core/datastore}/DatabaseHelper.kt (82%) rename {app/src/main/java/org/mifos/mobile/api/local => core/datastore/src/main/java/org/mifos/mobile/core/datastore}/PreferencesHelper.kt (66%) rename {app/src/main/java/org/mifos/mobile/api/local => core/datastore/src/main/java/org/mifos/mobile/core/datastore}/SelfServiceDatabase.kt (87%) rename {app/src/main/java/org/mifos/mobile/models => core/datastore/src/main/java/org/mifos/mobile/core/datastore/model}/Charge.kt (92%) rename {app/src/main/java/org/mifos/mobile/models => core/datastore/src/main/java/org/mifos/mobile/core/datastore/model}/ChargeListResponse.kt (56%) rename {app/src/main/java/org/mifos/mobile/models/notification => core/datastore/src/main/java/org/mifos/mobile/core/datastore/model}/MifosNotification.kt (88%) rename {app/src/main/java/org/mifos/mobile => core/datastore/src/main/java/org/mifos/mobile/core/datastore}/utils/NotificationComparator.kt (83%) rename {app/src/release/java/org/mifos/mobile/api => core/datastore/src/release/java/org/mifos/mobile/core/datastore}/BaseURL.kt (100%) rename {app/src/release/java/org/mifos/mobile/api => core/datastore/src/release/java/org/mifos/mobile/core/datastore}/SelfServiceInterceptor.kt (100%) create mode 100644 core/datastore/src/release/res/values/api_keys.xml create mode 100644 core/datastore/src/test/java/org/mifos/mobile/core/datastore/ExampleUnitTest.kt create mode 100644 core/logs/.gitignore create mode 100644 core/logs/build.gradle.kts create mode 100644 core/logs/consumer-rules.pro create mode 100644 core/logs/proguard-rules.pro create mode 100644 core/logs/src/androidTest/java/org/mifos/mobile/core/logs/ExampleInstrumentedTest.kt create mode 100644 core/logs/src/main/AndroidManifest.xml create mode 100644 core/logs/src/main/java/org/mifos/mobile/core/logs/AnalyticsEvent.kt create mode 100644 core/logs/src/main/java/org/mifos/mobile/core/logs/AnalyticsHelper.kt create mode 100644 core/logs/src/main/java/org/mifos/mobile/core/logs/di/AnalyticsModule.kt create mode 100644 core/logs/src/main/java/org/mifos/mobile/core/logs/di/FirebaseAnalyticsHelper.kt create mode 100644 core/logs/src/test/java/org/mifos/mobile/core/logs/ExampleUnitTest.kt create mode 100644 core/model/.gitignore create mode 100644 core/model/build.gradle.kts create mode 100644 core/model/consumer-rules.pro create mode 100644 core/model/proguard-rules.pro create mode 100644 core/model/src/androidTest/java/org/mifos/mobile/core/model/ExampleInstrumentedTest.kt create mode 100644 core/model/src/main/AndroidManifest.xml rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/AboutUsItem.kt (59%) create mode 100644 core/model/src/main/java/org/mifos/mobile/core/model/entity/AccountOptionAndBeneficiary.kt rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/ChargeCalculationType.kt (87%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/ChargeTimeType.kt (85%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/CheckboxStatus.kt (80%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/Currency.kt (89%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/FAQ.kt (86%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/Page.kt (76%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/Timeline.kt (95%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/Transaction.kt (77%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/UpdatePasswordPayload.kt (77%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/User.kt (86%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/Account.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/LoanAccountsListResponse.kt (54%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/SavingAccountsListResponse.kt (54%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/AmortizationType.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/Currency.kt (87%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/DaysInMonthType.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/DaysInYearType.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/InterestCalculationPeriodType.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/InterestRateFrequencyType.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/InterestRecalculationCompoundingType.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/InterestRecalculationData.kt (84%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/InterestType.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/LoanAccount.kt (96%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/LoanType.kt (77%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/LoanWithAssociations.kt (96%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/LoanWithdraw.kt (85%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/Periods.kt (97%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/RecalculationCompoundingFrequencyType.kt (83%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/RecalculationRestFrequencyType.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/RepaymentFrequencyType.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/RepaymentSchedule.kt (93%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/RescheduleStrategyType.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/Status.kt (94%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/Summary.kt (94%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/TermPeriodFrequencyType.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/Timeline.kt (98%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/calendardata/CalendarData.kt (93%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/calendardata/EntityType.kt (78%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/calendardata/Frequency.kt (78%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/calendardata/RepeatsOnNthDayOfMonth.kt (79%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/loan/calendardata/Type.kt (77%) create mode 100644 core/model/src/main/java/org/mifos/mobile/core/model/entity/accounts/loan/tableview/Cell.kt create mode 100644 core/model/src/main/java/org/mifos/mobile/core/model/entity/accounts/loan/tableview/ColumnHeader.kt create mode 100644 core/model/src/main/java/org/mifos/mobile/core/model/entity/accounts/loan/tableview/RowHeader.kt rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/Currency.kt (85%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/PaymentDetailData.kt (87%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/PaymentType.kt (78%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/SavingAccount.kt (84%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/SavingsAccountApplicationPayload.kt (86%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/SavingsAccountUpdatePayload.kt (80%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/SavingsAccountWithdrawPayload.kt (84%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/SavingsWithAssociations.kt (92%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/Status.kt (91%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/Summary.kt (90%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/TimeLine.kt (97%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/TransactionType.kt (93%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/savings/Transactions.kt (91%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/share/ShareAccount.kt (73%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/share/Status.kt (90%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/accounts/share/Timeline.kt (93%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/beneficiary/Beneficiary.kt (76%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/beneficiary/BeneficiaryDetail.kt (69%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/beneficiary/BeneficiaryPayload.kt (87%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/beneficiary/BeneficiaryUpdatePayload.kt (76%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/client/Client.kt (91%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/client/ClientAccounts.kt (75%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/client/ClientClassification.kt (84%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/client/ClientType.kt (83%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/client/Currency.kt (86%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/client/DepositType.kt (89%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/client/Gender.kt (83%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/client/Group.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/client/Status.kt (83%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/client/Type.kt (83%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/guarantor/GuarantorApplicationPayload.kt (88%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/guarantor/GuarantorPayload.kt (90%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/guarantor/GuarantorTemplatePayload.kt (78%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/guarantor/GuarantorType.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/mifoserror/Arg.kt (72%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/mifoserror/Errors.kt (84%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/mifoserror/MifosError.kt (86%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/notification/NotificationRegisterPayload.kt (72%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/notification/NotificationUserDetail.kt (65%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/payload/AccountDetail.kt (72%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/payload/LoansPayload.kt (96%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/payload/LoginPayload.kt (74%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/payload/TransferPayload.kt (93%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/register/RegisterPayload.kt (87%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/register/UserVerify.kt (74%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/account/AccountOption.kt (87%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/account/AccountOptionsTemplate.kt (87%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/account/AccountType.kt (80%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/beneficiary/AccountTypeOption.kt (79%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/beneficiary/BeneficiaryTemplate.kt (77%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/AccountLinkingOptions.kt (88%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/AccountingRule.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/AllowAttributeOverrides.kt (90%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/AmortizationTypeOptions.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/ChargeAppliesTo.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/ChargeOptions.kt (75%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/ChargePaymentMode.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/Currency.kt (87%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/FundOptions.kt (79%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/InterestRateFrequencyTypeOptions.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/InterestTypeOptions.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/LoanCollateralOptions.kt (85%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/LoanOfficerOptions.kt (91%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/LoanPurposeOptions.kt (87%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/LoanTemplate.kt (85%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/Product.kt (79%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/ProductOptions.kt (94%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/RepaymentFrequencyDaysOfWeekTypeOptions.kt (79%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/RepaymentFrequencyNthDayTypeOptions.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/RepaymentFrequencyTypeOptions.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/TaxGroup.kt (78%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/TermFrequencyTypeOptions.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/Timeline.kt (77%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/loans/TransactionProcessingStrategyOptions.kt (82%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/savings/ChargeAppliesTo.kt (77%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/savings/ChargeCalculationType.kt (78%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/savings/ChargeOptions.kt (81%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/savings/ChargePaymentMode.kt (77%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/savings/ChargeTimeType.kt (77%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/savings/ProductOptions.kt (78%) rename {app/src/main/java/org/mifos/mobile/models => core/model/src/main/java/org/mifos/mobile/core/model/entity}/templates/savings/SavingsAccountTemplate.kt (91%) rename {app/src/main/java/org/mifos/mobile/ui => core/model/src/main/java/org/mifos/mobile/core/model}/enums/AboutUsListItemId.kt (79%) rename {app/src/main/java/org/mifos/mobile/ui => core/model/src/main/java/org/mifos/mobile/core/model}/enums/AccountType.kt (73%) create mode 100644 core/model/src/main/java/org/mifos/mobile/core/model/enums/AppTheme.kt rename {app/src/main/java/org/mifos/mobile/ui => core/model/src/main/java/org/mifos/mobile/core/model}/enums/BeneficiaryState.kt (75%) rename {app/src/main/java/org/mifos/mobile/ui => core/model/src/main/java/org/mifos/mobile/core/model}/enums/BiometricCapability.kt (67%) rename {app/src/main/java/org/mifos/mobile/ui => core/model/src/main/java/org/mifos/mobile/core/model}/enums/ChargeType.kt (72%) rename {app/src/main/java/org/mifos/mobile/ui => core/model/src/main/java/org/mifos/mobile/core/model}/enums/GuarantorState.kt (71%) rename {app/src/main/java/org/mifos/mobile/ui => core/model/src/main/java/org/mifos/mobile/core/model}/enums/LoanState.kt (69%) create mode 100644 core/model/src/main/java/org/mifos/mobile/core/model/enums/MifosAppLanguage.kt rename {app/src/main/java/org/mifos/mobile/ui => core/model/src/main/java/org/mifos/mobile/core/model}/enums/RequestAccessType.kt (69%) rename {app/src/main/java/org/mifos/mobile/ui => core/model/src/main/java/org/mifos/mobile/core/model}/enums/SavingsAccountState.kt (71%) rename {app/src/main/java/org/mifos/mobile/ui => core/model/src/main/java/org/mifos/mobile/core/model}/enums/TransferType.kt (68%) create mode 100644 core/model/src/test/java/org/mifos/mobile/core/model/ExampleUnitTest.kt create mode 100644 core/network/.gitignore create mode 100644 core/network/build.gradle.kts create mode 100644 core/network/consumer-rules.pro create mode 100644 core/network/proguard-rules.pro create mode 100644 core/network/src/androidTest/java/org/mifos/mobile/core/network/ExampleInstrumentedTest.kt create mode 100644 core/network/src/main/AndroidManifest.xml rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/BaseApiManager.kt (67%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/DataManager.kt (54%) rename {app/src/main/java/org/mifos/mobile/utils => core/network/src/main/java/org/mifos/mobile/core/network}/Result.kt (90%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/SelfServiceOkHttpClient.kt (95%) rename {app/src/main/java/org/mifos/mobile => core/network/src/main/java/org/mifos/mobile/core/network}/di/NetworkModule.kt (75%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/AuthenticationService.kt (55%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/BeneficiaryService.kt (68%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/ClientChargeService.kt (74%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/ClientService.kt (78%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/GuarantorService.kt (79%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/LoanAccountsListService.kt (72%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/NotificationService.kt (71%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/RecentTransactionsService.kt (68%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/RegistrationService.kt (62%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/SavingAccountsListService.kt (69%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/ThirdPartyTransferService.kt (63%) rename {app/src/main/java/org/mifos/mobile/api => core/network/src/main/java/org/mifos/mobile/core/network}/services/UserDetailsService.kt (63%) create mode 100644 core/network/src/test/java/org/mifos/mobile/core/network/ExampleUnitTest.kt create mode 100644 feature/beneficiary/.gitignore create mode 100644 feature/beneficiary/build.gradle.kts create mode 100644 feature/beneficiary/consumer-rules.pro create mode 100644 feature/beneficiary/proguard-rules.pro create mode 100644 feature/beneficiary/src/androidTest/java/org/mifos/mobile/feature/beneficiary/ExampleInstrumentedTest.kt create mode 100644 feature/beneficiary/src/main/AndroidManifest.xml create mode 100644 feature/beneficiary/src/main/java/org/mifos/mobile/feature/beneficiary/beneficiary_application/BeneficiaryApplicationContent.kt create mode 100644 feature/beneficiary/src/main/java/org/mifos/mobile/feature/beneficiary/beneficiary_application/BeneficiaryApplicationScreen.kt create mode 100644 feature/beneficiary/src/main/java/org/mifos/mobile/feature/beneficiary/beneficiary_application/BeneficiaryApplicationViewModel.kt rename {app/src/main/java/org/mifos/mobile/ui => feature/beneficiary/src/main/java/org/mifos/mobile/feature/beneficiary}/beneficiary_detail/BeneficiaryDetailContent.kt (94%) rename {app/src/main/java/org/mifos/mobile/ui => feature/beneficiary/src/main/java/org/mifos/mobile/feature/beneficiary}/beneficiary_detail/BeneficiaryDetailScreen.kt (98%) rename {app/src/main/java/org/mifos/mobile/ui => feature/beneficiary/src/main/java/org/mifos/mobile/feature/beneficiary}/beneficiary_detail/BeneficiaryDetailViewModel.kt (82%) create mode 100644 feature/beneficiary/src/main/java/org/mifos/mobile/feature/beneficiary/beneficiary_list/BeneficiaryListContent.kt create mode 100644 feature/beneficiary/src/main/java/org/mifos/mobile/feature/beneficiary/beneficiary_list/BeneficiaryListScreen.kt create mode 100644 feature/beneficiary/src/main/java/org/mifos/mobile/feature/beneficiary/beneficiary_list/BeneficiaryListViewModel.kt create mode 100644 feature/beneficiary/src/main/java/org/mifos/mobile/feature/beneficiary/presentation/BeneficiaryScreen.kt rename {app/src/main/java/org/mifos/mobile/ui => feature/beneficiary/src/main/java/org/mifos/mobile/feature}/beneficiary/presentation/BeneficiaryScreenIcons.kt (93%) rename {app/src/main/java/org/mifos/mobile/ui => feature/beneficiary/src/main/java/org/mifos/mobile/feature}/beneficiary/presentation/RenderIconAndText.kt (98%) create mode 100644 feature/beneficiary/src/main/res/drawable/ic_add_white_24dp.xml create mode 100644 feature/beneficiary/src/main/res/drawable/ic_beneficiary_add_48px.xml create mode 100644 feature/beneficiary/src/main/res/drawable/ic_error_black_24dp.xml create mode 100644 feature/beneficiary/src/main/res/drawable/ic_file_upload_black_24dp.xml create mode 100644 feature/beneficiary/src/main/res/drawable/ic_qrcode_scan_gray_dark.xml create mode 100644 feature/beneficiary/src/main/res/values/strings.xml create mode 100644 feature/beneficiary/src/test/java/org/mifos/mobile/feature/beneficiary/ExampleUnitTest.kt create mode 100644 feature/guarantor/.gitignore create mode 100644 feature/guarantor/build.gradle.kts create mode 100644 feature/guarantor/consumer-rules.pro create mode 100644 feature/guarantor/proguard-rules.pro create mode 100644 feature/guarantor/src/main/AndroidManifest.xml rename {app/src/main/java/org/mifos/mobile/ui => feature/guarantor/src/main/java/org/mifos/mobile/feature}/guarantor/navigation/GuarantorNavGraph.kt (75%) create mode 100644 feature/guarantor/src/main/java/org/mifos/mobile/feature/guarantor/navigation/GuarantorScreen.kt rename {app/src/main/java/org/mifos/mobile/ui/guarantor => feature/guarantor/src/main/java/org/mifos/mobile/feature/guarantor/screens}/GuarantorActivity.kt (75%) rename {app/src/main/java/org/mifos/mobile/ui/guarantor => feature/guarantor/src/main/java/org/mifos/mobile/feature/guarantor/screens}/guarantor_add/AddGuarantorScreen.kt (95%) rename {app/src/main/java/org/mifos/mobile/ui/guarantor => feature/guarantor/src/main/java/org/mifos/mobile/feature/guarantor/screens}/guarantor_add/AddGuarantorViewModel.kt (83%) rename {app/src/main/java/org/mifos/mobile/ui/guarantor => feature/guarantor/src/main/java/org/mifos/mobile/feature/guarantor/screens}/guarantor_details/GuarantorDetailContent.kt (90%) rename {app/src/main/java/org/mifos/mobile/ui/guarantor => feature/guarantor/src/main/java/org/mifos/mobile/feature/guarantor/screens}/guarantor_details/GuarantorDetailScreen.kt (89%) rename {app/src/main/java/org/mifos/mobile/ui/guarantor => feature/guarantor/src/main/java/org/mifos/mobile/feature/guarantor/screens}/guarantor_details/GuarantorDetailTopBar.kt (96%) rename {app/src/main/java/org/mifos/mobile/ui/guarantor => feature/guarantor/src/main/java/org/mifos/mobile/feature/guarantor/screens}/guarantor_details/GuarantorDetailViewModel.kt (84%) rename {app/src/main/java/org/mifos/mobile/ui/guarantor => feature/guarantor/src/main/java/org/mifos/mobile/feature/guarantor/screens}/guarantor_list/GuarantorListScreen.kt (94%) rename {app/src/main/java/org/mifos/mobile/ui/guarantor => feature/guarantor/src/main/java/org/mifos/mobile/feature/guarantor/screens}/guarantor_list/GuarantorListViewModel.kt (83%) create mode 100644 feature/guarantor/src/main/res/values/strings.xml create mode 100644 feature/loan/.gitignore create mode 100644 feature/loan/build.gradle.kts create mode 100644 feature/loan/consumer-rules.pro create mode 100644 feature/loan/proguard-rules.pro create mode 100644 feature/loan/src/androidTest/java/org/mifos/mobile/feature/loan/ExampleInstrumentedTest.kt create mode 100644 feature/loan/src/main/AndroidManifest.xml rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account/LoanAccountDetailContent.kt (95%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account/LoanAccountDetailScreen.kt (93%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account/LoanAccountDetailTopBar.kt (97%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account/LoanAccountsDetailViewModel.kt (88%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account_application/LoanApplicationContent.kt (97%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account_application/LoanApplicationScreen.kt (92%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account_application/LoanApplicationViewModel.kt (93%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account_summary/LoanAccountSummaryScreen.kt (98%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account_transaction/LoanAccountTransactionScreen.kt (90%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account_transaction/LoanAccountTransactionViewModel.kt (83%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account_withdraw/LoanAccountWithdrawScreen.kt (95%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_account_withdraw/LoanAccountWithdrawViewModel.kt (84%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_repayment_schedule/LoanRepaymentScheduleScreen.kt (96%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_repayment_schedule/LoanRepaymentScheduleViewModel.kt (64%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_review/ReviewLoanApplicationContent.kt (97%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_review/ReviewLoanApplicationScreen.kt (92%) rename {app/src/main/java/org/mifos/mobile/ui => feature/loan/src/main/java/org/mifos/mobile/feature/loan}/loan_review/ReviewLoanApplicationViewModel.kt (91%) create mode 100644 feature/loan/src/main/res/drawable/ic_assignment_turned_in_black_24dp.xml create mode 100644 feature/loan/src/main/res/drawable/ic_charges.xml create mode 100644 feature/loan/src/main/res/drawable/ic_check_circle_green_24px.xml create mode 100644 feature/loan/src/main/res/drawable/ic_compare_arrows_black_24dp.xml create mode 100644 feature/loan/src/main/res/drawable/ic_edit_black_24dp.xml create mode 100644 feature/loan/src/main/res/drawable/ic_error_black_24dp.xml create mode 100644 feature/loan/src/main/res/drawable/ic_local_atm_black_24dp.xml create mode 100644 feature/loan/src/main/res/drawable/ic_qrcode_scan.xml create mode 100644 feature/loan/src/main/res/drawable/ic_report_problem_red_24px.xml rename {app => feature/loan}/src/main/res/drawable/ic_surveys_48px.xml (100%) create mode 100644 feature/loan/src/main/res/values/strings.xml create mode 100644 feature/loan/src/test/java/org/mifos/mobile/feature/loan/ExampleUnitTest.kt create mode 100644 feature/registration/.gitignore create mode 100644 feature/registration/build.gradle.kts create mode 100644 feature/registration/consumer-rules.pro create mode 100644 feature/registration/proguard-rules.pro create mode 100644 feature/registration/src/androidTest/java/org/mifos/mobile/feature/registration/ExampleInstrumentedTest.kt create mode 100644 feature/registration/src/main/AndroidManifest.xml create mode 100644 feature/registration/src/main/java/org/mifos/mobile/feature/registration/navigation/RegistrationNavGraph.kt create mode 100644 feature/registration/src/main/java/org/mifos/mobile/feature/registration/navigation/RegistrationScreen.kt create mode 100644 feature/registration/src/main/java/org/mifos/mobile/feature/registration/screens/RegistrationScreen.kt rename {app/src/main/java/org/mifos/mobile/ui/registration => feature/registration/src/main/java/org/mifos/mobile/feature/registration/screens}/RegistrationVerificationScreen.kt (89%) rename {app/src/main/java/org/mifos/mobile => feature/registration/src/main/java/org/mifos/mobile/feature/registration}/utils/PasswordStrength.kt (96%) create mode 100644 feature/registration/src/main/java/org/mifos/mobile/feature/registration/utils/RegistrationState.kt create mode 100644 feature/registration/src/main/java/org/mifos/mobile/feature/registration/viewmodel/RegistrationViewModel.kt create mode 100644 feature/registration/src/main/res/drawable/mifos_logo.png create mode 100644 feature/registration/src/main/res/values/strings.xml create mode 100644 feature/registration/src/main/res/values/validations.xml create mode 100644 feature/registration/src/main/res/values/values.xml create mode 100644 feature/registration/src/test/java/org/mifos/mobile/feature/registration/ExampleUnitTest.kt create mode 100644 ui/src/main/java/org/mifos/mobile/core/ui/component/MifosCheckBox.kt create mode 100644 ui/src/main/java/org/mifos/mobile/core/ui/component/MifosIcons.kt create mode 100644 ui/src/main/java/org/mifos/mobile/core/ui/component/MifosRadioButton.kt create mode 100644 ui/src/main/java/org/mifos/mobile/core/ui/component/MifosRadioButtonAlertDialog.kt create mode 100644 ui/src/main/java/org/mifos/mobile/core/ui/component/MifosTabPager.kt create mode 100644 ui/src/main/java/org/mifos/mobile/core/ui/component/MonitorListItemWithIcon.kt rename {app/src/main/java/org/mifos/mobile => ui/src/main/java/org/mifos/mobile/core/ui}/utils/SelectableDates.kt (92%) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 46b6f13dc..4e3525fc0 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -69,7 +69,19 @@ android { } dependencies { + + implementation(projects.core.logs) + implementation(projects.core.common) + implementation(projects.core.model) + implementation(projects.core.data) + implementation(projects.core.datastore) implementation(projects.ui) + implementation(projects.feature.loan) + + implementation(projects.feature.registration) + implementation(projects.feature.beneficiary) + implementation(projects.feature.guarantor) + implementation("androidx.legacy:legacy-support-v4:1.0.0") implementation(libs.androidx.lifecycle.ktx) @@ -164,6 +176,7 @@ dependencies { api(libs.androidx.activity.compose) api(platform(libs.androidx.compose.bom)) api(libs.androidx.compose.material3) + api(libs.androidx.compose.material) api(libs.androidx.compose.foundation) api(libs.androidx.compose.foundation.layout) api(libs.androidx.compose.material.iconsExtended) @@ -177,7 +190,17 @@ dependencies { // google maps implementation ("com.google.maps.android:maps-compose:4.4.1") + //image cropper + implementation("com.github.CanHub:Android-Image-Cropper:4.0.0") + + // Google Bar code scanner + implementation(libs.google.app.code.scanner) + //cameraX + implementation(libs.androidx.camera.camera2) + implementation(libs.androidx.camera.lifecycle) + implementation(libs.androidx.camera.view) + implementation(libs.androidx.camera.core) } diff --git a/app/src/debug/java/org/mifos/mobile/api/ObserveUiState.kt b/app/src/debug/java/org/mifos/mobile/api/ObserveUiState.kt deleted file mode 100644 index 9e624a5a1..000000000 --- a/app/src/debug/java/org/mifos/mobile/api/ObserveUiState.kt +++ /dev/null @@ -1,16 +0,0 @@ -package org.mifos.mobile.api - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import org.mifos.mobile.utils.BeneficiaryUiState - -//fun TestScope.obserrveUiState(): MutableList { -// val uiStates = mutableListOf() -// viewModel.beneficiaryUiState.onEach { -// println(it) -// uiStates.add(it) -// } -// .launchIn(CoroutineScope(UnconfinedTestDispatcher(testScheduler))) -// return uiStates -//} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d02774036..235cbc780 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,8 +3,14 @@ xmlns:tools="http://schemas.android.com/tools" package="org.mifos.mobile"> + + + + @@ -18,11 +24,12 @@ android:theme="@style/AppTheme" tools:ignore="GoogleAppIndexingWarning"> + @@ -35,6 +42,12 @@ android:configChanges="orientation|screenSize" android:label="@string/app_name" android:windowSoftInputMode="adjustResize" /> + + + - + \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/MifosSelfServiceApp.kt b/app/src/main/java/org/mifos/mobile/MifosSelfServiceApp.kt index 0de31d6f7..bebd02177 100644 --- a/app/src/main/java/org/mifos/mobile/MifosSelfServiceApp.kt +++ b/app/src/main/java/org/mifos/mobile/MifosSelfServiceApp.kt @@ -10,11 +10,9 @@ import com.mifos.mobile.passcode.utils.ForegroundChecker import com.raizlabs.android.dbflow.config.FlowConfig import com.raizlabs.android.dbflow.config.FlowManager import dagger.hilt.android.HiltAndroidApp -import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.ui.fragments.applySavedTheme -import org.mifos.mobile.utils.LanguageHelper -import org.mifos.mobile.utils.LanguageHelper.onAttach -import java.util.Locale +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.ui.settings.applySavedTheme +import org.mifos.mobile.core.common.utils.LanguageHelper.onAttach /** * @author ishan diff --git a/app/src/main/java/org/mifos/mobile/di/ApplicationModule.kt b/app/src/main/java/org/mifos/mobile/di/ApplicationModule.kt index e2aabca3e..c94097198 100644 --- a/app/src/main/java/org/mifos/mobile/di/ApplicationModule.kt +++ b/app/src/main/java/org/mifos/mobile/di/ApplicationModule.kt @@ -6,22 +6,22 @@ import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import org.mifos.mobile.api.BaseApiManager -import org.mifos.mobile.api.DataManager -import org.mifos.mobile.api.local.DatabaseHelper -import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.api.services.AuthenticationService -import org.mifos.mobile.api.services.BeneficiaryService -import org.mifos.mobile.api.services.ClientChargeService -import org.mifos.mobile.api.services.ClientService -import org.mifos.mobile.api.services.GuarantorService -import org.mifos.mobile.api.services.LoanAccountsListService -import org.mifos.mobile.api.services.NotificationService -import org.mifos.mobile.api.services.RecentTransactionsService -import org.mifos.mobile.api.services.RegistrationService -import org.mifos.mobile.api.services.SavingAccountsListService -import org.mifos.mobile.api.services.ThirdPartyTransferService -import org.mifos.mobile.api.services.UserDetailsService +import org.mifos.mobile.core.datastore.DatabaseHelper +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.network.BaseApiManager +import org.mifos.mobile.core.network.DataManager +import org.mifos.mobile.core.network.services.AuthenticationService +import org.mifos.mobile.core.network.services.BeneficiaryService +import org.mifos.mobile.core.network.services.ClientChargeService +import org.mifos.mobile.core.network.services.ClientService +import org.mifos.mobile.core.network.services.GuarantorService +import org.mifos.mobile.core.network.services.LoanAccountsListService +import org.mifos.mobile.core.network.services.NotificationService +import org.mifos.mobile.core.network.services.RecentTransactionsService +import org.mifos.mobile.core.network.services.RegistrationService +import org.mifos.mobile.core.network.services.SavingAccountsListService +import org.mifos.mobile.core.network.services.ThirdPartyTransferService +import org.mifos.mobile.core.network.services.UserDetailsService import javax.inject.Singleton /** diff --git a/app/src/main/java/org/mifos/mobile/models/AccountOptionAndBeneficiary.kt b/app/src/main/java/org/mifos/mobile/models/AccountOptionAndBeneficiary.kt deleted file mode 100644 index fdf2e8bfa..000000000 --- a/app/src/main/java/org/mifos/mobile/models/AccountOptionAndBeneficiary.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.mifos.mobile.models - -import org.mifos.mobile.models.beneficiary.Beneficiary -import org.mifos.mobile.models.templates.account.AccountOptionsTemplate - -/** - * Created by dilpreet on 23/6/17. - */ - -data class AccountOptionAndBeneficiary( - val accountOptionsTemplate: AccountOptionsTemplate, - val beneficiaryList: List, -) diff --git a/app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/Cell.kt b/app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/Cell.kt deleted file mode 100644 index 18ad43038..000000000 --- a/app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/Cell.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.mifos.mobile.models.accounts.loan.tableview - -data class Cell(val data: Any) diff --git a/app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/ColumnHeader.kt b/app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/ColumnHeader.kt deleted file mode 100644 index db7ee1c05..000000000 --- a/app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/ColumnHeader.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.mifos.mobile.models.accounts.loan.tableview - -data class ColumnHeader(val data: Any) diff --git a/app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/RowHeader.kt b/app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/RowHeader.kt deleted file mode 100644 index 0a2d89520..000000000 --- a/app/src/main/java/org/mifos/mobile/models/accounts/loan/tableview/RowHeader.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.mifos.mobile.models.accounts.loan.tableview - -data class RowHeader(val data: Any) diff --git a/app/src/main/java/org/mifos/mobile/ui/about/AboutUsActivity.kt b/app/src/main/java/org/mifos/mobile/ui/about/AboutUsActivity.kt index 43d9da002..58ce379a4 100644 --- a/app/src/main/java/org/mifos/mobile/ui/about/AboutUsActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/about/AboutUsActivity.kt @@ -4,7 +4,6 @@ import android.os.Bundle import org.mifos.mobile.R import org.mifos.mobile.databinding.ActivityContainerBinding import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.about.AboutUsFragment /** * @author Rajan Maurya diff --git a/app/src/main/java/org/mifos/mobile/ui/about/AboutUsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/about/AboutUsFragment.kt index 4ca4ba372..c938dea15 100644 --- a/app/src/main/java/org/mifos/mobile/ui/about/AboutUsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/about/AboutUsFragment.kt @@ -8,7 +8,6 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.compose.material3.Scaffold import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.fragment.app.viewModels @@ -16,11 +15,11 @@ import com.google.android.gms.oss.licenses.OssLicensesMenuActivity import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.core.ui.theme.MifosMobileTheme import org.mifos.mobile.ui.activities.PrivacyPolicyActivity -import org.mifos.mobile.ui.enums.AboutUsListItemId +import org.mifos.mobile.core.model.enums.AboutUsListItemId import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.utils.Constants.LICENSE_LINK -import org.mifos.mobile.utils.Constants.SOURCE_CODE_LINK -import org.mifos.mobile.utils.Constants.WEBSITE_LINK +import org.mifos.mobile.core.common.Constants.LICENSE_LINK +import org.mifos.mobile.core.common.Constants.SOURCE_CODE_LINK +import org.mifos.mobile.core.common.Constants.WEBSITE_LINK /* ~This project is licensed under the open source MPL V2. diff --git a/app/src/main/java/org/mifos/mobile/ui/about/AboutUsScreen.kt b/app/src/main/java/org/mifos/mobile/ui/about/AboutUsScreen.kt index 5d9aef698..62691551c 100644 --- a/app/src/main/java/org/mifos/mobile/ui/about/AboutUsScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/about/AboutUsScreen.kt @@ -7,9 +7,9 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import org.mifos.mobile.core.model.enums.AboutUsListItemId import org.mifos.mobile.core.ui.component.AboutUsItemCard import org.mifos.mobile.core.ui.component.MifosItemCard -import org.mifos.mobile.ui.enums.AboutUsListItemId @Composable fun AboutUsScreen(viewModel: AboutUsViewModel) { diff --git a/app/src/main/java/org/mifos/mobile/ui/about/AboutUsViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/about/AboutUsViewModel.kt index 1a134bb6c..f7d8d70b9 100644 --- a/app/src/main/java/org/mifos/mobile/ui/about/AboutUsViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/about/AboutUsViewModel.kt @@ -6,8 +6,8 @@ import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import org.mifos.mobile.MifosSelfServiceApp.Companion.context import org.mifos.mobile.R -import org.mifos.mobile.models.AboutUsItem -import org.mifos.mobile.ui.enums.AboutUsListItemId +import org.mifos.mobile.core.model.entity.AboutUsItem +import org.mifos.mobile.core.model.enums.AboutUsListItemId import java.util.* import javax.inject.Inject @@ -22,7 +22,7 @@ class AboutUsViewModel @Inject constructor() : ViewModel() { context?.getString(R.string.copy_right_mifos) ?.replace("%1\$s", currentYear.toString()) - val aboutUsItems: List = listOf( + val aboutUsItems = listOf( AboutUsItem( title = context?.getString(R.string.app_version_text), itemId = AboutUsListItemId.APP_VERSION_TEXT diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/account/AccountsFragment.kt similarity index 99% rename from app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt rename to app/src/main/java/org/mifos/mobile/ui/account/AccountsFragment.kt index c2911c495..dda43b321 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/AccountsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/account/AccountsFragment.kt @@ -1,5 +1,6 @@ -package org.mifos.mobile.ui.fragments +package org.mifos.mobile.ui.account +/* import android.content.Intent import android.os.Bundle import android.os.Parcelable @@ -28,8 +29,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 org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedArrayListFromParcelable import java.util.* /** @@ -548,3 +548,4 @@ class AccountsFragment : BaseFragment(), OnRefreshListener { } } } +*/ \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/account/AccountsScreen.kt b/app/src/main/java/org/mifos/mobile/ui/account/AccountsScreen.kt new file mode 100644 index 000000000..c2538be2f --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/account/AccountsScreen.kt @@ -0,0 +1,244 @@ +package org.mifos.mobile.ui.account + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.MifosErrorComponent +import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay +import org.mifos.mobile.core.common.Network +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import org.mifos.mobile.core.model.entity.accounts.loan.LoanAccount +import org.mifos.mobile.core.model.entity.accounts.savings.SavingAccount +import org.mifos.mobile.core.model.entity.accounts.share.ShareAccount +import org.mifos.mobile.core.ui.component.EmptyDataView +import org.mifos.mobile.core.ui.theme.MifosMobileTheme + + +@Composable +fun AccountsScreen( + viewModel: AccountsViewModel = hiltViewModel(), + accountType: String, + onItemClick: (accountType: String, accountId: Long) -> Unit +) { + val context = LocalContext.current + val uiState by viewModel.accountsUiState.collectAsStateWithLifecycle() + val isRefreshing by viewModel.isRefreshing.collectAsStateWithLifecycle() + val isSearching by viewModel.isSearching.collectAsStateWithLifecycle() + val isFiltered by viewModel.isFiltered.collectAsStateWithLifecycle() + val searchQuery by viewModel.searchQuery.collectAsStateWithLifecycle() + val filterList by viewModel.filterList.collectAsStateWithLifecycle() + + LaunchedEffect(key1 = Unit) { + viewModel.loadAccounts(accountType) + } + + AccountsScreen( + uiState = uiState, + isSearching = isSearching, + isFiltered = isFiltered, + onRetry = { viewModel.loadAccounts(accountType) }, + isRefreshing = isRefreshing, + onRefresh = { viewModel.refresh(accountType) }, + searchSavingsAccountList = { accountsList -> + viewModel.searchInSavingsList( + accountsList, + searchQuery + ) + }, + searchLoanAccountList = { accountsList -> + viewModel.searchInLoanList( + accountsList, + searchQuery + ) + }, + searchShareAccountList = { accountsList -> + viewModel.searchInSharesList( + accountsList, + searchQuery + ) + }, + filterSavingsAccountList = { accountsList -> + viewModel.getFilterSavingsAccountList( + accountsList = accountsList, + filterList = filterList, + context = context + ) + }, + filterLoanAccountList = { accountsList -> + viewModel.getFilterLoanAccountList( + accountsList = accountsList, + filterList = filterList, + context = context + ) + }, + filterShareAccountList = { accountsList -> + viewModel.getFilterShareAccountList( + accountsList = accountsList, + filterList = filterList, + context = context + ) + }, + onItemClick = { accType, accountId -> onItemClick.invoke(accType, accountId) }, + ) +} + +@OptIn(ExperimentalMaterialApi::class) +@Composable +fun AccountsScreen( + uiState: AccountsUiState, + onRetry: () -> Unit, + isRefreshing: Boolean, + onRefresh: () -> Unit, + isSearching: Boolean, + isFiltered: Boolean, + searchSavingsAccountList: (accountsList: List) -> List, + searchLoanAccountList: (accountsList: List) -> List, + searchShareAccountList: (accountsList: List) -> List, + filterSavingsAccountList: (accountsList: List) -> List, + filterLoanAccountList: (accountsList: List) -> List, + filterShareAccountList: (accountsList: List) -> List, + onItemClick: (accountType: String, accountId: Long) -> Unit, +) { + val context = LocalContext.current + val pullRefreshState = rememberPullRefreshState( + refreshing = isRefreshing, + onRefresh = onRefresh + ) + + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.Center + ) { + + Box(modifier = Modifier.pullRefresh(pullRefreshState)) + { + when (uiState) { + is AccountsUiState.Error -> { + MifosErrorComponent( + isNetworkConnected = Network.isConnected(context), + isRetryEnabled = true, + onRetry = onRetry + ) + } + + is AccountsUiState.Loading -> { + MifosProgressIndicatorOverlay() + } + + is AccountsUiState.ShowSavingsAccounts -> { + if ((uiState.savingAccounts.isNullOrEmpty())) { + EmptyDataView( + icon = R.drawable.ic_error_black_24dp, + error = R.string.empty_savings_accounts, + modifier = Modifier.fillMaxSize() + ) + } else { + SavingsAccountContent( + accountsList = uiState.savingAccounts, + isSearching = isSearching, + isFiltered = isFiltered, + getUpdatedSearchList = searchSavingsAccountList, + onItemClick = onItemClick, + getUpdatedFilterList = filterSavingsAccountList + ) + } + } + + is AccountsUiState.ShowLoanAccounts -> { + if ((uiState.loanAccounts.isNullOrEmpty())) { + EmptyDataView( + icon = R.drawable.ic_error_black_24dp, + error = R.string.empty_loan_accounts, + modifier = Modifier.fillMaxSize() + ) + } else { + LoanAccountContent( + accountsList = uiState.loanAccounts, + isSearching = isSearching, + isFiltered = isFiltered, + getUpdatedSearchList = searchLoanAccountList, + onItemClick = onItemClick, + getUpdatedFilterList = filterLoanAccountList + ) + } + } + + is AccountsUiState.ShowShareAccounts -> { + if ((uiState.shareAccounts.isNullOrEmpty())) { + EmptyDataView( + icon = R.drawable.ic_error_black_24dp, + error = R.string.empty_share_accounts, + modifier = Modifier.fillMaxSize() + ) + } else { + AccountScreenShareContent( + accountsList = uiState.shareAccounts, + isSearching = isSearching, + isFiltered = isFiltered, + getUpdatedSearchList = searchShareAccountList, + getUpdatedFilterList = filterShareAccountList + ) + } + } + } + + PullRefreshIndicator( + refreshing = isRefreshing, + state = pullRefreshState, + modifier = Modifier.align(Alignment.TopCenter) + ) + } + } +} + +class AccountsScreenPreviewProvider : PreviewParameterProvider { + + override val values: Sequence + get() = sequenceOf( + AccountsUiState.Loading, + AccountsUiState.Error, + AccountsUiState.ShowLoanAccounts(listOf()), + AccountsUiState.ShowShareAccounts(listOf()), + AccountsUiState.ShowSavingsAccounts(listOf()), + ) +} + +@Preview(showSystemUi = true) +@Composable +private fun AccountSavingsScreenPreview( + @PreviewParameter(AccountsScreenPreviewProvider::class) accountUiState: AccountsUiState +) { + MifosMobileTheme { + AccountsScreen( + uiState = accountUiState, + isSearching = true, + isFiltered = true, + onRetry = { }, + isRefreshing = true, + onRefresh = { }, + filterSavingsAccountList = { _ -> listOf() }, + filterLoanAccountList = { _ -> listOf() }, + filterShareAccountList = { _ -> listOf() }, + searchLoanAccountList = { _ -> listOf() }, + searchSavingsAccountList = { _ -> listOf() }, + searchShareAccountList = { _ -> listOf() }, + onItemClick = { _, _ -> }, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/AccountsViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/account/AccountsViewModel.kt similarity index 65% rename from app/src/main/java/org/mifos/mobile/viewModels/AccountsViewModel.kt rename to app/src/main/java/org/mifos/mobile/ui/account/AccountsViewModel.kt index f9a604f4c..d07f90e37 100644 --- a/app/src/main/java/org/mifos/mobile/viewModels/AccountsViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/account/AccountsViewModel.kt @@ -1,5 +1,6 @@ -package org.mifos.mobile.viewModels +package org.mifos.mobile.ui.account +import android.content.Context import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -7,17 +8,19 @@ import io.reactivex.Observable import io.reactivex.functions.Predicate import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.mifos.mobile.models.CheckboxStatus -import org.mifos.mobile.models.accounts.loan.LoanAccount -import org.mifos.mobile.models.accounts.savings.SavingAccount -import org.mifos.mobile.models.accounts.share.ShareAccount -import org.mifos.mobile.repositories.AccountsRepository -import org.mifos.mobile.repositories.HomeRepository +import org.mifos.mobile.core.common.Constants import org.mifos.mobile.utils.AccountsFilterUtil -import org.mifos.mobile.utils.AccountsUiState -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.core.data.repositories.AccountsRepository +import org.mifos.mobile.core.data.repositories.HomeRepository +import org.mifos.mobile.core.model.entity.CheckboxStatus +import org.mifos.mobile.core.model.entity.accounts.loan.LoanAccount +import org.mifos.mobile.core.model.entity.accounts.savings.SavingAccount +import org.mifos.mobile.core.model.entity.accounts.share.ShareAccount +import org.mifos.mobile.utils.StatusUtils import java.util.* import javax.inject.Inject @@ -30,6 +33,140 @@ class AccountsViewModel @Inject constructor( private val _accountsUiState = MutableStateFlow(AccountsUiState.Loading) val accountsUiState: StateFlow = _accountsUiState + private val _isRefreshing = MutableStateFlow(false) + val isRefreshing: StateFlow get() = _isRefreshing.asStateFlow() + + private val _isSearching = MutableStateFlow(false) + val isSearching: StateFlow get() = _isSearching.asStateFlow() + + private val _searchQuery = MutableStateFlow("") + val searchQuery: StateFlow = _searchQuery.asStateFlow() + + private val _isFiltered = MutableStateFlow(false) + val isFiltered: StateFlow get() = _isFiltered.asStateFlow() + + private val _filterList = MutableStateFlow(emptyList()) + val filterList: StateFlow> = _filterList.asStateFlow() + + + fun refresh(accountType: String?) { + when (accountType) { + Constants.SAVINGS_ACCOUNTS -> { + _isRefreshing.value = true + loadAccounts(Constants.SAVINGS_ACCOUNTS) + } + Constants.LOAN_ACCOUNTS -> { + _isRefreshing.value = true + loadAccounts(Constants.LOAN_ACCOUNTS) + } + Constants.SHARE_ACCOUNTS -> { + _isRefreshing.value = true + loadAccounts(Constants.SHARE_ACCOUNTS) + } + } + } + + fun updateSearchQuery(query: String) { + _isSearching.update { true } + _searchQuery.update { query } + } + + fun stoppedSearching() { + _searchQuery.update { "" } + _isSearching.update { false } + } + + fun setFilterList( + checkBoxList: List, + currentPage: Int, + context: Context + ){ + if(checkBoxList.isEmpty()) { + when (currentPage) { + 0 -> { + _isFiltered.update { false } + _filterList.update { StatusUtils.getSavingsAccountStatusList(context) } + } + 1 -> { + _isFiltered.update { false } + _filterList.update { StatusUtils.getLoanAccountStatusList(context) } + } + 2 -> { + _isFiltered.update { false } + _filterList.update { StatusUtils.getShareAccountStatusList(context) } + } + } + }else { + var isChanged = false + for( checkBox in checkBoxList ) + { + if(checkBox.isChecked) + isChanged = true + } + if(isChanged) { + _isFiltered.update { true } + _filterList.update { checkBoxList } + } + else { + _isFiltered.update { false } + _filterList.update { checkBoxList } + } + } + } + + fun getFilterLoanAccountList( + accountsList: List, + filterList: List, + context: Context + ): List { + val uniqueAccountsMap: MutableMap = mutableMapOf() + + for (filter in filterList) { + if (filter.isChecked) { + val filteredAccounts = getFilteredLoanAccount(accountsList, filter, AccountsFilterUtil.getFilterStrings(context = context)) + for (account in filteredAccounts) { + val identifier = getUniqueIdentifierForLoanAccount(account) + uniqueAccountsMap[identifier] = account + } + } + } + + return uniqueAccountsMap.values.toList() + } + + fun getUniqueIdentifierForLoanAccount(account: LoanAccount): String { + return account.accountNo ?: account.loanProductId.toString() + } + + fun getFilterSavingsAccountList( + accountsList: List, + filterList: List, + context: Context + ): List { + + val newList : MutableList = mutableListOf() + for( filter in filterList) + { + if( filter.isChecked ) + newList.addAll( getFilteredSavingsAccount(accountsList,filter, AccountsFilterUtil.getFilterStrings(context = context))) + } + return newList + } + + fun getFilterShareAccountList( + accountsList: List, + filterList: List, + context: Context + ): List { + val newList : MutableList = mutableListOf() + for( filter in filterList) + { + if(filter.isChecked) + newList.addAll(getFilteredShareAccount(accountsList,filter, AccountsFilterUtil.getFilterStrings(context = context))) + } + return newList + } + /** * Loads savings, loan and share accounts associated with the Client from the server * and notifies the view to display it. And in case of any error during fetching the required @@ -71,6 +208,7 @@ class AccountsViewModel @Inject constructor( Constants.SHARE_ACCOUNTS -> _accountsUiState.value = AccountsUiState.ShowShareAccounts(clientAccounts.shareAccounts) } + _isRefreshing.emit(false) } } @@ -86,7 +224,7 @@ class AccountsViewModel @Inject constructor( fun searchInSavingsList( accounts: List?, input: String?, - ): List { + ): List { return Observable.fromIterable(accounts) .filter { (accountNo, productName) -> input?.lowercase(Locale.ROOT) @@ -95,7 +233,7 @@ class AccountsViewModel @Inject constructor( accountNo?.lowercase(Locale.ROOT) ?.contains(it) } == true - }.toList().blockingGet() + }.toList().blockingGet().filterNotNull() } /** @@ -108,7 +246,7 @@ class AccountsViewModel @Inject constructor( fun searchInLoanList( accounts: List?, input: String?, - ): List? { + ): List { return Observable.fromIterable(accounts) .filter { (_, _, _, accountNo, productName) -> input?.lowercase(Locale.ROOT) @@ -117,7 +255,7 @@ class AccountsViewModel @Inject constructor( accountNo?.lowercase(Locale.ROOT) ?.contains(it) } == true - }.toList().blockingGet() + }.toList().blockingGet().filterNotNull() } /** @@ -130,7 +268,7 @@ class AccountsViewModel @Inject constructor( fun searchInSharesList( accounts: Collection?, input: String?, - ): List? { + ): List { return Observable.fromIterable(accounts) .filter { (accountNo, _, _, _, productName) -> input?.lowercase(Locale.ROOT) @@ -139,7 +277,7 @@ class AccountsViewModel @Inject constructor( accountNo?.lowercase(Locale.ROOT) ?.contains(it) } == true - }.toList().blockingGet() + }.toList().blockingGet().filterNotNull() } /** @@ -164,7 +302,7 @@ class AccountsViewModel @Inject constructor( accounts: List?, status: CheckboxStatus?, accountsFilterUtil: AccountsFilterUtil - ): Collection? { + ): Collection { return Observable.fromIterable(accounts) .filter( Predicate { (_, _, _, _, _, _, _, _, _, _, _, status1) -> @@ -191,7 +329,7 @@ class AccountsViewModel @Inject constructor( } false }, - ).toList().blockingGet() + ).toList().blockingGet().filterNotNull() } /** @@ -205,7 +343,7 @@ class AccountsViewModel @Inject constructor( accounts: List?, status: CheckboxStatus?, accountsFilterUtil: AccountsFilterUtil - ): Collection? { + ): Collection { return Observable.fromIterable(accounts) .filter( Predicate { (_, _, _, _, _, _, _, _, _, _, _, status1, _, _, _, _, _, inArrears) -> @@ -240,7 +378,7 @@ class AccountsViewModel @Inject constructor( } false }, - ).toList().blockingGet() + ).toList().blockingGet().filterNotNull() } /** @@ -254,7 +392,7 @@ class AccountsViewModel @Inject constructor( accounts: List?, status: CheckboxStatus?, accountsFilterUtil: AccountsFilterUtil - ): Collection? { + ): Collection { return Observable.fromIterable(accounts) .filter( Predicate { (_, _, _, _, _, _, status1) -> @@ -278,6 +416,15 @@ class AccountsViewModel @Inject constructor( } false }, - ).toList().blockingGet() + ).toList().blockingGet().filterNotNull() } + +} + +sealed class AccountsUiState { + data object Error : AccountsUiState() + data object Loading : AccountsUiState() + data class ShowSavingsAccounts(val savingAccounts: List?) : AccountsUiState() + data class ShowLoanAccounts(val loanAccounts: List?) : AccountsUiState() + data class ShowShareAccounts(val shareAccounts: List?) : AccountsUiState() } \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/account/LoanAccountContent.kt b/app/src/main/java/org/mifos/mobile/ui/account/LoanAccountContent.kt new file mode 100644 index 000000000..f1be20ad0 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/account/LoanAccountContent.kt @@ -0,0 +1,180 @@ +package org.mifos.mobile.ui.account + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import org.mifos.mobile.R +import org.mifos.mobile.utils.AccountTypeItemIndicator +import org.mifos.mobile.core.model.entity.accounts.loan.LoanAccount +import org.mifos.mobile.core.common.utils.CurrencyUtil +import org.mifos.mobile.core.common.utils.DateHelper +@Composable +fun LoanAccountContent( + accountsList: List, + isSearching: Boolean, + getUpdatedSearchList: (accountsList: List) -> List, + isFiltered: Boolean, + getUpdatedFilterList: (accountsList: List) -> List, + onItemClick: (accountType: String, accountId: Long) -> Unit, +) { + + var accounts by rememberSaveable { + mutableStateOf(accountsList) + } + + accounts = when { + isFiltered && isSearching -> { + getUpdatedSearchList(getUpdatedFilterList(accountsList)) + } + + isSearching -> { + getUpdatedSearchList(accountsList) + } + + isFiltered -> { + getUpdatedFilterList(accountsList) + } + + else -> { + accountsList + } + } + + val lazyColumnState = rememberLazyListState() + + LazyColumn( + modifier = Modifier.fillMaxSize(), + state = lazyColumnState + ) { + items(items = accounts) { loanAccount -> + AccountScreenLoanListItem( + loanAccount = loanAccount, + onItemClick = onItemClick + ) + } + } +} + +@Composable +fun AccountScreenLoanListItem( + loanAccount: LoanAccount, + onItemClick: (accountType: String, accountId: Long) -> Unit +) { + val context = LocalContext.current + + val (color, stringResource, numColor) = when { + loanAccount.status?.active == true && loanAccount.inArrears == true -> { + Triple( + colorResource(R.color.red), + "${stringResource(id = R.string.disbursement)} ${DateHelper.getDateAsString(loanAccount.timeline?.actualDisbursementDate)}", + colorResource(R.color.red) + ) + } + loanAccount.status?.active == true -> { + Triple( + colorResource(R.color.deposit_green), + "${stringResource(id = R.string.disbursement)} ${DateHelper.getDateAsString(loanAccount.timeline?.actualDisbursementDate)}", + colorResource(R.color.deposit_green) + ) + } + loanAccount.status?.waitingForDisbursal == true -> { + Triple( + colorResource(R.color.blue), + "${stringResource(id = R.string.approved)} ${DateHelper.getDateAsString(loanAccount.timeline?.approvedOnDate)}", + null + ) + } + loanAccount.status?.pendingApproval == true -> { + Triple( + colorResource(R.color.light_yellow), + "${stringResource(id = R.string.submitted)} ${DateHelper.getDateAsString(loanAccount.timeline?.submittedOnDate)}", + null + ) + } + loanAccount.status?.overpaid == true -> { + Triple( + colorResource(R.color.purple), + "${stringResource(id = R.string.approved)} ${DateHelper.getDateAsString(loanAccount.timeline?.actualDisbursementDate)}", + colorResource(R.color.purple) + ) + } + loanAccount.status?.closed == true -> { + Triple( + colorResource(R.color.black), + "${stringResource(id = R.string.closed)} ${DateHelper.getDateAsString(loanAccount.timeline?.closedOnDate)}", + null + ) + } + else -> { + Triple( + colorResource(R.color.gray_dark), + "${stringResource(id = R.string.withdrawn)} ${DateHelper.getDateAsString(loanAccount.timeline?.withdrawnOnDate)}", + null + ) + } + } + + Row( + modifier = Modifier.clickable { + onItemClick.invoke(org.mifos.mobile.core.common.Constants.LOAN_ACCOUNTS, loanAccount.id) + }, + verticalAlignment = Alignment.CenterVertically + ) { + AccountTypeItemIndicator(color) + + Column(modifier = Modifier.padding(all = 12.dp)) { + loanAccount.accountNo?.let { + Text( + text = it, + style = MaterialTheme.typography.bodyLarge + ) + } + + loanAccount.productName?.let { + Text( + text = it, + style = MaterialTheme.typography.labelLarge, + color = colorResource(id = R.color.gray_dark) + ) + } + + Text( + text = stringResource, + style = MaterialTheme.typography.labelLarge, + color = colorResource(id = R.color.gray_dark), + ) + } + + Spacer(Modifier.weight(1f)) + + numColor?.let { + val amountBalance = if (loanAccount.loanBalance != 0.0) loanAccount.loanBalance else 0.0 + Text( + text = CurrencyUtil.formatCurrency(context, amountBalance), + modifier = Modifier + .align(Alignment.CenterVertically) + .padding(end = 16.dp), + color = it + ) + } + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/account/SavingsAccountContent.kt b/app/src/main/java/org/mifos/mobile/ui/account/SavingsAccountContent.kt new file mode 100644 index 000000000..182748682 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/account/SavingsAccountContent.kt @@ -0,0 +1,172 @@ +package org.mifos.mobile.ui.account + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import org.mifos.mobile.R +import org.mifos.mobile.utils.AccountTypeItemIndicator +import org.mifos.mobile.core.model.entity.accounts.savings.SavingAccount +import org.mifos.mobile.core.common.utils.CurrencyUtil +import org.mifos.mobile.core.common.utils.DateHelper + +@Composable +fun SavingsAccountContent( + accountsList: List, + isSearching: Boolean, + getUpdatedSearchList: (accountsList: List) -> List, + isFiltered: Boolean, + getUpdatedFilterList: (accountsList: List) -> List, + onItemClick: (accountType: String, accountId: Long) -> Unit, +) { + + var accounts by rememberSaveable { + mutableStateOf(accountsList) + } + + accounts = when { + isFiltered && isSearching -> { + getUpdatedSearchList(getUpdatedFilterList(accountsList)) + } + + isSearching -> { + getUpdatedSearchList(accountsList) + } + + isFiltered -> { + getUpdatedFilterList(accountsList) + } + + else -> { + accountsList + } + } + + val lazyColumnState = rememberLazyListState() + + LazyColumn( + modifier = Modifier.fillMaxSize(), + state = lazyColumnState + ) { + items(items = accounts) { savingAccount -> + AccountScreenSavingsListItem( + savingAccount = savingAccount, + onItemClick = onItemClick + ) + } + } +} + +@Composable +fun AccountScreenSavingsListItem( + savingAccount: SavingAccount, + onItemClick: (accountType: String, accountId: Long) -> Unit +) { + val context = LocalContext.current + + val (color, stringResource, numColor) = when { + savingAccount.status?.active == true -> { + Triple( + colorResource(R.color.deposit_green), + DateHelper.getDateAsString(savingAccount.lastActiveTransactionDate), + colorResource(R.color.deposit_green) + ) + } + savingAccount.status?.approved == true -> { + Triple( + colorResource(R.color.light_green), + "${stringResource(id = R.string.approved)} ${DateHelper.getDateAsString(savingAccount.timeLine?.approvedOnDate)}", + null + ) + } + savingAccount.status?.submittedAndPendingApproval == true -> { + Triple( + colorResource(R.color.light_yellow), + "${stringResource(id = R.string.submitted)} ${DateHelper.getDateAsString(savingAccount.timeLine?.submittedOnDate)}", + null + ) + } + savingAccount.status?.matured == true -> { + Triple( + colorResource(R.color.red_light), + DateHelper.getDateAsString(savingAccount.lastActiveTransactionDate), + colorResource(R.color.red_light) + ) + } + else -> { + Triple( + colorResource(R.color.light_yellow), + "${stringResource(id = R.string.closed)} ${DateHelper.getDateAsString(savingAccount?.timeLine?.closedOnDate)}", + null + ) + } + } + + Row( + modifier = Modifier.clickable { + onItemClick.invoke(org.mifos.mobile.core.common.Constants.SAVINGS_ACCOUNTS, savingAccount.id) + }, + verticalAlignment = Alignment.CenterVertically + ) { + AccountTypeItemIndicator(color) + + Column(modifier = Modifier.padding(all = 12.dp)) { + savingAccount.accountNo?.let { + Text( + text = it, + style = MaterialTheme.typography.bodyLarge + ) + } + + savingAccount.productName?.let { + Text( + text = it, + style = MaterialTheme.typography.labelLarge, + color = colorResource(id = R.color.gray_dark), + ) + } + + Text( + text = stringResource, + style = MaterialTheme.typography.labelLarge, + color = colorResource(id = R.color.gray_dark), + ) + } + + Spacer(Modifier.weight(1f)) + + numColor?.let { + val amountBalance = context.getString( + R.string.string_and_string, + savingAccount.currency?.displaySymbol ?: savingAccount.currency?.code, + CurrencyUtil.formatCurrency(context, savingAccount.accountBalance) + ) + + Text( + text = amountBalance, + modifier = Modifier + .align(Alignment.CenterVertically) + .padding(end = 16.dp), + color = it + ) + } + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/account/ShareAccountContent.kt b/app/src/main/java/org/mifos/mobile/ui/account/ShareAccountContent.kt new file mode 100644 index 000000000..a1902216b --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/account/ShareAccountContent.kt @@ -0,0 +1,151 @@ +package org.mifos.mobile.ui.account + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.accounts.share.ShareAccount +import org.mifos.mobile.utils.AccountTypeItemIndicator + +@Composable +fun AccountScreenShareContent( + accountsList: List, + isSearching: Boolean, + getUpdatedSearchList: (accountsList: List) -> List, + isFiltered: Boolean, + getUpdatedFilterList: (accountsList: List) -> List +) { + + var accounts by rememberSaveable { + mutableStateOf(accountsList) + } + + when { + isFiltered && isSearching -> { + accounts = getUpdatedSearchList(getUpdatedFilterList(accountsList)) + } + + isSearching -> { + accounts = getUpdatedSearchList(accountsList) + } + + isFiltered -> { + accounts = getUpdatedFilterList(accountsList) + } + + else -> { + accounts = accountsList + } + } + + val lazyColumnState = rememberLazyListState() + + LazyColumn( + modifier = Modifier.fillMaxSize(), + state = lazyColumnState + ) { + items(items = accounts) { shareAccount -> + AccountScreenShareListItem( + shareAccount = shareAccount + ) + } + } +} + +@Composable +fun AccountScreenShareListItem( + shareAccount: ShareAccount +) { + val (color, setSharingAccountDetail) = when { + shareAccount.status?.active == true -> { + Pair(colorResource(R.color.deposit_green), true) + } + shareAccount.status?.approved == true -> { + Pair(colorResource(R.color.light_green), false) + } + shareAccount.status?.submittedAndPendingApproval == true -> { + Pair(colorResource(R.color.light_yellow), false) + } + else -> { + Pair(colorResource(R.color.light_blue), false) + } + } + + Row(verticalAlignment = Alignment.CenterVertically) { + AccountTypeItemIndicator(color) + + Column(modifier = Modifier.padding(all = 12.dp)) { + shareAccount.accountNo?.let { + Text( + text = it, + style = MaterialTheme.typography.bodyLarge + ) + } + + shareAccount.productName?.let { + Text( + text = it, + style = MaterialTheme.typography.labelLarge, + color = colorResource(id = R.color.gray_dark), + ) + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Row { + Text( + text = stringResource(id = R.string.pending), + style = MaterialTheme.typography.labelLarge, + color = colorResource(id = R.color.gray_dark), + ) + + Text( + text = " ${shareAccount.totalPendingForApprovalShares}", + style = MaterialTheme.typography.bodyLarge, + color = colorResource(id = R.color.black), + ) + } + + if (setSharingAccountDetail) { + Row { + Text( + text = stringResource(id = R.string.approved), + style = MaterialTheme.typography.labelLarge, + color = colorResource(id = R.color.gray_dark), + ) + + Text( + modifier = Modifier.padding(end = 12.dp), + text = " ${shareAccount.totalApprovedShares}", + style = MaterialTheme.typography.bodyLarge, + color = colorResource(id = R.color.black), + ) + } + } + } + } + Spacer(Modifier.weight(1f)) + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/BiometricAuthentication.kt b/app/src/main/java/org/mifos/mobile/ui/activities/BiometricAuthentication.kt index 3480db390..33bb6ae89 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/BiometricAuthentication.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/BiometricAuthentication.kt @@ -10,7 +10,7 @@ import androidx.biometric.BiometricPrompt import androidx.core.content.ContextCompat import androidx.fragment.app.FragmentActivity import org.mifos.mobile.R -import org.mifos.mobile.ui.enums.BiometricCapability +import org.mifos.mobile.core.model.enums.BiometricCapability open class BiometricAuthentication( val context: FragmentActivity, 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 b95b53147..db918d3fc 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 @@ -26,16 +26,15 @@ import com.google.android.material.imageview.ShapeableImageView import com.google.android.material.navigation.NavigationView import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R -import org.mifos.mobile.api.local.PreferencesHelper import org.mifos.mobile.databinding.ActivityHomeBinding import org.mifos.mobile.databinding.NavDrawerHeaderBinding -import org.mifos.mobile.models.client.Client import org.mifos.mobile.ui.about.AboutUsActivity import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.ui.beneficiary_list.BeneficiaryListComposeFragment +import org.mifos.mobile.ui.client_accounts.ClientAccountsComposeFragment import org.mifos.mobile.ui.client_charge.ClientChargeComposeFragment -import org.mifos.mobile.ui.enums.AccountType -import org.mifos.mobile.ui.enums.ChargeType -import org.mifos.mobile.ui.fragments.* +import org.mifos.mobile.core.model.enums.AccountType +import org.mifos.mobile.core.model.enums.ChargeType import org.mifos.mobile.ui.getThemeAttributeColor import org.mifos.mobile.ui.help.HelpActivity import org.mifos.mobile.ui.home.HomeOldFragment @@ -43,15 +42,19 @@ import org.mifos.mobile.ui.login.LoginActivity import org.mifos.mobile.ui.third_party_transfer.ThirdPartyTransferComposeFragment import org.mifos.mobile.ui.notification.NotificationFragment import org.mifos.mobile.ui.recent_transactions.RecentTransactionsComposeFragment -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.ui.transfer_process.TransferProcessComposeFragment +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.model.entity.client.Client import org.mifos.mobile.utils.TextDrawable import org.mifos.mobile.utils.Toaster 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 org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable import javax.inject.Inject +import org.mifos.mobile.ui.settings.SettingsActivity + /** * @author Vishwajeet @@ -101,7 +104,7 @@ class HomeActivity : viewModel.userImage showUserImage(null) } else { - client = savedInstanceState.getCheckedParcelable(Client::class.java, Constants.USER_DETAILS) + client = savedInstanceState.getCheckedParcelable(Client::class.java, org.mifos.mobile.core.common.Constants.USER_DETAILS) viewModel.setUserProfile(preferencesHelper?.userProfileImage) showUserDetails(client) } @@ -134,7 +137,7 @@ class HomeActivity : override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - outState.putParcelable(Constants.USER_DETAILS, client) + outState.putParcelable(org.mifos.mobile.core.common.Constants.USER_DETAILS, client) } override fun onPause() { @@ -148,7 +151,7 @@ class HomeActivity : if (!isReceiverRegistered) { LocalBroadcastManager.getInstance(this).registerReceiver( registerReceiver, - IntentFilter(Constants.REGISTER_ON_SERVER), + IntentFilter(org.mifos.mobile.core.common.Constants.REGISTER_ON_SERVER), ) isReceiverRegistered = true } @@ -178,7 +181,7 @@ class HomeActivity : R.id.item_accounts -> { hideToolbarElevation() replaceFragment( - ClientAccountsFragment.newInstance(AccountType.SAVINGS), + ClientAccountsComposeFragment.newInstance(AccountType.SAVINGS), true, R.id.container, ) @@ -203,7 +206,7 @@ class HomeActivity : ) R.id.item_beneficiaries -> replaceFragment( - BeneficiaryListFragment.newInstance(), + BeneficiaryListComposeFragment.newInstance(), true, R.id.container, ) @@ -387,8 +390,7 @@ class HomeActivity : doubleBackToExitPressedOnce = true Toaster.show(findViewById(android.R.id.content), getString(R.string.exit_message)) Handler().postDelayed({ doubleBackToExitPressedOnce = false }, 2000) - } else if (fragment is TransferProcessFragment) { - fragment.cancelTransferProcess() + } else if (fragment is TransferProcessComposeFragment) { } if (stackCount() != 0) { @@ -405,7 +407,7 @@ class HomeActivity : setNavigationViewSelectedItem(R.id.item_home) } - is ClientAccountsFragment -> { + is ClientAccountsComposeFragment -> { hideToolbarElevation() setNavigationViewSelectedItem(R.id.item_accounts) } @@ -422,7 +424,7 @@ class HomeActivity : setNavigationViewSelectedItem(R.id.item_third_party_transfer) } - is BeneficiaryListFragment -> { + is BeneficiaryListComposeFragment -> { setNavigationViewSelectedItem(R.id.item_beneficiaries) } } @@ -455,7 +457,7 @@ class HomeActivity : private val registerReceiver: BroadcastReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { - val token = intent.getStringExtra(Constants.TOKEN) + val token = intent.getStringExtra(org.mifos.mobile.core.common.Constants.TOKEN) token?.let { viewModel.registerNotification(it) } } } diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/LoanAccountContainerActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/LoanAccountContainerActivity.kt index 39e933a2c..54b751f89 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/LoanAccountContainerActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/LoanAccountContainerActivity.kt @@ -1,12 +1,10 @@ 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.loan_account.LoanAccountsDetailFragment -import org.mifos.mobile.utils.Constants /* ~This project is licensed under the open source MPL V2. @@ -21,7 +19,7 @@ class LoanAccountContainerActivity : BaseActivity() { super.onCreate(savedInstanceState) binding = ActivityContainerBinding.inflate(layoutInflater) setContentView(binding.root) - loanId = intent?.extras?.getLong(Constants.LOAN_ID)!! + loanId = intent?.extras?.getLong(org.mifos.mobile.core.common.Constants.LOAN_ID)!! replaceFragment(LoanAccountsDetailFragment.newInstance(loanId), false, R.id.container) showBackButton() } diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/LoanApplicationActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/LoanApplicationActivity.kt index 699be03e2..d236df960 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/LoanApplicationActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/LoanApplicationActivity.kt @@ -4,7 +4,7 @@ import android.os.Bundle import org.mifos.mobile.R import org.mifos.mobile.databinding.ActivityLoanApplicationBinding import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.LoanState +import org.mifos.mobile.core.model.enums.LoanState import org.mifos.mobile.ui.loan_account_application.LoanApplicationFragment class LoanApplicationActivity : BaseActivity() { diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/PassCodeActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/PassCodeActivity.kt index 46065bf22..8648c13f9 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/PassCodeActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/PassCodeActivity.kt @@ -14,10 +14,10 @@ import butterknife.OnClick import com.mifos.mobile.passcode.MifosPassCodeActivity import com.mifos.mobile.passcode.utils.EncryptionUtil import org.mifos.mobile.R -import org.mifos.mobile.ui.enums.BiometricCapability +import org.mifos.mobile.core.model.enums.BiometricCapability import org.mifos.mobile.ui.login.LoginActivity import org.mifos.mobile.utils.CheckSelfPermissionAndRequest -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.core.common.Constants import org.mifos.mobile.utils.MaterialDialog import org.mifos.mobile.utils.Toaster @@ -81,12 +81,12 @@ class PassCodeActivity : MifosPassCodeActivity() { CheckSelfPermissionAndRequest.requestPermission( this, Manifest.permission.READ_PHONE_STATE, - Constants.PERMISSIONS_REQUEST_READ_PHONE_STATE, + org.mifos.mobile.core.common.Constants.PERMISSIONS_REQUEST_READ_PHONE_STATE, resources.getString( R.string.dialog_message_phone_state_permission_denied_prompt, ), resources.getString(R.string.dialog_message_phone_state_permission_never_ask_again), - Constants.PERMISSIONS_READ_PHONE_STATE_STATUS, + org.mifos.mobile.core.common.Constants.PERMISSIONS_READ_PHONE_STATE_STATUS, ) } diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/SavingsAccountApplicationActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/SavingsAccountApplicationActivity.kt index 44112fdd1..391b29027 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/SavingsAccountApplicationActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/SavingsAccountApplicationActivity.kt @@ -4,7 +4,7 @@ import android.os.Bundle import org.mifos.mobile.R import org.mifos.mobile.databinding.ActivitySavingsAccountApplicationBinding import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.SavingsAccountState +import org.mifos.mobile.core.model.enums.SavingsAccountState import org.mifos.mobile.ui.savings_account_application.SavingsAccountApplicationFragment.Companion.newInstance /* 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 7367d0a61..d932999ac 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,12 +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.savings_account.SavingAccountsDetailFragment -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.core.common.Constants /** * Created by Rajan Maurya on 05/03/17. diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/SplashActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/SplashActivity.kt index 857a4b441..8ab4bd8a7 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/SplashActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/SplashActivity.kt @@ -5,7 +5,7 @@ import android.os.Bundle import com.mifos.mobile.passcode.utils.PasscodePreferencesHelper import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.login.LoginActivity -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.core.common.Constants /* * Created by saksham on 01/June/2018 diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/base/BaseActivity.kt b/app/src/main/java/org/mifos/mobile/ui/activities/base/BaseActivity.kt index cae4d31d2..acf1aa3bc 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/base/BaseActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/activities/base/BaseActivity.kt @@ -15,9 +15,9 @@ import androidx.fragment.app.FragmentManager import com.mifos.mobile.passcode.BasePassCodeActivity import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R +import org.mifos.mobile.core.common.utils.LanguageHelper import org.mifos.mobile.ui.activities.PassCodeActivity import org.mifos.mobile.ui.views.BaseActivityCallback -import org.mifos.mobile.utils.LanguageHelper /** * @author ishan diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/AccountsSpinnerAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/AccountsSpinnerAdapter.kt index 20f9d1a88..3ebccbb39 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/AccountsSpinnerAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/AccountsSpinnerAdapter.kt @@ -8,8 +8,7 @@ import android.widget.ArrayAdapter import android.widget.Filter import android.widget.TextView import org.mifos.mobile.R -import org.mifos.mobile.models.payload.AccountDetail -import java.util.* +import org.mifos.mobile.core.model.entity.payload.AccountDetail /** * Created by dilpreet on 19/03/18. diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/BeneficiaryListAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/BeneficiaryListAdapter.kt index 11cb656fc..6b3693031 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/BeneficiaryListAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/BeneficiaryListAdapter.kt @@ -3,8 +3,8 @@ package org.mifos.mobile.ui.adapters import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary import org.mifos.mobile.databinding.RowBeneficiaryBinding -import org.mifos.mobile.models.beneficiary.Beneficiary /** * Created by dilpreet on 15/6/17. diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/BeneficiarySpinnerAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/BeneficiarySpinnerAdapter.kt index e1e8d55b5..74e66e429 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/BeneficiarySpinnerAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/BeneficiarySpinnerAdapter.kt @@ -8,8 +8,8 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ArrayAdapter +import org.mifos.mobile.core.model.entity.beneficiary.BeneficiaryDetail import org.mifos.mobile.databinding.BeneficiarySpinnerLayoutBinding -import org.mifos.mobile.models.beneficiary.BeneficiaryDetail class BeneficiarySpinnerAdapter( context: Context, diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/CheckBoxAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/CheckBoxAdapter.kt index b8ab685ee..c218ff184 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/CheckBoxAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/CheckBoxAdapter.kt @@ -5,8 +5,8 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.core.widget.CompoundButtonCompat import androidx.recyclerview.widget.RecyclerView +import org.mifos.mobile.core.model.entity.CheckboxStatus import org.mifos.mobile.databinding.RowCheckboxBinding -import org.mifos.mobile.models.CheckboxStatus import javax.inject.Inject /** diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/ClientChargeAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/ClientChargeAdapter.kt index 707bd689e..21f4beb2c 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/ClientChargeAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/ClientChargeAdapter.kt @@ -5,11 +5,11 @@ import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import org.mifos.mobile.R +import org.mifos.mobile.core.datastore.model.Charge import org.mifos.mobile.databinding.RowClientChargeBinding -import org.mifos.mobile.models.Charge import org.mifos.mobile.ui.getThemeAttributeColor -import org.mifos.mobile.utils.CurrencyUtil.formatCurrency -import org.mifos.mobile.utils.DateHelper.getDateAsString +import org.mifos.mobile.core.common.utils.CurrencyUtil.formatCurrency +import org.mifos.mobile.core.common.utils.DateHelper.getDateAsString /** * @author Vishwajeet diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/ClientListAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/ClientListAdapter.kt index 8e5ab0ad3..cf7f28aae 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/ClientListAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/ClientListAdapter.kt @@ -9,7 +9,7 @@ import androidx.recyclerview.widget.RecyclerView import butterknife.BindView import butterknife.ButterKnife import org.mifos.mobile.R -import org.mifos.mobile.models.client.Client +import org.mifos.mobile.core.model.entity.client.Client /** * @author Vishwajeet diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/GuarantorListAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/GuarantorListAdapter.kt index a395beb62..0755a03ad 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/GuarantorListAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/GuarantorListAdapter.kt @@ -4,9 +4,9 @@ import android.content.Context import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView +import org.mifos.mobile.core.model.entity.guarantor.GuarantorPayload import org.mifos.mobile.databinding.RowGuarantorBinding -import org.mifos.mobile.models.guarantor.GuarantorPayload -import org.mifos.mobile.utils.DateHelper.getDateAsString +import org.mifos.mobile.core.common.utils.DateHelper.getDateAsString /* * Created by saksham on 24/July/2018 diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/LoanAccountsListAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/LoanAccountsListAdapter.kt index ea5d74864..3824430e7 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/LoanAccountsListAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/LoanAccountsListAdapter.kt @@ -6,10 +6,10 @@ import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.accounts.loan.LoanAccount import org.mifos.mobile.databinding.RowLoanAccountBinding -import org.mifos.mobile.models.accounts.loan.LoanAccount -import org.mifos.mobile.utils.CurrencyUtil.formatCurrency -import org.mifos.mobile.utils.DateHelper.getDateAsString +import org.mifos.mobile.core.common.utils.CurrencyUtil.formatCurrency +import org.mifos.mobile.core.common.utils.DateHelper.getDateAsString /** * @author Vishwajeet diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/LoanRepaymentScheduleAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/LoanRepaymentScheduleAdapter.kt index d097d30bb..b430767cc 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/LoanRepaymentScheduleAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/LoanRepaymentScheduleAdapter.kt @@ -6,16 +6,16 @@ import android.view.ViewGroup import com.evrencoskun.tableview.adapter.AbstractTableAdapter import com.evrencoskun.tableview.adapter.recyclerview.holder.AbstractViewHolder import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.accounts.loan.Periods +import org.mifos.mobile.core.model.entity.accounts.loan.tableview.Cell +import org.mifos.mobile.core.model.entity.accounts.loan.tableview.ColumnHeader +import org.mifos.mobile.core.model.entity.accounts.loan.tableview.RowHeader import org.mifos.mobile.databinding.CellLoanRepaymentScheduleBinding import org.mifos.mobile.databinding.ColumnHeaderLoanRepaymentScheduleBinding import org.mifos.mobile.databinding.CornerViewLoanRepaymentScheduleBinding import org.mifos.mobile.databinding.RowHeaderLoanRepaymentScheduleBinding -import org.mifos.mobile.models.accounts.loan.Periods -import org.mifos.mobile.models.accounts.loan.tableview.Cell -import org.mifos.mobile.models.accounts.loan.tableview.ColumnHeader -import org.mifos.mobile.models.accounts.loan.tableview.RowHeader -import org.mifos.mobile.utils.CurrencyUtil.formatCurrency -import org.mifos.mobile.utils.DateHelper.getDateAsString +import org.mifos.mobile.core.common.utils.CurrencyUtil.formatCurrency +import org.mifos.mobile.core.common.utils.DateHelper.getDateAsString import javax.inject.Inject /** diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/NotificationAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/NotificationAdapter.kt index 21e3f39b7..66e6375c7 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/NotificationAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/NotificationAdapter.kt @@ -8,12 +8,10 @@ import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import dagger.hilt.android.qualifiers.ActivityContext import org.mifos.mobile.R +import org.mifos.mobile.core.datastore.model.MifosNotification import org.mifos.mobile.databinding.RowNotificationBinding - - -import org.mifos.mobile.models.notification.MifosNotification import org.mifos.mobile.ui.getThemeAttributeColor -import org.mifos.mobile.utils.DateHelper.getDateAndTimeAsStringFromLong +import org.mifos.mobile.core.common.utils.DateHelper.getDateAndTimeAsStringFromLong import javax.inject.Inject /** diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/RecentTransactionListAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/RecentTransactionListAdapter.kt index 4d4409923..785cd9b01 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/RecentTransactionListAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/RecentTransactionListAdapter.kt @@ -8,13 +8,11 @@ import org.mifos.mobile.MifosSelfServiceApp.Companion.context import org.mifos.mobile.R import org.mifos.mobile.databinding.RowRecentTransactionBinding import dagger.hilt.android.qualifiers.ActivityContext - - -import org.mifos.mobile.models.Transaction -import org.mifos.mobile.models.client.Type -import org.mifos.mobile.utils.CurrencyUtil.formatCurrency -import org.mifos.mobile.utils.DateHelper.getDateAsString -import org.mifos.mobile.utils.Utils.formatTransactionType +import org.mifos.mobile.core.model.entity.Transaction +import org.mifos.mobile.core.model.entity.client.Type +import org.mifos.mobile.core.common.utils.CurrencyUtil.formatCurrency +import org.mifos.mobile.core.common.utils.DateHelper.getDateAsString +import org.mifos.mobile.core.common.utils.Utils.formatTransactionType import javax.inject.Inject /** diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/SavingAccountsListAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/SavingAccountsListAdapter.kt index e32a04258..3d921eee8 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/SavingAccountsListAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/SavingAccountsListAdapter.kt @@ -6,10 +6,10 @@ import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.accounts.savings.SavingAccount import org.mifos.mobile.databinding.RowSavingAccountBinding -import org.mifos.mobile.models.accounts.savings.SavingAccount -import org.mifos.mobile.utils.CurrencyUtil.formatCurrency -import org.mifos.mobile.utils.DateHelper.getDateAsString +import org.mifos.mobile.core.common.utils.CurrencyUtil.formatCurrency +import org.mifos.mobile.core.common.utils.DateHelper.getDateAsString /** * @author Vishwajeet diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/SavingAccountsTransactionListAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/SavingAccountsTransactionListAdapter.kt index a947e429e..bcd14d4e5 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/SavingAccountsTransactionListAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/SavingAccountsTransactionListAdapter.kt @@ -7,11 +7,11 @@ import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.accounts.savings.TransactionType +import org.mifos.mobile.core.model.entity.accounts.savings.Transactions import org.mifos.mobile.databinding.RowSavingAccountTransactionBinding -import org.mifos.mobile.models.accounts.savings.TransactionType -import org.mifos.mobile.models.accounts.savings.Transactions -import org.mifos.mobile.utils.CurrencyUtil.formatCurrency -import org.mifos.mobile.utils.DateHelper.getDateAsString +import org.mifos.mobile.core.common.utils.CurrencyUtil.formatCurrency +import org.mifos.mobile.core.common.utils.DateHelper.getDateAsString import javax.inject.Inject /** diff --git a/app/src/main/java/org/mifos/mobile/ui/adapters/ShareAccountsListAdapter.kt b/app/src/main/java/org/mifos/mobile/ui/adapters/ShareAccountsListAdapter.kt index 41c6f1730..7e0883497 100644 --- a/app/src/main/java/org/mifos/mobile/ui/adapters/ShareAccountsListAdapter.kt +++ b/app/src/main/java/org/mifos/mobile/ui/adapters/ShareAccountsListAdapter.kt @@ -6,8 +6,8 @@ import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.recyclerview.widget.RecyclerView import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.accounts.share.ShareAccount import org.mifos.mobile.databinding.RowShareAccountBinding -import org.mifos.mobile.models.accounts.share.ShareAccount class ShareAccountsListAdapter( private val onItemClick: (itemPosition: Int) -> Unit, diff --git a/app/src/main/java/org/mifos/mobile/ui/beneficiary/presentation/BeneficiaryAddOptionsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/beneficiary/presentation/BeneficiaryAddOptionsFragment.kt index d6a0b8b49..d5a9e64a2 100644 --- a/app/src/main/java/org/mifos/mobile/ui/beneficiary/presentation/BeneficiaryAddOptionsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/beneficiary/presentation/BeneficiaryAddOptionsFragment.kt @@ -1,13 +1,13 @@ package org.mifos.mobile.ui.beneficiary.presentation import android.Manifest -import android.content.Intent import android.content.pm.PackageManager +import android.os.Build import android.os.Bundle -import android.provider.MediaStore import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.annotation.RequiresApi import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import dagger.hilt.android.AndroidEntryPoint @@ -15,16 +15,17 @@ import org.mifos.mobile.R import org.mifos.mobile.core.ui.theme.MifosMobileTheme import org.mifos.mobile.databinding.FragmentBeneficiaryAddOptionsBinding import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.BeneficiaryState -import org.mifos.mobile.ui.enums.RequestAccessType -import org.mifos.mobile.ui.fragments.BeneficiaryApplicationFragment -import org.mifos.mobile.ui.fragments.QrCodeImportFragment -import org.mifos.mobile.ui.fragments.QrCodeReaderFragment +import org.mifos.mobile.ui.beneficiary_application.BeneficiaryApplicationComposeFragment +import org.mifos.mobile.core.model.enums.BeneficiaryState +import org.mifos.mobile.core.model.enums.RequestAccessType import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.ui.qr.QrCodeReaderFragment +import org.mifos.mobile.ui.qr_code_import.QrCodeImportComposeFragment import org.mifos.mobile.utils.CheckSelfPermissionAndRequest import org.mifos.mobile.utils.CheckSelfPermissionAndRequest.checkSelfPermission import org.mifos.mobile.utils.CheckSelfPermissionAndRequest.requestPermission -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.core.common.Constants +import org.mifos.mobile.feature.beneficiary.presentation.BeneficiaryScreen import org.mifos.mobile.utils.Toaster /** @@ -36,8 +37,11 @@ class BeneficiaryAddOptionsFragment : BaseFragment() { private var _binding: FragmentBeneficiaryAddOptionsBinding? = null private val binding get() = _binding!! + private var read_media_image_status = false private var external_storage_read_status = false private var external_storage_write_status = false + + @RequiresApi(Build.VERSION_CODES.TIRAMISU) override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -49,10 +53,12 @@ class BeneficiaryAddOptionsFragment : BaseFragment() { MifosMobileTheme { BeneficiaryScreen( - topAppbarNavigateback = {}, + topAppbarNavigateback = { + requireActivity().onBackPressedDispatcher.onBackPressed() + }, addiconClicked = { addManually() }, scaniconClicked = { addUsingQrCode() }, - uploadiconClicked = { addByImportingQrCode() } + uploadIconClicked = { addByImportingQrCode() }, ) } @@ -67,7 +73,7 @@ class BeneficiaryAddOptionsFragment : BaseFragment() { */ fun addManually() { (activity as BaseActivity?)?.replaceFragment( - BeneficiaryApplicationFragment.newInstance( + org.mifos.mobile.ui.beneficiary_application.BeneficiaryApplicationComposeFragment.newInstance( BeneficiaryState.CREATE_MANUAL, null, ), @@ -80,6 +86,7 @@ class BeneficiaryAddOptionsFragment : BaseFragment() { * It first checks CAMERA runtime permission and if it returns true then it opens * [QrCodeReaderFragment] , if it returns false then ask for permissions. */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) fun addUsingQrCode() { if (checkSelfPermission( activity, @@ -100,58 +107,19 @@ class BeneficiaryAddOptionsFragment : BaseFragment() { * It first checks Storage Read and Write Permission then if both of them are true then it opens * Intent to all gallery app */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) fun addByImportingQrCode() { - // request permission for writing external storage - accessReadWriteAccess() - if (external_storage_write_status && external_storage_read_status) { - val getIntent = Intent(Intent.ACTION_GET_CONTENT) - getIntent.type = "image/*" - val pickIntent = Intent( - Intent.ACTION_PICK, - MediaStore.Images.Media.EXTERNAL_CONTENT_URI, - ) - pickIntent.type = "image/*" - val chooserIntent = Intent.createChooser(getIntent, "Select Image") - chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, arrayOf(pickIntent)) - startActivityForResult(chooserIntent, Constants.GALLERY_QR_PICK) - } - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (requestCode == Constants.GALLERY_QR_PICK && data != null && data.data != null) { - activity?.supportFragmentManager?.popBackStack() - (activity as BaseActivity?)?.replaceFragment( - QrCodeImportFragment.newInstance(data.data!!), - true, - R.id.container, - ) - } - } - - private fun accessReadWriteAccess() { - if (checkSelfPermission( - activity, - Manifest.permission.READ_EXTERNAL_STORAGE, - ) - ) { - external_storage_read_status = true - } else { - requestPermission(RequestAccessType.EXTERNAL_STORAGE_READ) - } - if (checkSelfPermission( - activity, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - ) - ) { - external_storage_write_status = true - } else { - requestPermission(RequestAccessType.EXTERNAL_STORAGE_WRITE) - } + (activity as BaseActivity?)?.replaceFragment( + QrCodeImportComposeFragment.newInstance(), + true, + R.id.container, + ) } /** * Uses [CheckSelfPermissionAndRequest] to check for runtime permissions */ + @RequiresApi(Build.VERSION_CODES.TIRAMISU) private fun requestPermission(requestAccessType: RequestAccessType) { when (requestAccessType) { RequestAccessType.CAMERA -> { @@ -167,38 +135,21 @@ class BeneficiaryAddOptionsFragment : BaseFragment() { ) } - RequestAccessType.EXTERNAL_STORAGE_READ -> { - requestPermission( - (activity as BaseActivity?)!!, - Manifest.permission.READ_EXTERNAL_STORAGE, - Constants.PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE, - resources.getString(R.string.dialog_message_storage_permission_denied_prompt), - resources - .getString(R.string.dialog_message_read_storage_permission_never_ask_again), - Constants.PERMISSIONS_STORAGE_STATUS, - ) - } - - RequestAccessType.EXTERNAL_STORAGE_WRITE -> { - requestPermission( - (activity as BaseActivity?)!!, - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Constants.PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE, - resources.getString(R.string.dialog_message_storage_permission_denied_prompt), - resources.getString(R.string.dialog_message_write_storage_permission_never_ask_again), - Constants.PERMISSIONS_STORAGE_STATUS, - ) - } + RequestAccessType.EXTERNAL_STORAGE_READ -> TODO() + RequestAccessType.EXTERNAL_STORAGE_WRITE -> TODO() + RequestAccessType.READ_MEDIA_IMAGES -> TODO() } } + + @Deprecated("Deprecated in Java") override fun onRequestPermissionsResult( requestCode: Int, permissions: Array, grantResults: IntArray, ) { when (requestCode) { - Constants.PERMISSIONS_REQUEST_CAMERA -> { + org.mifos.mobile.core.common.Constants.PERMISSIONS_REQUEST_CAMERA -> { if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED ) { @@ -215,45 +166,22 @@ class BeneficiaryAddOptionsFragment : BaseFragment() { ) } } - - Constants.PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE -> { - if (grantResults.size > 0 && - grantResults[0] == PackageManager.PERMISSION_GRANTED - ) { - external_storage_read_status = true - } else { - Toaster.show( - binding.root, - resources - .getString(R.string.permission_denied_storage), - ) - } - } - - Constants.PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE -> { - if (grantResults.size > 0 && - grantResults[0] == PackageManager.PERMISSION_GRANTED - ) { - external_storage_write_status = true - } else { - Toaster.show( - binding.root, - resources - .getString(R.string.permission_denied_storage), - ) - } - } } } + + override fun onDestroyView() { super.onDestroyView() _binding = null } + override fun onResume() { + super.onResume() + (activity as? BaseActivity)?.hideToolbar() + } companion object { - @JvmStatic fun newInstance(): BeneficiaryAddOptionsFragment { val fragment = BeneficiaryAddOptionsFragment() val args = Bundle() diff --git a/app/src/main/java/org/mifos/mobile/ui/beneficiary/presentation/BeneficiaryScreen.kt b/app/src/main/java/org/mifos/mobile/ui/beneficiary/presentation/BeneficiaryScreen.kt deleted file mode 100644 index ec2a005ec..000000000 --- a/app/src/main/java/org/mifos/mobile/ui/beneficiary/presentation/BeneficiaryScreen.kt +++ /dev/null @@ -1,83 +0,0 @@ -package org.mifos.mobile.ui.beneficiary.presentation - -import android.content.res.Configuration -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.padding -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.dimensionResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import org.mifos.mobile.R -import org.mifos.mobile.core.ui.component.MifosTopBar -import org.mifos.mobile.core.ui.theme.MifosMobileTheme - - -/** - * This is a composable function that represent the beneficiary screen and the parameters include - * @param[addiconClicked] to navigate to the add screen - * @param[scaniconClicked] to navigate to the scanicon screen - * @param[uploadiconClicked] to navigate to the upload icin screen - **/ - - -@Composable -fun BeneficiaryScreen( - topAppbarNavigateback: () -> Unit, - addiconClicked: () -> Unit, - scaniconClicked: () -> Unit, - uploadiconClicked: () -> Unit -) { - MifosTopBar( - navigateBack = topAppbarNavigateback, - title = { - Text(text = stringResource(id = R.string.add_beneficiary)) - } - ) - - Column( - modifier = Modifier.padding(dimensionResource(id = R.dimen.padding_10dp)) - ) { - Text( - stringResource(id = R.string.select_mode), - fontSize = 18.sp, - color = MaterialTheme.colorScheme.onSurface - ) - - Text( - modifier = Modifier.padding(top = 16.dp), - text = stringResource(R.string.add_beneficiary_option), - fontSize = 18.sp, - color = MaterialTheme.colorScheme.onSurface - ) - - BeneficiaryScreenIcons( - modifier = Modifier.padding(top = 20.dp), - addIconclicked = addiconClicked, - scanIconClicked = scaniconClicked, - uploadIconClicked = uploadiconClicked - ) - - } - -} - -@Preview( - name = "Night Mode", - uiMode = Configuration.UI_MODE_NIGHT_YES, -) -@Preview( - name = "Day mode", - uiMode = Configuration.UI_MODE_NIGHT_NO, -) -@Composable -fun BeneficiaryScreenPreview() { - MifosMobileTheme { - BeneficiaryScreen({}, {}, {}, {}) - - } -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/beneficiary_application/BeneficiaryApplicationComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/beneficiary_application/BeneficiaryApplicationComposeFragment.kt new file mode 100644 index 000000000..2d0613d0a --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/beneficiary_application/BeneficiaryApplicationComposeFragment.kt @@ -0,0 +1,70 @@ +package org.mifos.mobile.ui.beneficiary_application + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.viewModels +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.core.model.enums.BeneficiaryState +import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.core.common.Constants +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedSerializable +import org.mifos.mobile.feature.beneficiary.beneficiary_application.BeneficiaryApplicationScreen +import org.mifos.mobile.feature.beneficiary.beneficiary_application.BeneficiaryApplicationViewModel + +/** + * Created by dilpreet on 16/6/17. + */ +@AndroidEntryPoint +class BeneficiaryApplicationComposeFragment : BaseFragment() { + + private val viewModel: BeneficiaryApplicationViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (arguments != null) { + viewModel.initArgs( + beneficiaryState = arguments?.getCheckedSerializable(BeneficiaryState::class.java, Constants.BENEFICIARY_STATE) as BeneficiaryState, + beneficiary = arguments?.getCheckedParcelable(Beneficiary::class.java, Constants.BENEFICIARY) + ) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + return mifosComposeView(requireContext()) { + BeneficiaryApplicationScreen( + navigateBack = { activity?.onBackPressed() } + ) + } + } + + override fun onResume() { + super.onResume() + (activity as? BaseActivity)?.hideToolbar() + } + + companion object { + fun newInstance( + beneficiaryState: BeneficiaryState?, + beneficiary: Beneficiary?, + ): BeneficiaryApplicationComposeFragment { + val fragment = BeneficiaryApplicationComposeFragment() + val args = Bundle() + args.putSerializable(Constants.BENEFICIARY_STATE, beneficiaryState) + if (beneficiary != null) { + args.putParcelable(Constants.BENEFICIARY, beneficiary) + } + fragment.arguments = args + return fragment + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/beneficiary_detail/BeneficiaryDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/beneficiary_detail/BeneficiaryDetailFragment.kt index bf5097f8f..4a71fa1fe 100644 --- a/app/src/main/java/org/mifos/mobile/ui/beneficiary_detail/BeneficiaryDetailFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/beneficiary_detail/BeneficiaryDetailFragment.kt @@ -1,6 +1,5 @@ package org.mifos.mobile.ui.beneficiary_detail; - import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -8,13 +7,14 @@ import android.view.ViewGroup import androidx.fragment.app.viewModels import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R +import org.mifos.mobile.core.common.Constants import org.mifos.mobile.core.ui.component.mifosComposeView -import org.mifos.mobile.models.beneficiary.Beneficiary import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.BeneficiaryState -import org.mifos.mobile.ui.fragments.BeneficiaryApplicationFragment import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary +import org.mifos.mobile.core.model.enums.BeneficiaryState +import org.mifos.mobile.feature.beneficiary.beneficiary_detail.BeneficiaryDetailScreen +import org.mifos.mobile.feature.beneficiary.beneficiary_detail.BeneficiaryDetailViewModel @AndroidEntryPoint class BeneficiaryDetailFragment : BaseFragment() { @@ -45,7 +45,7 @@ class BeneficiaryDetailFragment : BaseFragment() { private fun updateBeneficiaryClicked() { (activity as BaseActivity?)?.replaceFragment( - BeneficiaryApplicationFragment.newInstance( + org.mifos.mobile.ui.beneficiary_application.BeneficiaryApplicationComposeFragment.newInstance( BeneficiaryState.UPDATE, viewModel.getBeneficiary() ), diff --git a/app/src/main/java/org/mifos/mobile/ui/beneficiary_list/BeneficiaryListComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/beneficiary_list/BeneficiaryListComposeFragment.kt new file mode 100644 index 000000000..af2107674 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/beneficiary_list/BeneficiaryListComposeFragment.kt @@ -0,0 +1,63 @@ +package org.mifos.mobile.ui.beneficiary_list + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.ui.beneficiary.presentation.BeneficiaryAddOptionsFragment +import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.feature.beneficiary.beneficiary_list.BeneficiaryListScreen +import org.mifos.mobile.feature.guarantor.R + +@AndroidEntryPoint +class BeneficiaryListComposeFragment : BaseFragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + return mifosComposeView(requireContext()) { + BeneficiaryListScreen( + navigateBack = { activity?.supportFragmentManager?.popBackStack() }, + addBeneficiaryClicked = { addBeneficiary() }, + onBeneficiaryItemClick = { position, beneficiaryList -> + onItemClick( + position = position, + beneficiaryList = beneficiaryList + ) + }, + ) + } + } + + private fun onItemClick(position: Int, beneficiaryList: List) { + (activity as? BaseActivity)?.replaceFragment( + org.mifos.mobile.ui.beneficiary_detail.BeneficiaryDetailFragment.newInstance(beneficiaryList[position]), + true, + R.id.container, + ) + } + + private fun addBeneficiary() { + (activity as? BaseActivity)?.replaceFragment( + BeneficiaryAddOptionsFragment.newInstance(), + true, + R.id.container, + ) + } + + override fun onResume() { + super.onResume() + (activity as? BaseActivity)?.hideToolbar() + } + + companion object { + fun newInstance(): BeneficiaryListComposeFragment { + return BeneficiaryListComposeFragment() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountFilterDialog.kt b/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountFilterDialog.kt new file mode 100644 index 000000000..20485eef6 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountFilterDialog.kt @@ -0,0 +1,124 @@ +package org.mifos.mobile.ui.client_accounts + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Checkbox +import androidx.compose.material3.CheckboxColors +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.CheckboxStatus + +@Composable +fun ClientAccountFilterDialog( + cancelDialog: () -> Unit, + clearFilter: () -> Unit, + updateFilterList: (checkBoxList: List) -> Unit, + title: String, + filterList: List +) { + var checkBoxList : List = filterList + + AlertDialog( + onDismissRequest = { cancelDialog.invoke() }, + text = { + Column { + Text(modifier = Modifier.padding(bottom = 8.dp), text = "Filter $title") + Text(modifier = Modifier.padding(bottom = 16.dp), text = stringResource(R.string.select_you_want)) + + ClientAccountFilterCheckBox( accountStatusList = filterList ) { checkBoxList = it } + + Row( modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) + { + TextButton(onClick = { clearFilter.invoke() }) { + Text(text = stringResource(R.string.clear_filters)) + } + Row { + TextButton(onClick = { cancelDialog.invoke() }) { + Text(text = stringResource(R.string.cancel)) + } + TextButton(onClick = { updateFilterList(checkBoxList) }) { + Text(text = stringResource(R.string.filter)) + } + } + } + + } + }, + confirmButton = {} + ) +} + +@Composable +fun ClientAccountFilterCheckBox( + accountStatusList: List, + updateList: (List) -> Unit +) { + + var checkBoxList by rememberSaveable { + mutableStateOf(accountStatusList) + } + + val lazyColumnState = rememberLazyListState() + + LazyColumn( + state = lazyColumnState + ) { + items( checkBoxList.size ){ index-> + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.Start + ) + { + Checkbox( + checked = checkBoxList[index].isChecked, + onCheckedChange = { + val updatedList = checkBoxList.toMutableList() + updatedList[index] = checkBoxList[index].copy(isChecked = it) + checkBoxList = updatedList + updateList.invoke(checkBoxList) + }, + colors= CheckboxColors( + checkedBoxColor = Color(checkBoxList[index].color), + uncheckedBoxColor = if (isSystemInDarkTheme()) colorResource(id = R.color.gray_light) else colorResource(id = R.color.white) , + checkedCheckmarkColor = if (isSystemInDarkTheme()) colorResource(id = R.color.black) else colorResource(id = R.color.white), + uncheckedCheckmarkColor= colorResource(id = R.color.white), + checkedBorderColor = Color(checkBoxList[index].color), + uncheckedBorderColor = Color(checkBoxList[index].color ), + disabledBorderColor = colorResource(id = R.color.gray_dark), + disabledIndeterminateBorderColor = colorResource(id = R.color.gray_dark), + disabledCheckedBoxColor= colorResource(id = R.color.black), + disabledUncheckedBoxColor= colorResource(id = R.color.black), + disabledIndeterminateBoxColor= colorResource(id = R.color.black), + disabledUncheckedBorderColor= colorResource(id = R.color.black), + ) + ) + Text( + text = checkBoxList[index].status ?: "", + color = MaterialTheme.colorScheme.onSurface, + ) + } + } + } +} + diff --git a/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountScreenTopBar.kt b/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountScreenTopBar.kt new file mode 100644 index 000000000..5706ab76b --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountScreenTopBar.kt @@ -0,0 +1,122 @@ +package org.mifos.mobile.ui.client_accounts + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxHeight +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.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.unit.dp +import org.mifos.mobile.core.ui.component.MifosIcons +import org.mifos.mobile.core.ui.component.MifosSearchTextField + +@Composable +fun ClientAccountsScreenTopBar( + navigateBack: () -> Unit?, + onChange: (String) -> Unit, + clickDialog: () -> Unit, + closeSearch: () -> Unit, +) { + var query by rememberSaveable(stateSaver = TextFieldValue.Saver) { mutableStateOf(TextFieldValue("")) } + var isSearchActive by rememberSaveable { mutableStateOf(false) } + + Row( + Modifier.padding(top = 8.dp) + .fillMaxWidth() + .height(50.dp), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + + IconButton( + onClick = { navigateBack.invoke() }, + modifier = Modifier.size(40.dp) + ) { + Icon( + imageVector = Icons.Filled.ArrowBack, + contentDescription = "Back Arrow", + tint = if (isSystemInDarkTheme()) Color.White else Color.Black, + ) + } + + Box( + Modifier + .fillMaxWidth() + .fillMaxHeight(), contentAlignment = Alignment.CenterStart + ) { + + Text( + text = "Accounts", + style = MaterialTheme.typography.titleLarge, + color = if (isSystemInDarkTheme()) Color.White else Color.Black + ) + + Row( + Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End, + verticalAlignment = Alignment.CenterVertically + ) { + + IconButton( + onClick = { isSearchActive = true }, + modifier = Modifier.size(40.dp) + ) { + Image( + imageVector = MifosIcons.Search, + contentDescription = "Add account", + colorFilter = ColorFilter.tint(if (isSystemInDarkTheme()) Color.White else Color.Black) + ) + } + IconButton( + onClick = { clickDialog.invoke() }, + modifier = Modifier.size(40.dp) + ) { + Image( + imageVector = MifosIcons.FilterList, + contentDescription = "Add account" + ) + } + } + + if (isSearchActive) { + MifosSearchTextField( + value = query, + onValueChange = { + query = it + onChange(it.text) + }, + modifier = Modifier.padding(end = 40.dp) + .height(52.dp) + .fillMaxWidth() + .background(color = MaterialTheme.colorScheme.background), + onSearchDismiss = { + query = TextFieldValue("") + closeSearch.invoke() + isSearchActive = false + } + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsComposeFragment.kt new file mode 100644 index 000000000..65ce2c070 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsComposeFragment.kt @@ -0,0 +1,77 @@ +package org.mifos.mobile.ui.client_accounts + + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.ui.activities.LoanAccountContainerActivity +import org.mifos.mobile.ui.activities.LoanApplicationActivity +import org.mifos.mobile.ui.activities.SavingsAccountApplicationActivity +import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity +import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.core.model.enums.AccountType +import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.core.common.Constants + +/* +~This project is licensed under the open source MPL V2. +~See https://github.com/openMF/self-service-app/blob/master/LICENSE.md +*/ +@AndroidEntryPoint +class ClientAccountsComposeFragment : BaseFragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + (activity as? BaseActivity)?.hideToolbar() + return mifosComposeView(requireContext()) { + ClientAccountsScreen( + navigateBack = { activity?.onBackPressed() }, + openNextActivity = { currentPage -> openActivity(currentPage) }, + onItemClick = { accountType, accountId -> onItemClick(accountType, accountId) } + ) + } + } + + private fun openActivity( currentPage : Int) { + when (currentPage) { + 0 -> startActivity(Intent(activity, SavingsAccountApplicationActivity::class.java)) + 1 -> startActivity(Intent(activity, LoanApplicationActivity::class.java)) + } + } + + private fun onItemClick(accountType: String, accountId: Long + ) { + var intent: Intent? = null + when (accountType) { + Constants.SAVINGS_ACCOUNTS -> { + intent = Intent(activity, SavingsAccountContainerActivity::class.java) + intent.putExtra(Constants.SAVINGS_ID, accountId) + } + Constants.LOAN_ACCOUNTS -> { + intent = Intent(activity, LoanAccountContainerActivity::class.java) + intent.putExtra(Constants.LOAN_ID,accountId) + } + } + openActivity(intent) + } + + private fun openActivity(intent: Intent?) { + intent?.let { startActivity(it) } + } + + companion object { + fun newInstance(accountType: AccountType?): ClientAccountsComposeFragment { + val clientAccountsComposeFragment = ClientAccountsComposeFragment() + val args = Bundle() + args.putSerializable(Constants.ACCOUNT_TYPE, accountType) + clientAccountsComposeFragment.arguments = args + return clientAccountsComposeFragment + } + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsFragment.kt similarity index 98% rename from app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt rename to app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsFragment.kt index 0c569a9db..897c09430 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/ClientAccountsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsFragment.kt @@ -1,5 +1,6 @@ -package org.mifos.mobile.ui.fragments +package org.mifos.mobile.ui.client_accounts +/* import android.app.SearchManager import android.content.Context import android.content.Intent @@ -31,10 +32,9 @@ import org.mifos.mobile.ui.adapters.CheckBoxAdapter 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.core.common.Constants +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedSerializable import org.mifos.mobile.utils.StatusUtils -import org.mifos.mobile.viewModels.AccountsViewModel import javax.inject.Inject /* @@ -468,3 +468,4 @@ class ClientAccountsFragment : BaseFragment() { } } } +*/ \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsScreen.kt b/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsScreen.kt new file mode 100644 index 000000000..b59fa3d77 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/client_accounts/ClientAccountsScreen.kt @@ -0,0 +1,250 @@ +package org.mifos.mobile.ui.client_accounts + +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.pager.rememberPagerState +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.FloatingActionButtonContent +import org.mifos.mobile.core.ui.component.MFScaffold +import org.mifos.mobile.core.ui.component.MifosIcons +import org.mifos.mobile.core.ui.component.MifosTabPager +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.ui.account.AccountsScreen +import org.mifos.mobile.ui.account.AccountsViewModel +import org.mifos.mobile.core.model.entity.CheckboxStatus + +@Composable +fun ClientAccountsScreen( + viewModel: AccountsViewModel = hiltViewModel(), + navigateBack: () -> Unit?, + openNextActivity: (currentPage: Int) -> Unit, + onItemClick: (accountType: String, accountId: Long) -> Unit +) { + val context = LocalContext.current + var isDialogActive by rememberSaveable { mutableStateOf(false) } + var currentPage by rememberSaveable { mutableIntStateOf(0) } + val filterList by viewModel.filterList.collectAsStateWithLifecycle() + + LaunchedEffect(key1 = currentPage) { + viewModel.setFilterList( + checkBoxList = emptyList(), + currentPage = currentPage, + context = context + ) + } + + ClientAccountsScreen( + navigateBack = navigateBack, + openNextActivity = { index -> openNextActivity.invoke(index) }, + onItemClick = { accountType, accountId -> onItemClick.invoke(accountType, accountId) }, + cancelFilterDialog = { isDialogActive = false }, + clearFilter = { + viewModel.setFilterList( + checkBoxList = emptyList(), + currentPage = currentPage, + context = context + ) + isDialogActive = false + }, + filterAccounts = { + viewModel.setFilterList(checkBoxList = it, currentPage = currentPage, context = context) + isDialogActive = false + }, + onSearchQueryChange = { viewModel.updateSearchQuery(query = it) }, + openSearch = { isDialogActive = true }, + closeSearch = { viewModel.stoppedSearching() }, + currentPage = currentPage, + pageChanged = { index -> currentPage = index }, + isDialogActive = isDialogActive, + filterList = filterList + ) +} + +@Composable +fun ClientAccountsScreen( + navigateBack: () -> Unit?, + openNextActivity: (currentPage: Int) -> Unit, + onItemClick: (accountType: String, accountId: Long) -> Unit, + cancelFilterDialog: () -> Unit, + clearFilter: () -> Unit, + filterAccounts: (checkBoxList: List) -> Unit, + onSearchQueryChange: (String) -> Unit, + openSearch: () -> Unit, + closeSearch: () -> Unit, + currentPage: Int, + pageChanged: (index: Int) -> Unit, + isDialogActive: Boolean, + filterList: List + +) { + val tabs = listOf( + stringResource(id = R.string.savings_account), + stringResource(id = R.string.loan_account), + stringResource(id = R.string.share_account) + ) + + if (isDialogActive) { + ClientAccountFilterDialog( + filterList = filterList, + cancelDialog = { cancelFilterDialog.invoke() }, + clearFilter = { clearFilter.invoke() }, + updateFilterList = { list -> filterAccounts(list) }, + title = tabs[currentPage] + ) + } + + MFScaffold( + topBar = { + ClientAccountsScreenTopBar( + navigateBack = navigateBack, + onChange = { onSearchQueryChange(it) }, + clickDialog = { openSearch.invoke() }, + closeSearch = { closeSearch.invoke() } + ) + }, + + floatingActionButtonContent = FloatingActionButtonContent( + onClick = { + when (currentPage) { + 0 -> openNextActivity(currentPage) + 1 -> openNextActivity(currentPage) + } + }, + contentColor = if (isSystemInDarkTheme()) MaterialTheme.colorScheme.secondary + else MaterialTheme.colorScheme.primary, + content = { + Icon( + imageVector = MifosIcons.Add, + contentDescription = "Create Account", + tint = if (isSystemInDarkTheme()) Color.Black else Color.White + ) + } + ), + + scaffoldContent = { + ClientAccountsTabRow( + modifier = Modifier.padding(it), + pageChanged = { index -> pageChanged.invoke(index) }, + onItemClick = { accountType, accountId -> + onItemClick.invoke( + accountType, + accountId + ) + }, + ) + } + ) +} + + + +@OptIn(ExperimentalFoundationApi::class) +@Composable +fun ClientAccountsTabRow( + modifier: Modifier, + pageChanged: (index: Int) -> Unit, + onItemClick: (accountType: String, accountId: Long) -> Unit +) { + + var currentPage by remember { mutableIntStateOf(0) } + val pagerState = rememberPagerState(pageCount = { 3 }) + val tabs = listOf( + stringResource(id = R.string.savings), + stringResource(id = R.string.loan), + stringResource(id = R.string.share) + ) + + LaunchedEffect(key1 = currentPage) { + pageChanged(currentPage) + pagerState.animateScrollToPage(currentPage) + } + + LaunchedEffect(key1 = pagerState.currentPage, pagerState.isScrollInProgress) { + currentPage = if (!pagerState.isScrollInProgress) + pagerState.currentPage + else { + pagerState.targetPage + } + } + + MifosTabPager( + pagerState = pagerState, + currentPage = currentPage, + modifier = modifier, + tabs = tabs, + setCurrentPage = { currentPage = it } + ) { + when (currentPage) { + 0 -> AccountsScreen( + accountType = org.mifos.mobile.core.common.Constants.SAVINGS_ACCOUNTS, + onItemClick = { accType, accountId -> + onItemClick.invoke( + accType, + accountId + ) + } + ) + + 1 -> AccountsScreen( + accountType = org.mifos.mobile.core.common.Constants.LOAN_ACCOUNTS, + onItemClick = { accType, accountId -> + onItemClick.invoke( + accType, + accountId + ) + } + ) + + 2 -> AccountsScreen( + accountType = org.mifos.mobile.core.common.Constants.SHARE_ACCOUNTS, + onItemClick = { accType, accountId -> + onItemClick.invoke( + accType, + accountId + ) + } + ) + } + } +} + + +@Preview(showSystemUi = true) +@Composable +fun ClientAccountsScreenPreview() { + MifosMobileTheme { + ClientAccountsScreen( + navigateBack = {}, + openNextActivity = { it -> }, + onItemClick = { accountType, accountId -> }, + cancelFilterDialog = { }, + clearFilter = { }, + filterAccounts = { }, + onSearchQueryChange = { }, + openSearch = { }, + closeSearch = { }, + currentPage = 0, + pageChanged = { index -> }, + isDialogActive = false, + filterList = listOf() + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeComposeFragment.kt index da2d7fbc8..83c13ae5d 100644 --- a/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeComposeFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeComposeFragment.kt @@ -8,10 +8,10 @@ import androidx.fragment.app.viewModels import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.core.ui.component.mifosComposeView import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.ChargeType +import org.mifos.mobile.core.model.enums.ChargeType 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.core.common.Constants +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedSerializable /** * @author Vishwajeet diff --git a/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeFragment.kt index 3bf627f4d..7adf81f0b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeFragment.kt @@ -1,31 +1,5 @@ package org.mifos.mobile.ui.client_charge -import android.os.Bundle -import android.view.LayoutInflater -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 androidx.recyclerview.widget.LinearLayoutManager -import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler -import dagger.hilt.android.AndroidEntryPoint -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.base.BaseActivity -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.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 - /* @AndroidEntryPoint diff --git a/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeScreen.kt b/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeScreen.kt index f9a1e3812..def8e0e31 100644 --- a/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeScreen.kt @@ -36,10 +36,10 @@ import org.mifos.mobile.core.ui.component.MifosTextTitleDescSingleLine import org.mifos.mobile.core.ui.theme.GreenSuccess import org.mifos.mobile.core.ui.theme.MifosMobileTheme import org.mifos.mobile.core.ui.theme.RedErrorDark -import org.mifos.mobile.models.Charge -import org.mifos.mobile.utils.CurrencyUtil -import org.mifos.mobile.utils.DateHelper -import org.mifos.mobile.utils.Network +import org.mifos.mobile.core.common.utils.CurrencyUtil +import org.mifos.mobile.core.common.utils.DateHelper +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.datastore.model.Charge @Composable diff --git a/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeViewModel.kt index 3d2666ed8..e25b8eaa3 100644 --- a/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/client_charge/ClientChargeViewModel.kt @@ -7,9 +7,8 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch -import org.mifos.mobile.models.Charge -import org.mifos.mobile.repositories.ClientChargeRepository -import org.mifos.mobile.ui.enums.ChargeType +import org.mifos.mobile.core.data.repositories.ClientChargeRepository +import org.mifos.mobile.core.datastore.model.Charge import javax.inject.Inject @HiltViewModel @@ -22,12 +21,12 @@ class ClientChargeViewModel @Inject constructor(private val clientChargeReposito private val _clientId = MutableStateFlow(null) private val clientId: StateFlow get() = _clientId - private val _chargeType = MutableStateFlow(null) - private val chargeType: StateFlow get() = _chargeType + private val _chargeType = MutableStateFlow(null) + private val chargeType: StateFlow get() = _chargeType fun initArgs( clientId: Long?, - chargeType: ChargeType + chargeType: org.mifos.mobile.core.model.enums.ChargeType ) { _clientId.value = clientId _chargeType.value = chargeType @@ -37,9 +36,9 @@ class ClientChargeViewModel @Inject constructor(private val clientChargeReposito fun loadCharges() { clientId.value?.let { clientId -> when (chargeType.value) { - ChargeType.CLIENT -> loadClientCharges(clientId) - ChargeType.SAVINGS -> loadSavingsAccountCharges(clientId) - ChargeType.LOAN -> loadLoanAccountCharges(clientId) + org.mifos.mobile.core.model.enums.ChargeType.CLIENT -> loadClientCharges(clientId) + org.mifos.mobile.core.model.enums.ChargeType.SAVINGS -> loadSavingsAccountCharges(clientId) + org.mifos.mobile.core.model.enums.ChargeType.LOAN -> loadLoanAccountCharges(clientId) null -> Unit } } 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 deleted file mode 100644 index 63097d506..000000000 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryApplicationFragment.kt +++ /dev/null @@ -1,380 +0,0 @@ -package org.mifos.mobile.ui.fragments - -import android.os.Bundle -import android.os.Parcelable -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -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.databinding.FragmentBeneficiaryApplicationBinding -import org.mifos.mobile.models.beneficiary.Beneficiary -import org.mifos.mobile.models.beneficiary.BeneficiaryPayload -import org.mifos.mobile.models.beneficiary.BeneficiaryUpdatePayload -import org.mifos.mobile.models.templates.beneficiary.BeneficiaryTemplate -import org.mifos.mobile.ui.enums.BeneficiaryState -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 - -/** - * Created by dilpreet on 16/6/17. - */ -@AndroidEntryPoint -class BeneficiaryApplicationFragment : BaseFragment() { - - private var _binding: FragmentBeneficiaryApplicationBinding? = null - private val binding get() = _binding!! - - private val viewModel: BeneficiaryApplicationViewModel by viewModels() - - private val listAccountType: MutableList = ArrayList() - private var beneficiaryState: BeneficiaryState? = null - private var beneficiary: Beneficiary? = null - private var beneficiaryTemplate: BeneficiaryTemplate? = null - private var accountTypeId: Int? = -1 - private var sweetUIErrorHandler: SweetUIErrorHandler? = null - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setToolbarTitle(getString(R.string.add_beneficiary)) - if (arguments != null) { - beneficiaryState = requireArguments().getCheckedSerializable( - BeneficiaryState::class.java, - Constants.BENEFICIARY_STATE - ) as BeneficiaryState - when (beneficiaryState) { - BeneficiaryState.UPDATE -> { - beneficiary = arguments?.getCheckedParcelable( - Beneficiary::class.java, - Constants.BENEFICIARY - ) - setToolbarTitle(getString(R.string.update_beneficiary)) - } - - BeneficiaryState.CREATE_QR -> { - beneficiary = arguments?.getCheckedParcelable( - Beneficiary::class.java, - Constants.BENEFICIARY - ) - setToolbarTitle(getString(R.string.add_beneficiary)) - } - - else -> { - setToolbarTitle(getString(R.string.add_beneficiary)) - } - } - } - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = FragmentBeneficiaryApplicationBinding.inflate(inflater, container, false) - sweetUIErrorHandler = SweetUIErrorHandler(activity, binding.root) - showUserInterface() - if (savedInstanceState == null) { - viewModel.loadBeneficiaryTemplate() - } - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewLifecycleOwner.lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.beneficiaryUiState.collect { - when (it) { - is BeneficiaryUiState.Loading -> showProgress() - is BeneficiaryUiState.ShowError -> { - hideProgress() - showError(getString(it.message)) - } - - is BeneficiaryUiState.SetVisibility -> { - hideProgress() - setVisibility(it.visibility) - } - - is BeneficiaryUiState.ShowBeneficiaryTemplate -> { - hideProgress() - showBeneficiaryTemplate(it.beneficiaryTemplate) - } - - is BeneficiaryUiState.CreatedSuccessfully -> { - hideProgress() - showBeneficiaryCreatedSuccessfully() - } - - is BeneficiaryUiState.UpdatedSuccessfully -> { - hideProgress() - showBeneficiaryUpdatedSuccessfully() - } - - is BeneficiaryUiState.Initial -> {} - - else -> throw IllegalStateException("Undesired $it") - } - } - } - } - - with(binding) { - btnBeneficiarySubmit.setOnClickListener { - submitBeneficiary() - } - layoutError.btnTryAgain.setOnClickListener { - onRetry() - } - } - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putParcelable(Constants.TEMPLATE, beneficiaryTemplate) - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - if (savedInstanceState != null) { - showBeneficiaryTemplate( - savedInstanceState.getCheckedParcelable( - BeneficiaryTemplate::class.java, - Constants.TEMPLATE - ) - ) - } - } - - /** - * Setting up `accountTypeAdapter` and `` spAccountType - */ - fun showUserInterface() { - with(binding) { - accountTypeField.setOnItemClickListener { _, _, position, _ -> - accountTypeId = beneficiaryTemplate?.accountTypeOptions?.get(position)?.id - } - accountTypeFieldParent.isEnabled = Network.isConnected(context) - accountTypeField.setSimpleItems(listAccountType.toTypedArray()) - } - } - - /** - * Fetches [BeneficiaryTemplate] from server and further updates the UI according to - * [BeneficiaryState] which is initialized in `newInstance()` as - * `beneficiaryState` - * - * @param beneficiaryTemplate [BeneficiaryTemplate] fetched from server - */ - private fun showBeneficiaryTemplate(beneficiaryTemplate: BeneficiaryTemplate?) { - this.beneficiaryTemplate = beneficiaryTemplate - for ((_, _, value) in beneficiaryTemplate?.accountTypeOptions!!) { - listAccountType.add(value) - } - binding.accountTypeField.setSimpleItems(listAccountType.toTypedArray()) - if (beneficiaryState == BeneficiaryState.UPDATE) { - with(binding) { - accountTypeField.setText(beneficiary?.accountType?.value!!, false) - accountTypeFieldParent.isEnabled = false - tilAccountNumber.editText?.setText(beneficiary?.accountNumber) - tilAccountNumber.isEnabled = false - tilOfficeName.editText?.setText(beneficiary?.officeName) - tilOfficeName.isEnabled = false - tilBeneficiaryName.editText?.setText(beneficiary?.name) - tilTransferLimit.editText?.setText(beneficiary?.transferLimit.toString()) - } - } else if (beneficiaryState == BeneficiaryState.CREATE_QR) { - with(binding) { - accountTypeField.setText(beneficiary?.accountType?.value!!, false) - tilAccountNumber.editText?.setText(beneficiary?.accountNumber) - tilOfficeName.editText?.setText(beneficiary?.officeName) - } - } - } - - /** - * Used for submitting a new or updating beneficiary application - */ - private fun submitBeneficiary() { - with(binding) { - tilAccountNumber.isErrorEnabled = false - tilOfficeName.isErrorEnabled = false - tilTransferLimit.isErrorEnabled = false - tilBeneficiaryName.isErrorEnabled = false - } - with(binding) { - when { - accountTypeId == -1 -> { - Toaster.show(root, getString(R.string.choose_account_type)) - return - } - - tilAccountNumber.editText?.text.isNullOrBlank() -> { - tilAccountNumber.error = getString(R.string.enter_account_number) - return - } - - tilOfficeName.editText?.text.isNullOrBlank() -> { - tilOfficeName.error = getString(R.string.enter_office_name) - return - } - - tilTransferLimit.editText?.text.toString().isEmpty() -> { - tilTransferLimit.error = getString(R.string.enter_transfer_limit) - return - } - - tilTransferLimit.editText?.text.toString() == "." -> { - tilTransferLimit.error = getString(R.string.invalid_amount) - return - } - - tilTransferLimit.editText?.text.toString().matches("^0*".toRegex()) -> { - tilTransferLimit.error = getString(R.string.amount_greater_than_zero) - return - } - - tilBeneficiaryName.editText?.text.isNullOrBlank() -> { - tilBeneficiaryName.error = getString(R.string.enter_beneficiary_name) - return - } - - else -> {} - } - } - - if (beneficiaryState == BeneficiaryState.CREATE_MANUAL || - beneficiaryState == BeneficiaryState.CREATE_QR - ) { - submitNewBeneficiaryApplication() - } else if (beneficiaryState == BeneficiaryState.UPDATE) { - submitUpdateBeneficiaryApplication() - } - } - - private fun onRetry() { - if (Network.isConnected(context)) { - viewModel.loadBeneficiaryTemplate() - sweetUIErrorHandler?.hideSweetErrorLayoutUI( - binding.viewFlipper, - binding.layoutError.root, - ) - } else { - Toaster.show(binding.root, getString(R.string.internet_not_connected)) - } - } - - /** - * Submit a new Beneficiary application - */ - private fun submitNewBeneficiaryApplication() { - val beneficiaryPayload = BeneficiaryPayload() - with(binding) { - beneficiaryPayload.accountNumber = tilAccountNumber.editText?.text.toString() - beneficiaryPayload.officeName = tilOfficeName.editText?.text.toString() - beneficiaryPayload.name = tilBeneficiaryName.editText?.text.toString() - beneficiaryPayload.transferLimit = - tilTransferLimit.editText?.text.toString().toInt().toFloat() - } - - beneficiaryPayload.accountType = accountTypeId - viewModel.createBeneficiary(beneficiaryPayload) - } - - /** - * Updates an existing beneficiary application - */ - private fun submitUpdateBeneficiaryApplication() { - val payload = BeneficiaryUpdatePayload() - payload.name = binding.tilBeneficiaryName.editText?.text.toString() - payload.transferLimit = binding.tilTransferLimit.editText?.text.toString().toFloat() - viewModel.updateBeneficiary(beneficiary?.id?.toLong(), payload) - } - - /** - * Displays a {@link Snackbar} on successfully creation of - * Beneficiary and pops fragments in order to go back to [BeneficiaryListFragment] - */ - private fun showBeneficiaryCreatedSuccessfully() { - Toaster.show(binding.tilTransferLimit, getString(R.string.beneficiary_created_successfully)) - activity?.finish() - } - - /** - * Displays a {@link Snackbar} on successfully updation of - * Beneficiary and pops fragments in order to go back to [BeneficiaryListFragment] - */ - private fun showBeneficiaryUpdatedSuccessfully() { - Toaster.show(binding.root, getString(R.string.beneficiary_updated_successfully)) - activity?.supportFragmentManager?.popBackStack() - activity?.supportFragmentManager?.popBackStack() - } - - /** - * It is called whenever any error occurs while executing a request - * - * @param msg Error message that tells the user about the problem. - */ - fun showError(msg: String?) { - if (!Network.isConnected(context)) { - sweetUIErrorHandler?.showSweetNoInternetUI( - binding.viewFlipper, - binding.layoutError.root, - ) - } else { - sweetUIErrorHandler?.showSweetErrorUI( - msg, - binding.viewFlipper, - binding.layoutError.root, - ) - Toaster.show(binding.root, msg) - } - } - - private fun setVisibility(state: Int) { - binding.llApplicationBeneficiary.visibility = state - } - - fun showProgress() { - showProgressBar() - } - - fun hideProgress() { - hideProgressBar() - } - - override fun onDestroyView() { - super.onDestroyView() - hideProgress() - _binding = null - } - - companion object { - fun newInstance( - beneficiaryState: BeneficiaryState?, - beneficiary: Beneficiary?, - ): BeneficiaryApplicationFragment { - val fragment = BeneficiaryApplicationFragment() - val args = Bundle() - args.putSerializable(Constants.BENEFICIARY_STATE, beneficiaryState) - if (beneficiary != null) { - args.putParcelable(Constants.BENEFICIARY, beneficiary) - } - fragment.arguments = args - return fragment - } - } -} 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 deleted file mode 100644 index 2b56b96fd..000000000 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/BeneficiaryListFragment.kt +++ /dev/null @@ -1,272 +0,0 @@ -package org.mifos.mobile.ui.fragments - -import android.content.Intent -import android.os.Bundle -import android.os.Parcelable -import android.view.LayoutInflater -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 androidx.recyclerview.widget.LinearLayoutManager -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener -import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import org.mifos.mobile.R -import org.mifos.mobile.databinding.FragmentBeneficiaryListBinding -import org.mifos.mobile.models.beneficiary.Beneficiary -import org.mifos.mobile.ui.activities.AddBeneficiaryActivity -import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.adapters.BeneficiaryListAdapter -import org.mifos.mobile.ui.beneficiary_detail.BeneficiaryDetailFragment -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.DividerItemDecoration -import org.mifos.mobile.utils.Network -import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedArrayListFromParcelable -import org.mifos.mobile.viewModels.BeneficiaryListViewModel - -/** - * Created by dilpreet on 14/6/17. - */ -@AndroidEntryPoint -class BeneficiaryListFragment : BaseFragment(), OnRefreshListener { - - private var _binding: FragmentBeneficiaryListBinding? = null - private val binding get() = _binding!! - - private val viewModel: BeneficiaryListViewModel by viewModels() - - private var beneficiaryListAdapter: BeneficiaryListAdapter? = null - - private var beneficiaryList: List? = null - private var sweetUIErrorHandler: SweetUIErrorHandler? = null - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = FragmentBeneficiaryListBinding.inflate(inflater, container, false) - beneficiaryListAdapter = BeneficiaryListAdapter(::onItemClick) - setToolbarTitle(getString(R.string.beneficiaries)) - sweetUIErrorHandler = SweetUIErrorHandler(activity, binding.root) - showUserInterface() - if (savedInstanceState == null) { - viewModel.loadBeneficiaries() - } - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewLifecycleOwner.lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.beneficiaryUiState.collect { - when (it) { - is BeneficiaryUiState.Loading -> showProgress() - - is BeneficiaryUiState.ShowError -> { - hideProgress() - showError(getString(it.message)) - } - - is BeneficiaryUiState.ShowBeneficiaryList -> { - hideProgress() - showBeneficiaryList(it.beneficiaries) - } - - is BeneficiaryUiState.Initial -> {} - - else -> throw IllegalStateException("Undesired $it") - } - } - } - } - - binding.layoutError.btnTryAgain.setOnClickListener { - retryClicked() - } - } - - override fun onResume() { - super.onResume() - viewModel.loadBeneficiaries() - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - if (beneficiaryList != null) { - outState.putParcelableArrayList( - Constants.BENEFICIARY, - ArrayList( - beneficiaryList, - ), - ) - } - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - if (savedInstanceState != null) { - val beneficiaries: List = - savedInstanceState.getCheckedArrayListFromParcelable( - Beneficiary::class.java, - Constants.BENEFICIARY - ) ?: listOf() - showBeneficiaryList(beneficiaries) - } - } - - /** - * Setup Initial User Interface - */ - fun showUserInterface() { - val layoutManager = LinearLayoutManager(activity) - layoutManager.orientation = LinearLayoutManager.VERTICAL - with(binding) { - rvBeneficiaries.layoutManager = layoutManager - rvBeneficiaries.setHasFixedSize(true) - rvBeneficiaries.addItemDecoration( - DividerItemDecoration( - (activity?.applicationContext)!!, - layoutManager.orientation, - ), - ) - rvBeneficiaries.adapter = beneficiaryListAdapter - swipeContainer.setColorSchemeColors( - *requireActivity() - .resources.getIntArray(R.array.swipeRefreshColors), - ) - swipeContainer.setOnRefreshListener(this@BeneficiaryListFragment) - fabAddBeneficiary.setOnClickListener { - startActivity( - Intent( - activity, - AddBeneficiaryActivity::class.java, - ), - ) - } - } - } - - private fun retryClicked() { - if (Network.isConnected((context?.applicationContext)!!)) { - sweetUIErrorHandler?.hideSweetErrorLayoutUI( - binding.rvBeneficiaries, - binding.layoutError.root, - ) - viewModel.loadBeneficiaries() - } else { - Toast.makeText( - context, - getString(R.string.internet_not_connected), - Toast.LENGTH_SHORT, - ).show() - } - } - - /** - * Refreshes `beneficiaryList` by calling `loadBeneficiaries()` - */ - override fun onRefresh() { - if (binding.layoutError.root.visibility == View.VISIBLE) { - sweetUIErrorHandler?.hideSweetErrorLayoutUI( - binding.rvBeneficiaries, - binding.layoutError.root, - ) - } - viewModel.loadBeneficiaries() - } - - /** - * Shows [SwipeRefreshLayout] - */ - fun showProgress() { - showSwipeRefreshLayout(true) - } - - /** - * Hides [SwipeRefreshLayout] - */ - fun hideProgress() { - showSwipeRefreshLayout(false) - } - - /** - * It is called whenever any error occurs while executing a request - * - * @param msg Error message that tells the user about the problem. - */ - fun showError(msg: String?) { - if (!Network.isConnected((activity?.applicationContext)!!)) { - sweetUIErrorHandler?.showSweetNoInternetUI( - binding.rvBeneficiaries, - binding.layoutError.root, - ) - } else { - sweetUIErrorHandler?.showSweetErrorUI( - msg, - binding.rvBeneficiaries, - binding.layoutError.root, - ) - } - } - - /** - * Set the `beneficiaryList` fetched from server to `beneficiaryListAdapter` - */ - private fun showBeneficiaryList(beneficiaryList: List?) { - this.beneficiaryList = beneficiaryList - if (beneficiaryList?.isNotEmpty() == true) { - beneficiaryListAdapter?.setBeneficiaryList(beneficiaryList) - } else { - showEmptyBeneficiary() - } - } - - private fun onItemClick(position: Int) { - (activity as BaseActivity?)?.replaceFragment( - BeneficiaryDetailFragment.newInstance( - beneficiaryList!![position], - ), - true, - R.id.container, - ) - } - - private fun showSwipeRefreshLayout(show: Boolean?) { - binding.swipeContainer.post { binding.swipeContainer.isRefreshing = (show == true) } - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - /** - * Shows an error layout when this function is called.` - */ - private fun showEmptyBeneficiary() { - sweetUIErrorHandler?.showSweetEmptyUI( - getString(R.string.beneficiary), - getString(R.string.beneficiary), - R.drawable.ic_beneficiaries_48px, - binding.rvBeneficiaries, - binding.layoutError.root, - ) - binding.rvBeneficiaries.visibility = View.GONE - } - - companion object { - fun newInstance(): BeneficiaryListFragment { - return BeneficiaryListFragment() - } - } -} diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeReaderFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeReaderFragment.kt deleted file mode 100644 index f3f1cc01d..000000000 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeReaderFragment.kt +++ /dev/null @@ -1,134 +0,0 @@ -package org.mifos.mobile.ui.fragments - -import android.os.Build -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import com.google.gson.Gson -import com.google.gson.JsonSyntaxException -import com.google.zxing.Result -import dagger.hilt.android.AndroidEntryPoint -import me.dm7.barcodescanner.zxing.ZXingScannerView -import me.dm7.barcodescanner.zxing.ZXingScannerView.ResultHandler -import org.mifos.mobile.R -import org.mifos.mobile.databinding.FragmentScanQrCodeBinding -import org.mifos.mobile.models.beneficiary.Beneficiary -import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.BeneficiaryState -import org.mifos.mobile.ui.fragments.base.BaseFragment - -/** - * Created by dilpreet on 6/7/17. - */ -@AndroidEntryPoint -class QrCodeReaderFragment : BaseFragment(), ResultHandler { - - private var _binding: FragmentScanQrCodeBinding? = null - private val binding get() = _binding!! - - private var flashOn = false - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = FragmentScanQrCodeBinding.inflate(inflater, container, false) - setToolbarTitle(getString(R.string.add_beneficiary)) - binding.viewScanner.setAutoFocus(true) - binding.btnFlash.setOnClickListener { - turnOnFlash() - } - return binding.root - } - - /** - * Sets the [me.dm7.barcodescanner.zxing.ZXingScannerView.ResultHandler] callback and - * opens Camera - */ - override fun onResume() { - super.onResume() - binding.viewScanner.setResultHandler(this) - binding.viewScanner.startCamera() - } - - @Suppress("DEPRECATION") - fun turnOnFlash() { - if (flashOn) { - flashOn = false - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - binding.btnFlash.setImageDrawable( - resources.getDrawable( - R.drawable.ic_flash_on, - null, - ), - ) - } else { - binding.btnFlash.setImageDrawable(resources.getDrawable(R.drawable.ic_flash_on)) - } - binding.viewScanner.flash = false - } else { - flashOn = true - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - binding.btnFlash.setImageDrawable( - resources.getDrawable( - R.drawable.ic_flash_off, - null, - ), - ) - } else { - binding.btnFlash.setImageDrawable(resources.getDrawable(R.drawable.ic_flash_off)) - } - binding.viewScanner.flash = true - } - } - - /** - * Closes the Camera - */ - override fun onPause() { - super.onPause() - binding.viewScanner.stopCamera() - } - - /** - * Callback for [ZXingScannerView] which retrieves data from QRCode - * - * @param result Contains data scanned from QRCode - */ - override fun handleResult(result: Result) { - val gson = Gson() - try { - val beneficiary = gson.fromJson(result.text, Beneficiary::class.java) - activity?.supportFragmentManager?.popBackStack() - (activity as BaseActivity?)?.replaceFragment( - BeneficiaryApplicationFragment.newInstance( - BeneficiaryState.CREATE_QR, - beneficiary, - ), - true, - R.id.container, - ) - } catch (e: JsonSyntaxException) { - Toast.makeText( - activity, - getString(R.string.invalid_qr), - Toast.LENGTH_SHORT, - ).show() - binding.viewScanner.resumeCameraPreview(this) - } - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - companion object { - fun newInstance(): QrCodeReaderFragment { - return QrCodeReaderFragment() - } - } -} diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/base/BaseFragment.kt b/app/src/main/java/org/mifos/mobile/ui/fragments/base/BaseFragment.kt index 63b29f4c8..492921ae4 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/base/BaseFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/fragments/base/BaseFragment.kt @@ -4,9 +4,9 @@ import android.app.Activity import android.content.Context import android.os.Bundle import androidx.fragment.app.Fragment +import org.mifos.mobile.core.common.utils.LanguageHelper +import org.mifos.mobile.core.common.utils.ProgressBarHandler import org.mifos.mobile.ui.views.BaseActivityCallback -import org.mifos.mobile.utils.LanguageHelper -import org.mifos.mobile.utils.ProgressBarHandler open class BaseFragment : Fragment() { private var callback: BaseActivityCallback? = null diff --git a/app/src/main/java/org/mifos/mobile/ui/guarantor/navigation/GuarantorScreen.kt b/app/src/main/java/org/mifos/mobile/ui/guarantor/navigation/GuarantorScreen.kt deleted file mode 100644 index 9a5c5411c..000000000 --- a/app/src/main/java/org/mifos/mobile/ui/guarantor/navigation/GuarantorScreen.kt +++ /dev/null @@ -1,39 +0,0 @@ -package org.mifos.mobile.ui.guarantor.navigation - -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asStateFlow -import org.mifos.mobile.models.guarantor.GuarantorApplicationPayload -import org.mifos.mobile.models.guarantor.GuarantorPayload -import org.mifos.mobile.ui.enums.GuarantorState -import org.mifos.mobile.ui.enums.LoanState -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.Constants.GUARANTOR_ADD_SCREEN_ROUTE_BASE -import org.mifos.mobile.utils.Constants.GUARANTOR_DETAILS -import org.mifos.mobile.utils.Constants.GUARANTOR_DETAIL_SCREEN_ROUTE_BASE -import org.mifos.mobile.utils.Constants.GUARANTOR_LIST_SCREEN_ROUTE_BASE -import org.mifos.mobile.utils.Constants.GUARANTOR_STATE -import org.mifos.mobile.utils.Constants.INDEX -import org.mifos.mobile.utils.Constants.LOAN_ID -import org.mifos.mobile.utils.Constants.LOAN_STATE -import org.mifos.mobile.utils.DateHelper -import javax.inject.Inject -import javax.inject.Scope -import javax.inject.Singleton - -sealed class GuarantorScreen(val route: String) { - data object GuarantorList : GuarantorScreen( - route = "$GUARANTOR_LIST_SCREEN_ROUTE_BASE/{$LOAN_ID}" - ) - - data object GuarantorDetails : GuarantorScreen( - route = "$GUARANTOR_DETAIL_SCREEN_ROUTE_BASE/{$LOAN_ID}/{$INDEX}" - ) { - fun passArguments(index: Int, loanId: Long) = "$GUARANTOR_DETAIL_SCREEN_ROUTE_BASE/$loanId/$index" - } - - data object GuarantorAdd : GuarantorScreen( - route = "$GUARANTOR_ADD_SCREEN_ROUTE_BASE/{$LOAN_ID}/{$INDEX}" - ) { - fun passArguments(index: Int, loanId: Long) = "$GUARANTOR_ADD_SCREEN_ROUTE_BASE/$loanId/$index" - } -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/help/HelpActivity.kt b/app/src/main/java/org/mifos/mobile/ui/help/HelpActivity.kt index 788e84ebb..8157041c7 100644 --- a/app/src/main/java/org/mifos/mobile/ui/help/HelpActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/help/HelpActivity.kt @@ -5,7 +5,6 @@ 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.help.HelpFragment /** * @author Rajan Maurya diff --git a/app/src/main/java/org/mifos/mobile/ui/help/HelpFragment.kt b/app/src/main/java/org/mifos/mobile/ui/help/HelpFragment.kt index d1327dcfd..1d9faa27b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/help/HelpFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/help/HelpFragment.kt @@ -18,8 +18,8 @@ import androidx.lifecycle.repeatOnLifecycle import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.FAQ import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.models.FAQ import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.ui.location.LocationsFragment diff --git a/app/src/main/java/org/mifos/mobile/ui/help/HelpScreen.kt b/app/src/main/java/org/mifos/mobile/ui/help/HelpScreen.kt index ca1c9388a..4e47bb7e0 100644 --- a/app/src/main/java/org/mifos/mobile/ui/help/HelpScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/help/HelpScreen.kt @@ -20,12 +20,12 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.FAQ import org.mifos.mobile.core.ui.component.EmptyDataView import org.mifos.mobile.core.ui.component.FaqItemHolder import org.mifos.mobile.core.ui.component.MifosTextButtonWithTopDrawable import org.mifos.mobile.core.ui.component.MifosTitleSearchCard import org.mifos.mobile.core.ui.component.MifosTopBar -import org.mifos.mobile.models.FAQ @Composable diff --git a/app/src/main/java/org/mifos/mobile/ui/help/HelpViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/help/HelpViewModel.kt index b4bb2e1d2..402fef46f 100644 --- a/app/src/main/java/org/mifos/mobile/ui/help/HelpViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/help/HelpViewModel.kt @@ -4,7 +4,7 @@ import androidx.lifecycle.ViewModel import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import org.mifos.mobile.models.FAQ +import org.mifos.mobile.core.model.entity.FAQ import org.mifos.mobile.utils.HelpUiState import java.util.Locale import javax.inject.Inject diff --git a/app/src/main/java/org/mifos/mobile/ui/home/HomeContent.kt b/app/src/main/java/org/mifos/mobile/ui/home/HomeContent.kt index 3c68999ef..1984772fc 100644 --- a/app/src/main/java/org/mifos/mobile/ui/home/HomeContent.kt +++ b/app/src/main/java/org/mifos/mobile/ui/home/HomeContent.kt @@ -39,7 +39,7 @@ import org.mifos.mobile.core.ui.component.MifosHiddenTextRow import org.mifos.mobile.core.ui.component.MifosLinkText import org.mifos.mobile.core.ui.component.MifosUserImage import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.utils.CurrencyUtil +import org.mifos.mobile.core.common.utils.CurrencyUtil @Composable fun HomeContent( diff --git a/app/src/main/java/org/mifos/mobile/ui/home/HomeOldFragment.kt b/app/src/main/java/org/mifos/mobile/ui/home/HomeOldFragment.kt index d7171031d..f3572a22a 100644 --- a/app/src/main/java/org/mifos/mobile/ui/home/HomeOldFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/home/HomeOldFragment.kt @@ -22,22 +22,21 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener 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.ui.activities.HomeActivity import org.mifos.mobile.ui.activities.LoanApplicationActivity import org.mifos.mobile.ui.activities.NotificationActivity import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.ui.beneficiary_list.BeneficiaryListComposeFragment +import org.mifos.mobile.ui.client_accounts.ClientAccountsComposeFragment import org.mifos.mobile.ui.client_charge.ClientChargeComposeFragment -import org.mifos.mobile.ui.enums.AccountType -import org.mifos.mobile.ui.enums.ChargeType -import org.mifos.mobile.ui.fragments.BeneficiaryListFragment -import org.mifos.mobile.ui.fragments.ClientAccountsFragment +import org.mifos.mobile.core.model.enums.AccountType +import org.mifos.mobile.core.model.enums.ChargeType import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.ui.savings_make_transfer.SavingsMakeTransferComposeFragment import org.mifos.mobile.ui.third_party_transfer.ThirdPartyTransferComposeFragment import org.mifos.mobile.ui.user_profile.UserProfileActivity -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.core.datastore.PreferencesHelper import org.mifos.mobile.utils.MaterialDialog import org.mifos.mobile.utils.Toaster import javax.inject.Inject @@ -140,7 +139,7 @@ class HomeOldFragment : BaseFragment(), OnRefreshListener { if (!isReceiverRegistered) { LocalBroadcastManager.getInstance(requireActivity()).registerReceiver( notificationReceiver, - IntentFilter(Constants.NOTIFY_HOME_FRAGMENT), + IntentFilter(org.mifos.mobile.core.common.Constants.NOTIFY_HOME_FRAGMENT), ) isReceiverRegistered = true } @@ -167,7 +166,7 @@ class HomeOldFragment : BaseFragment(), OnRefreshListener { */ private fun openAccount(accountType: AccountType?) { (activity as BaseActivity?)?.replaceFragment( - ClientAccountsFragment.newInstance(accountType), + ClientAccountsComposeFragment.newInstance(accountType), true, R.id.container, ) @@ -299,7 +298,7 @@ class HomeOldFragment : BaseFragment(), OnRefreshListener { */ fun beneficiaries() { (activity as HomeActivity?)?.replaceFragment( - BeneficiaryListFragment.newInstance(), + BeneficiaryListComposeFragment.newInstance(), true, R.id.container, ) diff --git a/app/src/main/java/org/mifos/mobile/ui/home/HomeViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/home/HomeViewModel.kt index 67830c35a..45afc312c 100644 --- a/app/src/main/java/org/mifos/mobile/ui/home/HomeViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/home/HomeViewModel.kt @@ -13,10 +13,10 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch import org.mifos.mobile.R -import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.models.accounts.loan.LoanAccount -import org.mifos.mobile.models.accounts.savings.SavingAccount -import org.mifos.mobile.repositories.HomeRepository +import org.mifos.mobile.core.data.repositories.HomeRepository +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.model.entity.accounts.loan.LoanAccount +import org.mifos.mobile.core.model.entity.accounts.savings.SavingAccount import org.mifos.mobile.utils.ImageUtil import javax.inject.Inject diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_account/LoanAccountsDetailFragment.kt b/app/src/main/java/org/mifos/mobile/ui/loan_account/LoanAccountsDetailFragment.kt index 5feb1df87..916eac651 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_account/LoanAccountsDetailFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_account/LoanAccountsDetailFragment.kt @@ -9,22 +9,26 @@ 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.common.Constants +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.model.enums.AccountType +import org.mifos.mobile.core.model.enums.ChargeType +import org.mifos.mobile.core.model.enums.LoanState import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.feature.guarantor.screens.GuarantorActivity +import org.mifos.mobile.feature.loan.loan_account.LoanAccountDetailScreen +import org.mifos.mobile.feature.loan.loan_account.LoanAccountsDetailViewModel import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.client_charge.ClientChargeComposeFragment -import org.mifos.mobile.ui.enums.AccountType -import org.mifos.mobile.ui.enums.ChargeType -import org.mifos.mobile.ui.enums.LoanState import org.mifos.mobile.ui.loan_account_transaction.LoanAccountTransactionFragment import org.mifos.mobile.ui.loan_account_withdraw.LoanAccountWithdrawFragment import org.mifos.mobile.ui.loan_account_application.LoanApplicationFragment import org.mifos.mobile.ui.loan_repayment_schedule.LoanRepaymentScheduleFragment -import org.mifos.mobile.ui.fragments.QrCodeDisplayFragment import org.mifos.mobile.ui.savings_make_transfer.SavingsMakeTransferFragment import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.guarantor.GuarantorActivity import org.mifos.mobile.ui.loan_account_summary.LoanAccountSummaryFragment +import org.mifos.mobile.ui.qr_code_display.QrCodeDisplayComposeFragment import org.mifos.mobile.ui.savings_make_transfer.SavingsMakeTransferComposeFragment import org.mifos.mobile.utils.* import javax.inject.Inject @@ -45,7 +49,7 @@ class LoanAccountsDetailFragment : BaseFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (arguments != null) { - viewModel.setLoanId(arguments?.getLong(Constants.LOAN_ID)) + viewModel.setLoanId(arguments?.getLong(org.mifos.mobile.core.common.Constants.LOAN_ID)) } } @@ -92,7 +96,7 @@ class LoanAccountsDetailFragment : BaseFragment() { SavingsMakeTransferComposeFragment.newInstance( viewModel.loanId, viewModel.loanWithAssociations?.summary?.totalOutstanding, - Constants.TRANSFER_PAY_TO, + org.mifos.mobile.core.common.Constants.TRANSFER_PAY_TO, ), true, R.id.container, @@ -156,7 +160,7 @@ class LoanAccountsDetailFragment : BaseFragment() { AccountType.LOAN, ) (activity as BaseActivity?)?.replaceFragment( - QrCodeDisplayFragment.newInstance( + QrCodeDisplayComposeFragment.newInstance( accountDetailsInJson, ), true, @@ -199,7 +203,7 @@ class LoanAccountsDetailFragment : BaseFragment() { private fun viewGuarantor() { val intent = Intent(requireContext(), GuarantorActivity::class.java) - intent.putExtra(Constants.LOAN_ID, viewModel.loanId) + intent.putExtra(org.mifos.mobile.core.common.Constants.LOAN_ID, viewModel.loanId) startActivity(intent) } diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_account_application/LoanApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/loan_account_application/LoanApplicationFragment.kt index d1bbb6c69..b535820ca 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_account_application/LoanApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_account_application/LoanApplicationFragment.kt @@ -4,23 +4,23 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -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.core.common.Constants.LOAN_STATE +import org.mifos.mobile.core.common.utils.DateHelper +import org.mifos.mobile.core.model.entity.accounts.loan.LoanWithAssociations +import org.mifos.mobile.core.model.entity.payload.LoansPayload import org.mifos.mobile.core.ui.component.mifosComposeView -import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.models.accounts.loan.LoanAccount -import org.mifos.mobile.models.accounts.loan.LoanWithAssociations -import org.mifos.mobile.models.payload.LoansPayload import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.LoanState -import org.mifos.mobile.ui.loan_review.ReviewLoanApplicationFragment.Companion.newInstance +import org.mifos.mobile.core.model.enums.LoanState +import org.mifos.mobile.feature.loan.loan_account_application.LoanApplicationScreen +import org.mifos.mobile.feature.loan.loan_account_application.LoanApplicationViewModel 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.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedSerializable +import org.mifos.mobile.ui.loan_review.ReviewLoanApplicationFragment /** * Created by Rajan Maurya on 06/03/17. @@ -35,9 +35,11 @@ class LoanApplicationFragment : BaseFragment() { (activity as? BaseActivity)?.hideToolbar() if (arguments != null) { - viewModel.loanState = arguments?.getCheckedSerializable(LoanState::class.java, Constants.LOAN_STATE) as? LoanState ?: LoanState.CREATE - if (viewModel.loanState == LoanState.UPDATE) { - viewModel.loanWithAssociations = arguments?.getCheckedParcelable(LoanWithAssociations::class.java, Constants.LOAN_ACCOUNT) + viewModel.loanState = arguments?.getCheckedSerializable(LoanState::class.java, LOAN_STATE) as? LoanState + ?: LoanState.CREATE + if (viewModel.loanState == org.mifos.mobile.core.model.enums.LoanState.UPDATE) { + viewModel.loanWithAssociations = arguments?.getCheckedParcelable( + LoanWithAssociations::class.java, org.mifos.mobile.core.common.Constants.LOAN_ACCOUNT) } } } @@ -83,7 +85,7 @@ class LoanApplicationFragment : BaseFragment() { } (activity as BaseActivity?)?.replaceFragment( - newInstance( + ReviewLoanApplicationFragment.newInstance( viewModel.loanState, loansPayload, getString(R.string.string_and_string, getString(R.string.new_loan_application) + " ", viewModel.loanApplicationScreenData.value.clientName ?: ""), @@ -116,7 +118,7 @@ class LoanApplicationFragment : BaseFragment() { } (activity as BaseActivity?)?.replaceFragment( - newInstance( + ReviewLoanApplicationFragment.newInstance( viewModel.loanState, loansPayload, viewModel.loanWithAssociations?.id?.toLong(), @@ -139,7 +141,7 @@ class LoanApplicationFragment : BaseFragment() { fun newInstance(loanState: LoanState?): LoanApplicationFragment { val fragment = LoanApplicationFragment() val args = Bundle() - args.putSerializable(Constants.LOAN_STATE, loanState) + args.putSerializable(org.mifos.mobile.core.common.Constants.LOAN_STATE, loanState) fragment.arguments = args return fragment } @@ -152,13 +154,13 @@ class LoanApplicationFragment : BaseFragment() { * @return Instance of [LoanApplicationFragment] */ fun newInstance( - loanState: LoanState?, + loanState: org.mifos.mobile.core.model.enums.LoanState?, loanWithAssociations: LoanWithAssociations?, ): LoanApplicationFragment { val fragment = LoanApplicationFragment() val args = Bundle() - args.putSerializable(Constants.LOAN_STATE, loanState) - args.putParcelable(Constants.LOAN_ACCOUNT, loanWithAssociations) + args.putSerializable(org.mifos.mobile.core.common.Constants.LOAN_STATE, loanState) + args.putParcelable(org.mifos.mobile.core.common.Constants.LOAN_ACCOUNT, loanWithAssociations) fragment.arguments = args return fragment } diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_account_summary/LoanAccountSummaryFragment.kt b/app/src/main/java/org/mifos/mobile/ui/loan_account_summary/LoanAccountSummaryFragment.kt index ea869c9e9..71c588d4e 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_account_summary/LoanAccountSummaryFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_account_summary/LoanAccountSummaryFragment.kt @@ -7,16 +7,13 @@ import android.view.ViewGroup import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import dagger.hilt.android.AndroidEntryPoint -import org.mifos.mobile.R import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.databinding.FragmentLoanAccountSummaryBinding -import org.mifos.mobile.models.accounts.loan.LoanWithAssociations import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.savings_account.SavingsAccountDetailScreen -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.CurrencyUtil -import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.core.common.Constants +import org.mifos.mobile.core.model.entity.accounts.loan.LoanWithAssociations +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.feature.loan.loan_account_summary.LoanAccountSummaryScreen /* ~This project is licensed under the open source MPL V2. diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_account_transaction/LoanAccountTransactionFragment.kt b/app/src/main/java/org/mifos/mobile/ui/loan_account_transaction/LoanAccountTransactionFragment.kt index 76a8dc98e..2dae2d1ac 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_account_transaction/LoanAccountTransactionFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_account_transaction/LoanAccountTransactionFragment.kt @@ -9,7 +9,9 @@ import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.core.ui.component.mifosComposeView import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.core.common.Constants +import org.mifos.mobile.feature.loan.loan_account_transaction.LoanAccountTransactionScreen +import org.mifos.mobile.feature.loan.loan_account_transaction.LoanAccountTransactionViewModel /* ~This project is licensed under the open source MPL V2. diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_account_withdraw/LoanAccountWithdrawFragment.kt b/app/src/main/java/org/mifos/mobile/ui/loan_account_withdraw/LoanAccountWithdrawFragment.kt index 5dc4b5946..eeae4b3a8 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_account_withdraw/LoanAccountWithdrawFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_account_withdraw/LoanAccountWithdrawFragment.kt @@ -7,24 +7,15 @@ import android.view.ViewGroup import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.fragment.app.viewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import org.mifos.mobile.R import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.databinding.FragmentLoanWithdrawBinding -import org.mifos.mobile.models.accounts.loan.LoanWithAssociations -import org.mifos.mobile.models.accounts.loan.LoanWithdraw import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.savings_account_withdraw.SavingsAccountWithdrawScreen -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.core.common.Constants +import org.mifos.mobile.core.model.entity.accounts.loan.LoanWithAssociations +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.feature.loan.loan_account_withdraw.LoanAccountWithdrawScreen +import org.mifos.mobile.feature.loan.loan_account_withdraw.LoanAccountWithdrawViewModel /** * Created by dilpreet on 7/6/17. diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_repayment_schedule/LoanRepaymentScheduleFragment.kt b/app/src/main/java/org/mifos/mobile/ui/loan_repayment_schedule/LoanRepaymentScheduleFragment.kt index 858cdc1ad..ac86c18c4 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_repayment_schedule/LoanRepaymentScheduleFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_repayment_schedule/LoanRepaymentScheduleFragment.kt @@ -9,7 +9,8 @@ import androidx.compose.ui.platform.ViewCompositionStrategy import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.core.ui.theme.MifosMobileTheme import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.core.common.Constants +import org.mifos.mobile.feature.loan.loan_repayment_schedule.LoanRepaymentScheduleScreen /** * Created by Rajan Maurya on 03/03/17. diff --git a/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationFragment.kt index b79a2a054..de5b42a27 100644 --- a/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/loan_review/ReviewLoanApplicationFragment.kt @@ -8,13 +8,15 @@ 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.core.model.entity.payload.LoansPayload +import org.mifos.mobile.core.model.enums.LoanState import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.models.payload.LoansPayload +import org.mifos.mobile.feature.loan.loan_review.ReviewLoanApplicationScreen +import org.mifos.mobile.feature.loan.loan_review.ReviewLoanApplicationViewModel import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.LoanState import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable -import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedSerializable +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedSerializable @AndroidEntryPoint class ReviewLoanApplicationFragment : BaseFragment() { diff --git a/app/src/main/java/org/mifos/mobile/ui/login/LoginActivity.kt b/app/src/main/java/org/mifos/mobile/ui/login/LoginActivity.kt index b1301642b..346951d24 100644 --- a/app/src/main/java/org/mifos/mobile/ui/login/LoginActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/login/LoginActivity.kt @@ -16,9 +16,8 @@ import org.mifos.mobile.core.ui.theme.MifosMobileTheme import org.mifos.mobile.ui.activities.PassCodeActivity import org.mifos.mobile.ui.registration.RegistrationActivity import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.utils.Constants import org.mifos.mobile.utils.LoginUiState -import org.mifos.mobile.utils.Network +import org.mifos.mobile.core.common.Network /** * @author Vishwajeet @@ -216,7 +215,7 @@ class LoginActivity : BaseActivity() { private fun startPassCodeActivity() { val intent = Intent(this@LoginActivity, PassCodeActivity::class.java) - intent.putExtra(Constants.INTIAL_LOGIN, true) + intent.putExtra(org.mifos.mobile.core.common.Constants.INTIAL_LOGIN, true) startActivity(intent) finish() } diff --git a/app/src/main/java/org/mifos/mobile/ui/login/LoginViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/login/LoginViewModel.kt index ad330a095..a61c5a58d 100644 --- a/app/src/main/java/org/mifos/mobile/ui/login/LoginViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/login/LoginViewModel.kt @@ -7,8 +7,8 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch -import org.mifos.mobile.repositories.ClientRepository -import org.mifos.mobile.repositories.UserAuthRepository +import org.mifos.mobile.core.data.repositories.ClientRepository +import org.mifos.mobile.core.data.repositories.UserAuthRepository import org.mifos.mobile.utils.LoginUiState import javax.inject.Inject diff --git a/app/src/main/java/org/mifos/mobile/ui/notification/NotificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/notification/NotificationFragment.kt index fbb8d8c58..002d6bd3c 100644 --- a/app/src/main/java/org/mifos/mobile/ui/notification/NotificationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/notification/NotificationFragment.kt @@ -4,27 +4,10 @@ import android.os.Bundle import android.view.LayoutInflater 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 androidx.recyclerview.widget.LinearLayoutManager -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener -import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import org.mifos.mobile.BuildConfig -import org.mifos.mobile.R import org.mifos.mobile.core.ui.component.mifosComposeView -import org.mifos.mobile.databinding.FragmentNotificationBinding -import org.mifos.mobile.models.notification.MifosNotification import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.adapters.NotificationAdapter import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.utils.DividerItemDecoration -import org.mifos.mobile.utils.Network -import javax.inject.Inject /** * Created by dilpreet on 13/9/17. diff --git a/app/src/main/java/org/mifos/mobile/ui/notification/NotificationScreen.kt b/app/src/main/java/org/mifos/mobile/ui/notification/NotificationScreen.kt index f9f056dba..8c2974228 100644 --- a/app/src/main/java/org/mifos/mobile/ui/notification/NotificationScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/notification/NotificationScreen.kt @@ -1,8 +1,5 @@ package org.mifos.mobile.ui.notification -import android.content.res.Configuration -import android.util.Log -import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -12,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider @@ -26,7 +22,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -35,24 +30,21 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp -import androidx.core.content.ContextCompat import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import org.checkerframework.checker.units.qual.UnitsMultiple import org.mifos.mobile.R import org.mifos.mobile.core.ui.component.EmptyDataView import org.mifos.mobile.core.ui.component.MFScaffold import org.mifos.mobile.core.ui.component.MifosErrorComponent import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.models.notification.MifosNotification -import org.mifos.mobile.utils.DateHelper -import org.mifos.mobile.utils.Network +import org.mifos.mobile.core.common.utils.DateHelper +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.datastore.model.MifosNotification @Composable fun NotificationScreen( diff --git a/app/src/main/java/org/mifos/mobile/ui/notification/NotificationViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/notification/NotificationViewModel.kt index ef40f9fc2..3bab85ace 100644 --- a/app/src/main/java/org/mifos/mobile/ui/notification/NotificationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/notification/NotificationViewModel.kt @@ -8,9 +8,8 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch -import org.mifos.mobile.models.notification.MifosNotification -import org.mifos.mobile.repositories.NotificationRepository -import org.mifos.mobile.utils.DateHelper +import org.mifos.mobile.core.data.repositories.NotificationRepository +import org.mifos.mobile.core.datastore.model.MifosNotification import javax.inject.Inject @HiltViewModel diff --git a/app/src/main/java/org/mifos/mobile/ui/qr/BarcodeCamera.kt b/app/src/main/java/org/mifos/mobile/ui/qr/BarcodeCamera.kt new file mode 100644 index 000000000..d62b1cf40 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/qr/BarcodeCamera.kt @@ -0,0 +1,114 @@ +package org.mifos.mobile.ui.qr + +import android.Manifest +import android.content.ContentValues.TAG +import android.content.Context +import android.os.Build +import androidx.camera.core.Camera +import android.util.Log +import android.view.ViewGroup +import android.widget.LinearLayout +import androidx.camera.core.CameraSelector +import androidx.camera.core.ExperimentalGetImage +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageCapture +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.view.PreviewView +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.viewinterop.AndroidView +import androidx.core.content.ContextCompat +import androidx.lifecycle.LifecycleOwner +import org.mifos.mobile.utils.QrCodeAnalyzer + +@ExperimentalGetImage +class BarcodeCamera { + + private var camera: Camera? = null + + @Composable + fun BarcodeReaderCamera( + onBarcodeScanned: (String?) -> Unit, + isFlashOn: Boolean, + ) { + LaunchedEffect(isFlashOn) { + toggleFlash(isOn = isFlashOn) + } + + val lifecycleOwner = LocalLifecycleOwner.current + + val imageCapture = remember { + ImageCapture.Builder().build() + } + + AndroidView( + factory = { context -> + PreviewView(context).apply { + layoutParams = + LinearLayout.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + ViewGroup.LayoutParams.MATCH_PARENT + ) + scaleType = PreviewView.ScaleType.FILL_START + + startCamera( + context = context, + previewView = this, + imageCapture = imageCapture, + lifecycleOwner = lifecycleOwner, + onBarcodeScanned = onBarcodeScanned + ) + } + } + ) + } + + private fun startCamera( + context: Context, + previewView: PreviewView, + lifecycleOwner: LifecycleOwner, + imageCapture: ImageCapture, + onBarcodeScanned: (String) -> Unit + ) { + val cameraProviderFuture = ProcessCameraProvider.getInstance(context) + + cameraProviderFuture.addListener( + { + val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get() + + val preview = Preview.Builder().build() + .also { it.setSurfaceProvider(previewView.surfaceProvider) } + + val imageAnalysis = ImageAnalysis.Builder() + .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST) + .build() + + imageAnalysis.setAnalyzer( + ContextCompat.getMainExecutor(context), + QrCodeAnalyzer( + onBarcodeScanned = onBarcodeScanned + ) + ) + + val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA + + try { + cameraProvider.unbindAll() + camera = cameraProvider.bindToLifecycle(lifecycleOwner, cameraSelector, preview, imageCapture, imageAnalysis) + } catch (exc: Exception) { + Log.e(TAG, "Use case binding failed", exc) + } + }, + ContextCompat.getMainExecutor(context) + ) + } + + private fun toggleFlash( + isOn: Boolean, + ) { + camera?.cameraControl?.enableTorch(isOn) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/qr/QrCodeReaderFragment.kt b/app/src/main/java/org/mifos/mobile/ui/qr/QrCodeReaderFragment.kt new file mode 100644 index 000000000..db76a4620 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/qr/QrCodeReaderFragment.kt @@ -0,0 +1,66 @@ +package org.mifos.mobile.ui.qr + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import com.google.gson.Gson +import com.google.gson.JsonSyntaxException +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.core.model.enums.BeneficiaryState +import org.mifos.mobile.ui.beneficiary_application.BeneficiaryApplicationComposeFragment +import org.mifos.mobile.ui.fragments.base.BaseFragment + +/** + * Created by dilpreet on 6/7/17. + */ +@AndroidEntryPoint +class QrCodeReaderFragment : BaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + (activity as? BaseActivity)?.hideToolbar() + return mifosComposeView(requireContext()) { + QrCodeReaderScreen( + qrScanned = { qrScanned(it) }, + navigateBack = { activity?.supportFragmentManager?.popBackStack() } + ) + } + } + + private fun qrScanned(text: String) { + val gson = Gson() + try { + val beneficiary = gson.fromJson(text, Beneficiary::class.java) + activity?.supportFragmentManager?.popBackStack() + (activity as BaseActivity?)?.replaceFragment( + BeneficiaryApplicationComposeFragment.newInstance( + BeneficiaryState.CREATE_QR, + beneficiary, + ), + true, + R.id.container, + ) + } catch (e: JsonSyntaxException) { + Toast.makeText( + activity, + getString(R.string.invalid_qr), + Toast.LENGTH_SHORT, + ).show() + } + } + + companion object { + fun newInstance(): QrCodeReaderFragment { + return QrCodeReaderFragment() + } + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/qr/QrCodeReaderScreen.kt b/app/src/main/java/org/mifos/mobile/ui/qr/QrCodeReaderScreen.kt new file mode 100644 index 000000000..1bdee5a01 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/qr/QrCodeReaderScreen.kt @@ -0,0 +1,90 @@ +package org.mifos.mobile.ui.qr + +import androidx.annotation.OptIn +import androidx.camera.core.ExperimentalGetImage +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +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.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.MFScaffold +import org.mifos.mobile.core.ui.component.MifosIcons +import org.mifos.mobile.core.ui.theme.MifosMobileTheme + +@Composable +fun QrCodeReaderScreen( + qrScanned: (String) -> Unit, + navigateBack: () -> Unit +) { + MFScaffold( + topBarTitleResId = R.string.add_beneficiary, + navigateBack = navigateBack, + scaffoldContent = { + Box(modifier = Modifier + .padding(it) + .fillMaxSize()) { + QrCodeReaderContent( + qrScanned = qrScanned, + navigateBack = navigateBack + ) + } + } + ) +} + +@OptIn(ExperimentalGetImage::class) +@Composable +fun QrCodeReaderContent( + qrScanned: (String) -> Unit, + navigateBack: () -> Unit +) { + val camera = remember { BarcodeCamera() } + var isFlashOn by remember { mutableStateOf(false) } + + Box { + camera.BarcodeReaderCamera( + onBarcodeScanned = { barcode -> + barcode?.let { + qrScanned(it) + navigateBack() + } + }, + isFlashOn = isFlashOn, + ) + + IconButton( + onClick = { isFlashOn = !isFlashOn }, + content = { + Icon( + imageVector = if(isFlashOn) MifosIcons.FlashOn + else MifosIcons.FlashOff, + contentDescription = null + ) + }, + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 20.dp) + ) + } +} + +@Preview(showSystemUi = true) +@Composable +fun QrCodeReaderScreenPreview() { + MifosMobileTheme { + QrCodeReaderScreen( + qrScanned = {}, + navigateBack = {} + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayComposeFragment.kt new file mode 100644 index 000000000..4b101352b --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayComposeFragment.kt @@ -0,0 +1,48 @@ +package org.mifos.mobile.ui.qr_code_display + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.viewModels +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.core.common.Constants + +@AndroidEntryPoint +class QrCodeDisplayComposeFragment : BaseFragment() { + + private val viewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + (activity as? BaseActivity)?.hideToolbar() + if (arguments != null) { + viewModel.setQrString(arguments?.getString(Constants.QR_DATA)) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + return mifosComposeView(requireContext()) { + QrCodeDisplayScreen( + navigateBack = { activity?.onBackPressed() } + ) + } + } + + companion object { + fun newInstance(json: String?): QrCodeDisplayComposeFragment { + val fragment = QrCodeDisplayComposeFragment() + val args = Bundle() + args.putString(Constants.QR_DATA, json) + fragment.arguments = args + return fragment + } + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeDisplayFragment.kt b/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayFragment.kt similarity index 93% rename from app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeDisplayFragment.kt rename to app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayFragment.kt index d7410b431..15f086deb 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeDisplayFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayFragment.kt @@ -1,4 +1,4 @@ -package org.mifos.mobile.ui.fragments +package org.mifos.mobile.ui.qr_code_display import android.content.Intent import android.graphics.drawable.BitmapDrawable @@ -12,12 +12,11 @@ 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.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.utils.Constants +import org.mifos.mobile.core.common.Constants import org.mifos.mobile.utils.QrCodeGenerator -import org.mifos.mobile.utils.Utils +import org.mifos.mobile.core.common.utils.Utils /** * Created by dilpreet on 16/8/17. diff --git a/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayScreen.kt b/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayScreen.kt new file mode 100644 index 000000000..dde35a4b0 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayScreen.kt @@ -0,0 +1,163 @@ +package org.mifos.mobile.ui.qr_code_display + +import android.content.Context +import android.content.Intent +import android.graphics.Bitmap +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.Share +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import androidx.core.content.ContextCompat.startActivity +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.MFScaffold +import org.mifos.mobile.core.ui.component.MifosErrorComponent +import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay +import org.mifos.mobile.core.ui.component.MifosTopBar +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.core.common.utils.Utils + + +@Composable +fun QrCodeDisplayScreen( + viewModel: QrCodeDisplayViewModel = hiltViewModel(), + navigateBack: () -> Unit +) { + val uiState by viewModel.qrCodeDisplayUiState.collectAsStateWithLifecycle() + QrCodeDisplayScreen( + uiState = uiState, + navigateBack = navigateBack + ) +} + +@Composable +fun QrCodeDisplayScreen( + uiState: QrCodeDisplayUiState, + navigateBack: () -> Unit +) { + val context = LocalContext.current + var qrBitmap by rememberSaveable { mutableStateOf(null) } + + MFScaffold( + topBar = { + MifosTopBar( + navigateBack = navigateBack, + title = { Text(text = stringResource(id = R.string.qr_code)) }, + actions = { + IconButton( + onClick = { + qrBitmap?.let { qrBitmap -> + onShareClicked(context = context, qrBitmap = qrBitmap) + } + }, + content = { + Icon( + imageVector = Icons.Default.Share, + contentDescription = null + ) + } + ) + } + ) + }, + scaffoldContent = { paddingValues -> + Box( + modifier = Modifier + .padding(paddingValues = paddingValues) + .fillMaxSize() + ) { + when (uiState) { + is QrCodeDisplayUiState.Error -> { + MifosErrorComponent(message = stringResource(id = R.string.something_went_wrong)) + } + + is QrCodeDisplayUiState.Loading -> { + MifosProgressIndicatorOverlay() + } + + is QrCodeDisplayUiState.Success -> { + qrBitmap = uiState.qrBitmap + QrCodeDisplayContent(qrBitmap = uiState.qrBitmap) + } + } + } + } + ) +} + +@Composable +fun QrCodeDisplayContent( + qrBitmap: Bitmap +) { + Box( + contentAlignment = Alignment.Center, + modifier = Modifier.fillMaxSize() + ) { + Image( + bitmap = qrBitmap.asImageBitmap(), + contentDescription = stringResource(id = R.string.qr_code), + modifier = Modifier.padding(20.dp).aspectRatio(1f) + ) + } +} + +private fun onShareClicked(context: Context, qrBitmap: Bitmap) { + val uri = Utils.getImageUri(context, qrBitmap) + + val intent = Intent(Intent.ACTION_SEND).apply { + type = "image/*" + putExtra(Intent.EXTRA_STREAM, uri) + addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) + } + + startActivity( + context, + Intent.createChooser(intent, context.getString(R.string.choose_option)), + null + ) +} + +class QrCodeDisplayScreenPreviewProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + QrCodeDisplayUiState.Loading, + QrCodeDisplayUiState.Error(""), + QrCodeDisplayUiState.Success( Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)) + ) +} + +@Preview(showSystemUi = true) +@Composable +private fun QrCodeDisplayScreenPreview( + @PreviewParameter(QrCodeDisplayScreenPreviewProvider::class) qrCodeDisplayUiState: QrCodeDisplayUiState +) { + MifosMobileTheme { + QrCodeDisplayScreen ( + uiState = qrCodeDisplayUiState, + navigateBack = {} + ) + } +} + + diff --git a/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayViewModel.kt new file mode 100644 index 000000000..9723d2980 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/qr_code_display/QrCodeDisplayViewModel.kt @@ -0,0 +1,63 @@ +package org.mifos.mobile.ui.qr_code_display + +import android.graphics.Bitmap +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import org.mifos.mobile.core.logs.AnalyticsEvent +import org.mifos.mobile.core.logs.AnalyticsHelper +import org.mifos.mobile.utils.QrCodeGenerator +import javax.inject.Inject + +@HiltViewModel +class QrCodeDisplayViewModel @Inject constructor( + private var analyticsHelper: AnalyticsHelper +): ViewModel() { + + private var qrString: MutableStateFlow = MutableStateFlow(null) + + val qrCodeDisplayUiState = qrString + .flatMapLatest { qrString -> + flow { + val qrBitmap = QrCodeGenerator.encodeAsBitmap(str = qrString) + if(qrBitmap == null) { + emit(QrCodeDisplayUiState.Error()) + } else { + emit(QrCodeDisplayUiState.Success(qrBitmap = qrBitmap)) + } + } + }.catch { + analyticsHelper.logEvent( + AnalyticsEvent( + type = AnalyticsEvent.AnalyticsEventTypes.EXCEPTION.type, + listOf( + AnalyticsEvent.Param(key = AnalyticsEvent.ParamKeys.SCREEN_NAME, value = it.message ?: "") + ) + ) + ) + emit(QrCodeDisplayUiState.Error(errorMessage = it.message)) + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(300), + initialValue = QrCodeDisplayUiState.Loading + ) + + fun setQrString(qrStr: String?) { + viewModelScope.launch { qrString.emit(qrStr) } + + } +} + +sealed class QrCodeDisplayUiState { + data object Loading: QrCodeDisplayUiState() + data class Success(val qrBitmap: Bitmap) : QrCodeDisplayUiState() + data class Error(val errorMessage: String? = null): QrCodeDisplayUiState() +} + diff --git a/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportComposeFragment.kt new file mode 100644 index 000000000..26fadfc9f --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportComposeFragment.kt @@ -0,0 +1,91 @@ +package org.mifos.mobile.ui.qr_code_import + +import android.os.Build +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.annotation.RequiresApi +import androidx.core.app.ActivityCompat +import com.google.gson.Gson +import com.google.gson.JsonSyntaxException +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.ui.beneficiary_application.BeneficiaryApplicationComposeFragment +import org.mifos.mobile.core.model.enums.BeneficiaryState +import org.mifos.mobile.ui.fragments.base.BaseFragment +import com.google.zxing.Result +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary + +@AndroidEntryPoint +class QrCodeImportComposeFragment : BaseFragment() { + @RequiresApi(Build.VERSION_CODES.TIRAMISU) + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + return mifosComposeView(requireContext()) { + QrCodeImportScreen( + navigateBack = { + activity?.onBackPressedDispatcher?.onBackPressed() + }, + handleDecodedResult = { result -> + handleDecodedResult(result) + }, + showRationaleChecker = { + checkPermissionRationale(it) + } + ) + } + } + + /** + * CallBack for [Image-Cropper] which retrieves data from QRCode + * Opens [BeneficiaryApplicationFragment] with [BeneficiaryState] as + * `BeneficiaryState.CREATE_QR` + * + * @param result contains the results from decoded QR bitmap + */ + + private fun handleDecodedResult(result: Result?) { + val gson = Gson() + try { + val beneficiary = gson.fromJson(result?.text, Beneficiary::class.java) + activity?.supportFragmentManager?.popBackStack() + (activity as BaseActivity?)?.replaceFragment( + BeneficiaryApplicationComposeFragment.newInstance( + BeneficiaryState.CREATE_QR, + beneficiary + ), + true, + R.id.container, + ) + } catch (e: JsonSyntaxException) { + Toast.makeText( + activity, + getString(R.string.invalid_qr), + Toast.LENGTH_SHORT, + ).show() + } + } + + private fun checkPermissionRationale(permission: String): Boolean { + return ActivityCompat.shouldShowRequestPermissionRationale(requireActivity(), permission) + } + + + override fun onResume() { + super.onResume() + (activity as? BaseActivity)?.hideToolbar() + } + + companion object { + fun newInstance(): QrCodeImportComposeFragment { + return QrCodeImportComposeFragment() + } + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportContent.kt b/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportContent.kt new file mode 100644 index 000000000..fd2d69311 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportContent.kt @@ -0,0 +1,161 @@ +package org.mifos.mobile.ui.qr_code_import + +import android.content.Intent +import android.content.pm.PackageManager +import android.graphics.Bitmap +import android.net.Uri +import android.os.Build +import android.provider.Settings +import android.widget.Toast +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.RequiresApi +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.compose.ui.res.stringResource +import androidx.core.content.ContextCompat +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.MifosAlertDialog + +@Composable +fun PermissionBox( + requiredPermissions: List, + title: Int, + description: Int, + confirmButtonText: Int, + dismissButtonText: Int, + rationaleChecker: (permission: String) -> Boolean, + onGranted: @Composable (() -> Unit)? = null, + onDenied: @Composable (() -> Unit)? = null, +) { + val context = LocalContext.current + val lifecycleOwner = LocalLifecycleOwner.current + + var permissionGranted by remember { + mutableStateOf( + requiredPermissions.all { + ContextCompat.checkSelfPermission( + context, + it + ) == PackageManager.PERMISSION_GRANTED + } + ) + } + + var shouldShowPermissionRationale by remember { + mutableStateOf( + requiredPermissions.all { + rationaleChecker.invoke(it) + } + ) + } + + var shouldDirectUserToApplicationSettings by remember { + mutableStateOf(false) + } + + val decideCurrentPermissionStatus: (Boolean, Boolean) -> String = + { permissionGranted, shouldShowPermissionRationale -> + if (permissionGranted) "Granted" + else if (shouldShowPermissionRationale) "Rejected" + else "Denied" + } + + var currentPermissionStatus by remember { + mutableStateOf( + decideCurrentPermissionStatus( + permissionGranted, + shouldShowPermissionRationale + ) + ) + } + + val multiplePermissionLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.RequestMultiplePermissions(), + onResult = { permissionResults -> + val isGranted = + requiredPermissions.all { permissionResults[it] ?: false } + + permissionGranted = isGranted + + if (!isGranted) { + shouldShowPermissionRationale = + requiredPermissions.all { + rationaleChecker.invoke(it) + } + } + shouldDirectUserToApplicationSettings = + !shouldShowPermissionRationale && !permissionGranted + currentPermissionStatus = decideCurrentPermissionStatus( + permissionGranted, + shouldShowPermissionRationale + ) + }) + + + if (shouldShowPermissionRationale) { + MifosAlertDialog( + onDismissRequest = { shouldShowPermissionRationale = false }, + dismissText = stringResource(id = dismissButtonText), + onConfirmation = { + shouldShowPermissionRationale = false + multiplePermissionLauncher.launch(requiredPermissions.toTypedArray()) + }, + confirmationText = stringResource(id = confirmButtonText), + dialogTitle = stringResource(id = title), + dialogText = stringResource(id = description) + ) + } + + if (shouldDirectUserToApplicationSettings) { + Toast.makeText(context, R.string.please_grant_us_storage_permissions, Toast.LENGTH_LONG) + .show() + Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", context.packageName, null) + ).also { + context.startActivity(it) + } + } + + DisposableEffect(key1 = lifecycleOwner, effect = { + val observer = LifecycleEventObserver { _, event -> + if (event == Lifecycle.Event.ON_START && + !permissionGranted && + !shouldShowPermissionRationale + ) { + multiplePermissionLauncher.launch(requiredPermissions.toTypedArray()) + } + } + lifecycleOwner.lifecycle.addObserver(observer) + onDispose { + lifecycleOwner.lifecycle.removeObserver(observer) + } + }) + + if (permissionGranted) { + if (onGranted != null) { + onGranted() + } + }else{ + onDenied?.invoke() + } +} + + +@RequiresApi(Build.VERSION_CODES.O) +fun convertToMutableBitmap(bitmap: Bitmap): Bitmap { + return if (bitmap.config == Bitmap.Config.HARDWARE) { + bitmap.copy(Bitmap.Config.ARGB_8888, true) + } else { + bitmap + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt b/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportFragment.kt similarity index 82% rename from app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt rename to app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportFragment.kt index 696f8e683..1ab704aa2 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/QrCodeImportFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportFragment.kt @@ -1,4 +1,4 @@ -package org.mifos.mobile.ui.fragments +package org.mifos.mobile.ui.qr_code_import import android.graphics.Bitmap import android.graphics.BitmapFactory @@ -17,26 +17,24 @@ import com.google.gson.Gson import com.google.gson.JsonSyntaxException import com.google.zxing.Result import com.isseiaoki.simplecropview.CropImageView -import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentQrCodeImportBinding -import org.mifos.mobile.models.beneficiary.Beneficiary import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.BeneficiaryState +import org.mifos.mobile.ui.beneficiary_application.BeneficiaryApplicationComposeFragment +import org.mifos.mobile.core.model.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.core.common.Constants +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.Toaster -import org.mifos.mobile.viewModels.QrCodeImportViewModel import java.io.FileNotFoundException import java.io.InputStream /** * Created by manishkumar on 19/05/18. */ -@AndroidEntryPoint + class QrCodeImportFragment : BaseFragment() { private var _binding: FragmentQrCodeImportBinding? = null @@ -85,21 +83,21 @@ class QrCodeImportFragment : BaseFragment() { viewLifecycleOwner.lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.qrCodeUiState.collect { + viewModel.qrCodeImportUiState.collect { when (it) { - is QrCodeUiState.Loading -> showProgress() + is QrCodeImportUiState.Loading -> showProgress() - is QrCodeUiState.ShowError -> { + is QrCodeImportUiState.ShowError -> { hideProgress() showErrorReadingQr(getString(it.message)) } - is QrCodeUiState.HandleDecodedResult -> { + is QrCodeImportUiState.HandleDecodedResult -> { hideProgress() handleDecodedResult(it.result) } - QrCodeUiState.Initial -> {} + QrCodeImportUiState.Initial -> {} } } } @@ -113,21 +111,21 @@ class QrCodeImportFragment : BaseFragment() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) // save data - outState.putParcelable(Constants.FRAME_RECT, binding.ivCropQrCode.actualCropRect) - outState.putParcelable(Constants.SOURCE_URI, binding.ivCropQrCode.sourceUri) + outState.putParcelable(org.mifos.mobile.core.common.Constants.FRAME_RECT, binding.ivCropQrCode.actualCropRect) + outState.putParcelable(org.mifos.mobile.core.common.Constants.SOURCE_URI, binding.ivCropQrCode.sourceUri) } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) if (savedInstanceState != null) { // restore data - mFrameRect = savedInstanceState.getCheckedParcelable(RectF::class.java, Constants.FRAME_RECT) - qrUri = savedInstanceState.getCheckedParcelable(Uri::class.java, Constants.SOURCE_URI)!! + mFrameRect = savedInstanceState.getCheckedParcelable(RectF::class.java, org.mifos.mobile.core.common.Constants.FRAME_RECT) + qrUri = savedInstanceState.getCheckedParcelable(Uri::class.java, org.mifos.mobile.core.common.Constants.SOURCE_URI)!! } } fun proceed() { - viewModel.getDecodedResult(qrUri, binding.ivCropQrCode) +// viewModel.getDecodedResult(qrUri, binding.ivCropQrCode) } /** @@ -152,7 +150,7 @@ class QrCodeImportFragment : BaseFragment() { val beneficiary = gson.fromJson(result?.text, Beneficiary::class.java) activity?.supportFragmentManager?.popBackStack() (activity as BaseActivity?)?.replaceFragment( - BeneficiaryApplicationFragment.newInstance(BeneficiaryState.CREATE_QR, beneficiary), + BeneficiaryApplicationComposeFragment.newInstance(BeneficiaryState.CREATE_QR, beneficiary), true, R.id.container, ) diff --git a/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportScreen.kt b/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportScreen.kt new file mode 100644 index 000000000..ea34c0de2 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportScreen.kt @@ -0,0 +1,288 @@ +package org.mifos.mobile.ui.qr_code_import + +import android.Manifest +import android.graphics.Bitmap +import android.graphics.ImageDecoder +import android.net.Uri +import android.os.Build +import android.provider.MediaStore +import android.widget.Toast +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.RequiresApi +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Button +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.canhub.cropper.CropImageContract +import com.canhub.cropper.CropImageContractOptions +import com.canhub.cropper.CropImageOptions +import com.google.zxing.Result +import org.mifos.mobile.R +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.ui.component.MFScaffold +import org.mifos.mobile.core.ui.component.MifosErrorComponent +import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +@Composable +fun QrCodeImportScreen( + viewModel: QrCodeImportViewModel = hiltViewModel(), + navigateBack: () -> Unit, + handleDecodedResult: (result: Result) -> Unit, + showRationaleChecker: (permission: String) -> Boolean +) { + val uiState by viewModel.qrCodeImportUiState.collectAsStateWithLifecycle() + + QrCodeImportScreen( + uiState = uiState, + navigateBack = navigateBack, + proceedClicked = { bitmap: Bitmap -> + viewModel.getDecodedResult(bitmap = bitmap) + }, + handleDecodedResult = handleDecodedResult, + showRationaleChecker = showRationaleChecker + ) +} + + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +@Composable +fun QrCodeImportScreen( + uiState: QrCodeImportUiState, + navigateBack: () -> Unit, + proceedClicked: (bitmap: Bitmap) -> Unit, + handleDecodedResult: (result: Result) -> Unit, + showRationaleChecker: (permission: String) -> Boolean +) { + val context = LocalContext.current + + MFScaffold( + topBarTitleResId = R.string.import_qr, + navigateBack = { navigateBack.invoke() } + ) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(it) + ) { + Box(modifier = Modifier.fillMaxSize()) { + + QrCodeImportContent( + proceedClicked = proceedClicked, + showRationaleChecker = showRationaleChecker + ) + + when (uiState) { + is QrCodeImportUiState.HandleDecodedResult -> { + handleDecodedResult.invoke(uiState.result) + } + + QrCodeImportUiState.Initial -> Unit + + QrCodeImportUiState.Loading -> { + MifosProgressIndicatorOverlay() + } + + is QrCodeImportUiState.ShowError -> { + Toast.makeText(context, uiState.message, Toast.LENGTH_SHORT).show() + } + } + } + + } + } +} + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +@Composable +fun QrCodeImportContent( + showRationaleChecker: (permission: String) -> Boolean, + proceedClicked: (bitmap: Bitmap) -> Unit +) { + + /** + * [Manifest.permission.READ_EXTERNAL_STORAGE] & [Manifest.permission.WRITE_EXTERNAL_STORAGE] + * is deprecated and is not granted when targeting Android 13+ , so if it's android 13+ + * we have to request for [Manifest.permission.READ_MEDIA_IMAGES] + */ + val permission = if (Build.VERSION.SDK_INT >= 33) { + listOf(Manifest.permission.READ_MEDIA_IMAGES) + } else { + listOf( + Manifest.permission.READ_EXTERNAL_STORAGE, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) + } + PermissionBox( + requiredPermissions = permission, + title = R.string.permission_denied_storage, + confirmButtonText = R.string.grant_permission, + dismissButtonText = R.string.deny, + rationaleChecker = showRationaleChecker, + description = R.string.dialog_message_write_storage_permission_never_ask_again, + onGranted = { + QrCodeImportContent( + proceedClicked = proceedClicked + ) + }, + onDenied = { + MifosErrorComponent( + message = stringResource(id = R.string.permission_denied_storage) + ) + } + ) +} + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +@Composable +fun QrCodeImportContent( + proceedClicked: (bitmap: Bitmap) -> Unit +) { + var bitmap: Bitmap? by rememberSaveable { + mutableStateOf(null) + } + val context = LocalContext.current + var showErrorScreen by rememberSaveable { + mutableStateOf(false) + } + + /** + * responsible for image picking, + * & cropping image + */ + QrCodeImportFunctions( + setImageBitmap = { bitmap = it }, + showErrorScreen = { showErrorScreen = it }, + ) + + Column( + modifier = Modifier + .fillMaxSize() + ) { + if (showErrorScreen) { + MifosErrorComponent( + isNetworkConnected = Network.isConnected(context), + isRetryEnabled = false, + isEmptyData = true, + message = stringResource( + id = R.string.no_image_selected_or_something_went_wrong + ) + ) + } else if (bitmap != null) { + Text( + modifier = Modifier + .fillMaxWidth(), + text = stringResource(id = R.string.seleted_qr_image), + textAlign = TextAlign.Center + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Image( + modifier = Modifier + .weight(1f) + .fillMaxWidth() + .padding(16.dp), + bitmap = bitmap!!.asImageBitmap(), + contentDescription = null + ) + + Spacer(modifier = Modifier.height(16.dp)) + + Button( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp), + onClick = { proceedClicked.invoke(bitmap!!) }) + { + Text(text = stringResource(id = R.string.proceed)) + } + } + } +} + + +@RequiresApi(Build.VERSION_CODES.TIRAMISU) +@Composable +fun QrCodeImportFunctions( + setImageBitmap: (Bitmap) -> Unit, + showErrorScreen: (error: Boolean) -> Unit +) { + var imageUri: Uri? by rememberSaveable { + mutableStateOf(null) + } + var bitmap: Bitmap? by rememberSaveable { mutableStateOf(null) } + val context = LocalContext.current + var hasImagePicked by rememberSaveable { + mutableStateOf(false) + } + + /** + * responsible for image cropping + * [https://github.com/CanHub/Android-Image-Cropper] + */ + val imageCropLauncher = rememberLauncherForActivityResult(CropImageContract()) { result -> + if (result.isSuccessful) { + hasImagePicked = true + val uri = result.uriContent + bitmap = if (Build.VERSION.SDK_INT < 28) { + MediaStore.Images.Media.getBitmap(context.contentResolver, uri) + } else { + val source = uri?.let { ImageDecoder.createSource(context.contentResolver, it) } + val hardwareBitmap = source?.let { ImageDecoder.decodeBitmap(it) } + hardwareBitmap?.let { convertToMutableBitmap(it) } + } + } else { + /** + * handles if the user presses back button on top-left (that comes with the cropLauncher) + * instead of cropping the image + */ + showErrorScreen.invoke(true) + Toast.makeText(context, R.string.something_went_wrong, Toast.LENGTH_SHORT).show() + } + bitmap?.let { setImageBitmap.invoke(it) } + } + + /** + * uri is null when the user presses back button instead of + * selecting images when on gallery. so we have to handle it as well + */ + val imagePickerLauncher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.GetContent() + ) { uri: Uri? -> + imageUri = uri + if (imageUri == null) { + Toast.makeText(context, R.string.something_went_wrong, Toast.LENGTH_SHORT).show() + showErrorScreen.invoke(true) + } else { + imageCropLauncher.launch(CropImageContractOptions(imageUri, CropImageOptions())) + } + } + + LaunchedEffect(Unit) { + if (!hasImagePicked) { + imagePickerLauncher.launch("image/*") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportViewModel.kt new file mode 100644 index 000000000..4c6ab3b7e --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/qr_code_import/QrCodeImportViewModel.kt @@ -0,0 +1,65 @@ +package org.mifos.mobile.ui.qr_code_import + +import android.graphics.Bitmap +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.google.zxing.BinaryBitmap +import com.google.zxing.Result +import com.google.zxing.NotFoundException +import com.google.zxing.RGBLuminanceSource +import com.google.zxing.common.HybridBinarizer +import com.google.zxing.multi.qrcode.QRCodeMultiReader +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext +import org.mifos.mobile.R +import javax.inject.Inject + +@HiltViewModel +class QrCodeImportViewModel @Inject constructor() : ViewModel() { + + private val _qrCodeImportUiState = + MutableStateFlow(QrCodeImportUiState.Initial) + val qrCodeImportUiState: StateFlow = _qrCodeImportUiState + + fun getDecodedResult(bitmap: Bitmap) { + _qrCodeImportUiState.value = QrCodeImportUiState.Loading + + viewModelScope.launch { + val result = withContext(Dispatchers.IO) { + decodeQrCode(bitmap) + } + + if (result != null) { + _qrCodeImportUiState.value = QrCodeImportUiState.HandleDecodedResult(result) + } else { + _qrCodeImportUiState.value = + QrCodeImportUiState.ShowError(R.string.error_reading_qr) + } + } + } + + private fun decodeQrCode(bitmap: Bitmap): Result? { + val intArray = IntArray(bitmap.width * bitmap.height) + bitmap.getPixels(intArray, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height) + val source = RGBLuminanceSource(bitmap.width, bitmap.height, intArray) + val binaryBitmap = BinaryBitmap(HybridBinarizer(source)) + + return try { + val reader = QRCodeMultiReader() + reader.decode(binaryBitmap) + } catch (e: NotFoundException) { + null + } + } +} + +sealed class QrCodeImportUiState { + object Initial : QrCodeImportUiState() + object Loading : QrCodeImportUiState() + data class ShowError(val message: Int) : QrCodeImportUiState() + data class HandleDecodedResult(val result: Result) : QrCodeImportUiState() +} diff --git a/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionScreen.kt b/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionScreen.kt index b93fac303..2dbd41986 100644 --- a/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionScreen.kt @@ -1,6 +1,7 @@ package org.mifos.mobile.ui.recent_transactions import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -11,14 +12,10 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.pulltorefresh.PullToRefreshContainer import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState @@ -36,7 +33,6 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp -import androidx.core.content.ContextCompat.getString import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import org.mifos.mobile.MifosSelfServiceApp @@ -47,12 +43,11 @@ import org.mifos.mobile.core.ui.component.MifosErrorComponent import org.mifos.mobile.core.ui.component.MifosProgressIndicator import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.models.Transaction -import org.mifos.mobile.models.client.Type -import org.mifos.mobile.utils.CurrencyUtil -import org.mifos.mobile.utils.DateHelper -import org.mifos.mobile.utils.Network -import org.mifos.mobile.utils.Utils +import org.mifos.mobile.core.common.utils.CurrencyUtil +import org.mifos.mobile.core.common.utils.DateHelper +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.model.entity.Transaction +import org.mifos.mobile.core.common.utils.Utils @Composable fun RecentTransactionScreen( @@ -96,55 +91,69 @@ fun RecentTransactionScreen( topBarTitleResId = R.string.recent_transactions, navigateBack = navigateBack, scaffoldContent = { paddingValues -> - Box(modifier = Modifier.padding(paddingValues = paddingValues)) { - when (uiState) { - is RecentTransactionUiState.Error -> { - MifosErrorComponent( - isNetworkConnected = Network.isConnected(context), - isRetryEnabled = true, - onRetry = onRetry - ) - } - is RecentTransactionUiState.Loading -> { - MifosProgressIndicatorOverlay() - } + Box( + Modifier + .fillMaxSize() + .nestedScroll(pullRefreshState.nestedScrollConnection) + ) { + Column( + modifier = Modifier + .fillMaxSize(), + verticalArrangement = Arrangement.Center + ) { - is RecentTransactionUiState.Success -> { - if (uiState.transactions.isEmpty()) { - EmptyDataView( - icon = R.drawable.ic_error_black_24dp, - error = R.string.no_transaction, - modifier = Modifier.fillMaxSize() - ) - } else { - RecentTransactionsContent( - transactions = uiState.transactions, - isPaginating = isPaginating, - loadMore = loadMore, - canPaginate = uiState.canPaginate + when (uiState) { + is RecentTransactionUiState.Error -> { + MifosErrorComponent( + isNetworkConnected = Network.isConnected(context), + isRetryEnabled = true, + onRetry = onRetry ) } + + is RecentTransactionUiState.Loading -> { + MifosProgressIndicatorOverlay() + } + + is RecentTransactionUiState.Success -> { + if (uiState.transactions.isEmpty()) { + EmptyDataView( + icon = R.drawable.ic_error_black_24dp, + error = R.string.no_transaction, + modifier = Modifier.fillMaxSize() + ) + } else { + RecentTransactionsContent( + transactions = uiState.transactions, + isPaginating = isPaginating, + loadMore = loadMore, + canPaginate = uiState.canPaginate + ) + } + } } } - } - } - ) + if (pullRefreshState.isRefreshing) { + LaunchedEffect(key1 = true) { + onRefresh() + } + } + LaunchedEffect(key1 = isRefreshing) { + if (isRefreshing) + pullRefreshState.startRefresh() + else + pullRefreshState.endRefresh() + } - if (pullRefreshState.isRefreshing) { - LaunchedEffect(key1 = true) { - onRefresh() + PullToRefreshContainer( + state = pullRefreshState, + modifier = Modifier + .padding(top = 24.dp) + .align(Alignment.TopCenter), + ) + } } - } - LaunchedEffect(key1 = isRefreshing) { - if (isRefreshing) - pullRefreshState.startRefresh() - else - pullRefreshState.endRefresh() - } - - PullToRefreshContainer( - state = pullRefreshState, ) } @@ -173,7 +182,7 @@ fun RecentTransactionsContent( RecentTransactionListItem(transaction) } - if(isPaginating) { + if (isPaginating) { item { MifosProgressIndicator(modifier = Modifier.fillMaxWidth()) } @@ -203,10 +212,15 @@ fun RecentTransactionListItem(transaction: Transaction?) { text = stringResource( id = R.string.string_and_string, transaction?.currency?.displaySymbol ?: transaction?.currency?.code ?: "", - CurrencyUtil.formatCurrency(MifosSelfServiceApp.context, transaction?.amount ?: 0.0,) + CurrencyUtil.formatCurrency( + MifosSelfServiceApp.context, + transaction?.amount ?: 0.0, + ) ), style = MaterialTheme.typography.labelMedium, - modifier = Modifier.weight(1f).alpha(0.7f), + modifier = Modifier + .weight(1f) + .alpha(0.7f), color = MaterialTheme.colorScheme.onSurface ) Text( @@ -221,7 +235,6 @@ fun RecentTransactionListItem(transaction: Transaction?) { } } - class RecentTransactionScreenPreviewProvider : PreviewParameterProvider { override val values: Sequence get() = sequenceOf( @@ -247,5 +260,4 @@ private fun RecentTransactionScreenPreview( loadMore = {} ) } -} - +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionViewModel.kt index 7e4eb646b..ddfb72716 100644 --- a/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionViewModel.kt @@ -9,10 +9,8 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch -import org.mifos.mobile.R -import org.mifos.mobile.models.Transaction -import org.mifos.mobile.models.client.Type -import org.mifos.mobile.repositories.RecentTransactionRepository +import org.mifos.mobile.core.data.repositories.RecentTransactionRepository +import org.mifos.mobile.core.model.entity.Transaction import javax.inject.Inject @HiltViewModel diff --git a/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionsComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionsComposeFragment.kt index 531c1d1c6..1691f855b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionsComposeFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionsComposeFragment.kt @@ -4,9 +4,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.fragment.app.viewModels import dagger.hilt.android.AndroidEntryPoint -import org.mifos.mobile.R import org.mifos.mobile.core.ui.component.mifosComposeView import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment diff --git a/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionsFragment.kt index 30ac957cf..81873a2e2 100644 --- a/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/recent_transactions/RecentTransactionsFragment.kt @@ -1,32 +1,5 @@ package org.mifos.mobile.ui.recent_transactions -import android.os.Bundle -import android.os.Parcelable -import android.view.LayoutInflater -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 androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener -import com.github.therajanmaurya.sweeterror.SweetUIErrorHandler -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import org.mifos.mobile.R -import org.mifos.mobile.databinding.FragmentRecentTransactionsBinding -import org.mifos.mobile.models.Transaction -import org.mifos.mobile.ui.activities.base.BaseActivity -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 javax.inject.Inject - /* /** * @author Vishwwajeet diff --git a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationActivity.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationActivity.kt index e21552596..8892274cd 100644 --- a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationActivity.kt @@ -1,21 +1,36 @@ package org.mifos.mobile.ui.registration +import android.content.Intent import android.os.Bundle -import org.mifos.mobile.R -import org.mifos.mobile.databinding.ActivityRegistrationBinding +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.navigation.compose.rememberNavController +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.feature.registration.navigation.RegistrationNavGraph +import org.mifos.mobile.feature.registration.navigation.RegistrationScreen import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.registration.RegistrationFragment -import org.mifos.mobile.utils.MaterialDialog +import org.mifos.mobile.ui.login.LoginActivity class RegistrationActivity : BaseActivity() { - - private lateinit var binding: ActivityRegistrationBinding - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = ActivityRegistrationBinding.inflate(layoutInflater) - setContentView(binding.root) - replaceFragment(RegistrationFragment.newInstance(), false, R.id.container) + enableEdgeToEdge() + setContent { + MifosMobileTheme { + val navController = rememberNavController() + RegistrationNavGraph( + startDestination = RegistrationScreen.Registration.route, + navController = navController, + navigateBack = { this.finish() }, + startLoginActivity = { startLoginActivity() } + ) + } + } } + private fun startLoginActivity() + { + this.startActivity(Intent(this, LoginActivity::class.java)) + this.finish() + } } diff --git a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationComposeFragment.kt new file mode 100644 index 000000000..7cfc3e2be --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationComposeFragment.kt @@ -0,0 +1,47 @@ +package org.mifos.mobile.ui.registration + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.ui.fragments.base.BaseFragment + +/* +/** + * Created by dilpreet on 31/7/17. + */ +@AndroidEntryPoint +class RegistrationComposeFragment : BaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + return mifosComposeView(requireContext()) { + org.mifos.mobile.feature.registration.screens.RegistrationScreen( + onVerified = { showRegisteredSuccessfully() }, + navigateBack = { activity?.onBackPressed() }, + ) + } + } + + private fun showRegisteredSuccessfully() { + (activity as BaseActivity?)?.replaceFragment( + RegistrationVerificationComposeFragment.newInstance(), + true, + R.id.container, + ) + } + + companion object { + fun newInstance(): RegistrationComposeFragment { + return RegistrationComposeFragment() + } + } +} +*/ \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationFragment.kt index e27b2b0ed..d35ac7d9b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationFragment.kt @@ -1,26 +1,6 @@ package org.mifos.mobile.ui.registration -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.compose.ui.platform.ComposeView -import androidx.compose.ui.platform.ViewCompositionStrategy -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import org.mifos.mobile.R -import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.utils.Network -import org.mifos.mobile.utils.PasswordStrength -import org.mifos.mobile.utils.RegistrationUiState -import org.mifos.mobile.utils.Toaster - +/* /** * Created by dilpreet on 31/7/17. */ @@ -261,3 +241,4 @@ class RegistrationFragment : BaseFragment() { } } } +*/ \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationScreen.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationScreen.kt deleted file mode 100644 index 6bb97b7bc..000000000 --- a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationScreen.kt +++ /dev/null @@ -1,276 +0,0 @@ -package org.mifos.mobile.ui.registration - -import android.content.res.Configuration -import androidx.compose.foundation.border -import androidx.compose.foundation.gestures.detectTapGestures -import androidx.compose.foundation.isSystemInDarkTheme -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Visibility -import androidx.compose.material.icons.filled.VisibilityOff -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.LinearProgressIndicator -import androidx.compose.material3.RadioButton -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.pointer.pointerInput -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.KeyboardType -import androidx.compose.ui.text.input.PasswordVisualTransformation -import androidx.compose.ui.text.input.TextFieldValue -import androidx.compose.ui.text.input.VisualTransformation -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import com.owlbuddy.www.countrycodechooser.CountryCodeChooser -import com.owlbuddy.www.countrycodechooser.utils.enums.CountryCodeType -import org.mifos.mobile.R -import org.mifos.mobile.core.ui.component.MifosOutlinedTextField - -/** - * @author pratyush - * @since 28/12/2023 - */ - -@OptIn(ExperimentalComposeUiApi::class) -@Composable -fun RegistrationScreen( - register: (accountNumber: String, username: String, firstName: String, lastName: String, phoneNumber: String, email: String, password: String, authMode: String, countryCode: String) -> Unit, - progress: (String) -> Float, -) { - - val keyboardController = LocalSoftwareKeyboardController.current - - var accountNumber by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue("")) - } - var username by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue("")) - } - var firstName by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue("")) - } - var lastName by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue("")) - } - var phoneNumber by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue("")) - } - var email by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue("")) - } - var password by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue("")) - } - var onValueChangePassword by rememberSaveable { - mutableStateOf(false) - } - var confirmPassword by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue("")) - } - var countryCode by rememberSaveable { - mutableStateOf("") - } - val radioOptions = - listOf(stringResource(id = R.string.rb_email), stringResource(id = R.string.rb_mobile)) - var authenticationMode by remember { mutableStateOf(radioOptions[0]) } - - val progressIndicator = progress(password.text) - var passwordVisibility: Boolean by remember { mutableStateOf(false) } - var confirmPasswordVisibility: Boolean by remember { mutableStateOf(false) } - - Column( - modifier = Modifier - .fillMaxSize() - .padding(bottom = 12.dp) - .pointerInput(Unit) { - detectTapGestures(onTap = { - keyboardController?.hide() - }) - }) { - MifosOutlinedTextField( - value = accountNumber, - onValueChange = { accountNumber = it }, - label = R.string.account_number, - supportingText = "" - ) - MifosOutlinedTextField( - value = username, - onValueChange = { username = it }, - label = R.string.username, - supportingText = "" - ) - MifosOutlinedTextField( - value = firstName, - onValueChange = { firstName = it }, - label = R.string.first_name, - supportingText = "" - ) - MifosOutlinedTextField( - value = lastName, - onValueChange = { lastName = it }, - label = R.string.last_name, - supportingText = "" - ) - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.Center - ) { - CountryCodeChooser( - modifier = Modifier - .padding(start = 16.dp) - .border( - width = 1.dp, - shape = RoundedCornerShape(5.dp), - color = Color.Gray - ) - .padding(10.dp), - defaultCountryCode = "91", - countryCodeType = CountryCodeType.FLAG, - onCountyCodeSelected = { code, codeWithPrefix -> - countryCode = code - } - ) - MifosOutlinedTextField( - value = phoneNumber, - onValueChange = { phoneNumber = it }, - label = R.string.phone_number, - supportingText = "" - ) - } - MifosOutlinedTextField( - value = email, - onValueChange = { email = it }, - label = R.string.email, - supportingText = "" - ) - MifosOutlinedTextField( - value = password, - onValueChange = { - password = it - onValueChangePassword = true - }, - label = R.string.password, - supportingText = "", - visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(), - trailingIcon = { - val image = if (passwordVisibility) - Icons.Filled.Visibility - else Icons.Filled.VisibilityOff - IconButton(onClick = { passwordVisibility = !passwordVisibility }) { - Icon(imageVector = image, null) - } - }, - keyboardType = KeyboardType.Password - ) - - if (onValueChangePassword) { - LinearProgressIndicator( - modifier = Modifier - .fillMaxWidth() - .padding(start = 16.dp, end = 16.dp), - color = when (progressIndicator) { - 0.25f -> Color.Red - 0.5f -> Color(alpha = 255, red = 220, green = 185, blue = 0) - 0.75f -> Color.Green - else -> Color.Blue - }, - progress = progressIndicator, - trackColor = Color.White - ) - } - - MifosOutlinedTextField( - value = confirmPassword, - onValueChange = { confirmPassword = it }, - label = R.string.confirm_password, - supportingText = "", - visualTransformation = if (confirmPasswordVisibility) VisualTransformation.None else PasswordVisualTransformation(), - trailingIcon = { - val image = if (confirmPasswordVisibility) - Icons.Filled.Visibility - else Icons.Filled.VisibilityOff - IconButton(onClick = { confirmPasswordVisibility = !confirmPasswordVisibility }) { - Icon(imageVector = image, null) - } - }, - keyboardType = KeyboardType.Password - ) - - Row( - modifier = Modifier - .fillMaxWidth() - .padding(start = 16.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = stringResource(id = R.string.verification_mode), - modifier = Modifier.padding(end = 8.dp), - color = if (isSystemInDarkTheme()) Color.White else Color.Black - ) - radioOptions.forEach { authMode -> - RadioButton( - selected = (authMode == authenticationMode), - onClick = { authenticationMode = authMode } - ) - Text( - text = authMode, - color = if (isSystemInDarkTheme()) Color.White else Color.Black - ) - } - } - - Button( - onClick = { - register.invoke( - accountNumber.text, - username.text, - firstName.text, - lastName.text, - phoneNumber.text, - email.text, - password.text, - authenticationMode, - countryCode - ) - keyboardController?.hide() - }, - modifier = Modifier - .fillMaxWidth() - .padding(start = 16.dp, end = 16.dp, top = 4.dp), - contentPadding = PaddingValues(12.dp), - colors = ButtonDefaults.buttonColors( - containerColor = if (isSystemInDarkTheme()) Color( - 0xFF9bb1e3 - ) else Color(0xFF325ca8) - ) - ) { - Text(text = stringResource(id = R.string.register)) - } - } -} - -@Preview(showSystemUi = true, uiMode = Configuration.UI_MODE_NIGHT_YES) -@Composable -fun RegistrationScreenPreview() { - RegistrationScreen({ _, _, _, _, _, _, _, _, _ -> }, { 0f }) -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationComposeFragment.kt new file mode 100644 index 000000000..e141572ca --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationComposeFragment.kt @@ -0,0 +1,40 @@ +package org.mifos.mobile.ui.registration + +/* +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.ui.login.LoginActivity + +/** + * Created by dilpreet on 31/7/17. + */ +@AndroidEntryPoint +class RegistrationVerificationComposeFragment : BaseFragment() { + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + return mifosComposeView(requireContext()) { + org.mifos.mobile.feature.registration.screens.RegistrationVerificationScreen( + navigateBack = { activity?.finish() }, + onVerified = { + startActivity(Intent(activity, LoginActivity::class.java)) + activity?.finish() + } + ) + } + } + companion object { + fun newInstance(): RegistrationVerificationComposeFragment { + return RegistrationVerificationComposeFragment() + } + } +} +*/ \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationFragment.kt index cc7775e40..cd87e2c53 100644 --- a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationFragment.kt @@ -1,42 +1,89 @@ package org.mifos.mobile.ui.registration -import android.content.Intent -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.Toast -import androidx.fragment.app.viewModels -import dagger.hilt.android.AndroidEntryPoint -import org.mifos.mobile.R -import org.mifos.mobile.core.ui.component.mifosComposeView -import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.ui.login.LoginActivity - +/* /** * Created by dilpreet on 31/7/17. */ @AndroidEntryPoint class RegistrationVerificationFragment : BaseFragment() { + private var _binding: FragmentRegistrationVerificationBinding? = null + private val binding get() = _binding!! + + private val viewModel: RegistrationViewModel by viewModels() override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, ): View { - return mifosComposeView(requireContext()) { - RegistrationVerificationScreen( - navigateBack = { activity?.finish() } , - onVerified = { - startActivity(Intent(activity, LoginActivity::class.java)) - activity?.finish() + _binding = FragmentRegistrationVerificationBinding.inflate(inflater, container, false) + val rootView = binding.root + return rootView + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + viewModel.registrationVerificationUiState.collect { state -> + when (state) { + RegistrationUiState.Loading -> showProgress() + + RegistrationUiState.Success -> { + hideProgress() + showVerifiedSuccessfully() + } + + is RegistrationUiState.Error -> { + hideProgress() + showError(getString(state.exception)) + } + + RegistrationUiState.Initial -> {} + } } - ) + } + } + + binding.btnVerify.setOnClickListener { + verifyClicked() } } + + private fun verifyClicked() { + val authenticationToken = binding.etAuthenticationToken.text.toString() + val requestId = binding.etRequestId.text.toString() + viewModel.verifyUser(authenticationToken, requestId) + } + + private fun showVerifiedSuccessfully() { + startActivity(Intent(activity, LoginActivity::class.java)) + Toast.makeText(context, getString(R.string.verified), Toast.LENGTH_SHORT).show() + activity?.finish() + } + + fun showError(msg: String?) { + Toaster.show(binding.root, msg) + } + + fun showProgress() { + showMifosProgressDialog(getString(R.string.verifying)) + } + + fun hideProgress() { + hideMifosProgressDialog() + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } + companion object { fun newInstance(): RegistrationVerificationFragment { return RegistrationVerificationFragment() } } } +*/ \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationFragment_Old.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationFragment_Old.kt deleted file mode 100644 index e9b892abd..000000000 --- a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationVerificationFragment_Old.kt +++ /dev/null @@ -1,106 +0,0 @@ -package org.mifos.mobile.ui.registration - -import android.content.Intent -import android.os.Bundle -import android.view.LayoutInflater -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 dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch -import org.mifos.mobile.R -import org.mifos.mobile.databinding.FragmentRegistrationVerificationBinding -import org.mifos.mobile.ui.login.LoginActivity -import org.mifos.mobile.ui.fragments.base.BaseFragment -import org.mifos.mobile.utils.RegistrationUiState -import org.mifos.mobile.utils.Toaster - -/** - * Created by dilpreet on 31/7/17. - */ -@AndroidEntryPoint -class RegistrationVerificationFragment_Old : BaseFragment() { - private var _binding: FragmentRegistrationVerificationBinding? = null - private val binding get() = _binding!! - - private val viewModel: RegistrationViewModel by viewModels() - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = FragmentRegistrationVerificationBinding.inflate(inflater, container, false) - val rootView = binding.root - return rootView - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - viewLifecycleOwner.lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.registrationVerificationUiState.collect { state -> - when (state) { - RegistrationUiState.Loading -> showProgress() - - RegistrationUiState.Success -> { - hideProgress() - showVerifiedSuccessfully() - } - - is RegistrationUiState.Error -> { - hideProgress() - showError(getString(state.exception)) - } - - RegistrationUiState.Initial -> {} - } - } - } - } - - binding.btnVerify.setOnClickListener { - verifyClicked() - } - } - - private fun verifyClicked() { - val authenticationToken = binding.etAuthenticationToken.text.toString() - val requestId = binding.etRequestId.text.toString() - viewModel.verifyUser(authenticationToken, requestId) - } - - private fun showVerifiedSuccessfully() { - startActivity(Intent(activity, LoginActivity::class.java)) - Toast.makeText(context, getString(R.string.verified), Toast.LENGTH_SHORT).show() - activity?.finish() - } - - fun showError(msg: String?) { - Toaster.show(binding.root, msg) - } - - fun showProgress() { - showMifosProgressDialog(getString(R.string.verifying)) - } - - fun hideProgress() { - hideMifosProgressDialog() - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } - - companion object { - fun newInstance(): RegistrationVerificationFragment_Old { - return RegistrationVerificationFragment_Old() - } - } -} diff --git a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationViewModel.kt deleted file mode 100644 index 7e55e7c2d..000000000 --- a/app/src/main/java/org/mifos/mobile/ui/registration/RegistrationViewModel.kt +++ /dev/null @@ -1,94 +0,0 @@ -package org.mifos.mobile.ui.registration - -import androidx.core.util.PatternsCompat -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.R -import org.mifos.mobile.repositories.UserAuthRepository -import org.mifos.mobile.utils.RegistrationUiState -import javax.inject.Inject - -@HiltViewModel -class RegistrationViewModel @Inject constructor(private val userAuthRepositoryImp: UserAuthRepository) : - ViewModel() { - - private val _registrationUiState = - MutableStateFlow(RegistrationUiState.Initial) - val registrationUiState: StateFlow get() = _registrationUiState - - private val _registrationVerificationUiState = - MutableStateFlow(RegistrationUiState.Initial) - val registrationVerificationUiState: StateFlow get() = _registrationVerificationUiState - - fun isInputFieldBlank(fieldText: String): Boolean { - return fieldText.trim().isEmpty() - } - - fun isPhoneNumberNotValid(fieldText: String): Boolean{ - return fieldText.trim().toIntOrNull() == null - } - - fun isInputLengthInadequate(fieldText: String): Boolean { - return fieldText.trim().length < 6 - } - - fun inputHasSpaces(fieldText: String): Boolean { - return fieldText.trim().contains(" ") - } - - fun hasLeadingTrailingSpaces(fieldText: String): Boolean { - return fieldText.trim().length < fieldText.length - } - - fun isEmailInvalid(emailText: String): Boolean { - return !PatternsCompat.EMAIL_ADDRESS.matcher(emailText.trim()).matches() - } - - fun registerUser( - accountNumber: String, - authenticationMode: String, - email: String, - firstName: String, - lastName: String, - mobileNumber: String, - password: String, - username: String - ) { - viewModelScope.launch { - _registrationUiState.value = RegistrationUiState.Loading - userAuthRepositoryImp.registerUser( - accountNumber, - authenticationMode, - email, - firstName, - lastName, - mobileNumber, - password, - username - ).catch { - _registrationUiState.value = - RegistrationUiState.Error(R.string.could_not_register_user_error) - }.collect { - _registrationUiState.value = RegistrationUiState.Success - } - } - } - - fun verifyUser(authenticationToken: String?, requestId: String?) { - viewModelScope.launch { - _registrationVerificationUiState.value = RegistrationUiState.Loading - userAuthRepositoryImp.verifyUser(authenticationToken, requestId).catch { - _registrationVerificationUiState.value = - RegistrationUiState.Error(R.string.could_not_register_user_error) - }.collect { - _registrationVerificationUiState.value = - RegistrationUiState.Success - } - } - } -} \ No newline at end of file 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 index 5a3a43203..d7c84a6e7 100644 --- 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 @@ -12,24 +12,23 @@ 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.client_charge.ClientChargeComposeFragment -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.QrCodeDisplayFragment -import org.mifos.mobile.ui.fragments.SavingAccountsTransactionFragment +import org.mifos.mobile.ui.savings_account_transaction.SavingAccountsTransactionComposeFragment import org.mifos.mobile.ui.savings_account_application.SavingsAccountApplicationFragment import org.mifos.mobile.ui.savings_account_withdraw.SavingsAccountWithdrawFragment import org.mifos.mobile.ui.savings_make_transfer.SavingsMakeTransferFragment import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.ui.qr_code_display.QrCodeDisplayComposeFragment import org.mifos.mobile.ui.savings_make_transfer.SavingsMakeTransferComposeFragment -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.Network +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.model.enums.AccountType +import org.mifos.mobile.core.model.enums.ChargeType +import org.mifos.mobile.core.model.enums.SavingsAccountState import org.mifos.mobile.utils.QrCodeGenerator import javax.inject.Inject @@ -47,7 +46,7 @@ class SavingAccountsDetailFragment : BaseFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (arguments != null) { - viewModel.setSavingsId(arguments?.getLong(Constants.SAVINGS_ID)) + viewModel.setSavingsId(arguments?.getLong(org.mifos.mobile.core.common.Constants.SAVINGS_ID)) } } @@ -102,7 +101,7 @@ class SavingAccountsDetailFragment : BaseFragment() { (activity as BaseActivity?)?.replaceFragment( SavingsMakeTransferComposeFragment.newInstance( viewModel.savingsId, - Constants.TRANSFER_PAY_TO, + org.mifos.mobile.core.common.Constants.TRANSFER_PAY_TO, ), true, R.id.container, @@ -125,7 +124,7 @@ class SavingAccountsDetailFragment : BaseFragment() { (activity as BaseActivity?)?.replaceFragment( SavingsMakeTransferComposeFragment.newInstance( viewModel.savingsId, - Constants.TRANSFER_PAY_FROM, + org.mifos.mobile.core.common.Constants.TRANSFER_PAY_FROM, ), true, R.id.container, @@ -153,7 +152,7 @@ class SavingAccountsDetailFragment : BaseFragment() { private fun transactionsClicked() { (activity as BaseActivity?)?.replaceFragment( - SavingAccountsTransactionFragment.newInstance(viewModel.savingsId), + SavingAccountsTransactionComposeFragment.newInstance(viewModel.savingsId), true, R.id.container, ) @@ -174,7 +173,7 @@ class SavingAccountsDetailFragment : BaseFragment() { AccountType.SAVINGS, ) (activity as BaseActivity?)?.replaceFragment( - QrCodeDisplayFragment.newInstance( + QrCodeDisplayComposeFragment.newInstance( accountDetailsInJson, ), true, @@ -206,7 +205,7 @@ class SavingAccountsDetailFragment : BaseFragment() { fun newInstance(savingsId: Long): SavingAccountsDetailFragment { val fragment = SavingAccountsDetailFragment() val args = Bundle() - args.putLong(Constants.SAVINGS_ID, savingsId) + args.putLong(org.mifos.mobile.core.common.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 index 5e208e6f6..5a127ac1d 100644 --- 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 @@ -13,10 +13,9 @@ 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 org.mifos.mobile.core.data.repositories.SavingsAccountRepository +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.model.entity.accounts.savings.Status import javax.inject.Inject @HiltViewModel @@ -42,7 +41,7 @@ class SavingAccountsDetailViewModel @Inject constructor(private val savingsAccou viewModelScope.launch { _savingAccountsDetailUiState.value = SavingsAccountDetailUiState.Loading savingsAccountRepositoryImp.getSavingsWithAssociations( - accountId, Constants.TRANSACTIONS, + accountId, org.mifos.mobile.core.common.Constants.TRANSACTIONS, ).catch { _savingAccountsDetailUiState.value = SavingsAccountDetailUiState.Error }.collect { 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 index 8037bbed0..707dba221 100644 --- 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 @@ -1,7 +1,6 @@ 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 @@ -29,13 +28,13 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.model.entity.accounts.savings.Status import org.mifos.mobile.core.ui.component.MifosLinkText -import org.mifos.mobile.core.ui.component.MifosRoundIcon import org.mifos.mobile.core.ui.component.MifosTextTitleDescDoubleLine -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.core.ui.component.MonitorListItemWithIcon +import org.mifos.mobile.core.common.utils.CurrencyUtil +import org.mifos.mobile.core.common.utils.DateHelper import org.mifos.mobile.utils.SymbolsUtils @Composable @@ -309,44 +308,6 @@ fun SavingsMonitorComponent( } } -@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 StatusField( title: String, 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 index 9d40a5fa2..0ab5c945f 100644 --- 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 @@ -13,8 +13,8 @@ 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 +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations @Composable fun SavingsAccountDetailScreen( diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationContent.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationContent.kt index e02843c62..cddd90f43 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationContent.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationContent.kt @@ -38,9 +38,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.templates.savings.SavingsAccountTemplate import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.models.templates.savings.SavingsAccountTemplate -import org.mifos.mobile.utils.getTodayFormatted +import org.mifos.mobile.core.common.utils.getTodayFormatted @Composable fun SavingsAccountApplicationContent( diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationFragment.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationFragment.kt index d644fbcdd..f70414837 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationFragment.kt @@ -9,13 +9,13 @@ import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.fragment.app.viewModels import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.SavingsAccountState +import org.mifos.mobile.core.model.enums.SavingsAccountState 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.ParcelableAndSerializableUtils.getCheckedSerializable +import org.mifos.mobile.core.common.Constants +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedSerializable /* * Created by saksham on 30/June/2018 @@ -30,7 +30,8 @@ class SavingsAccountApplicationFragment : BaseFragment() { (activity as? BaseActivity)?.hideToolbar() if (arguments != null) { viewModel.setSavingsAccountState(arguments?.getCheckedSerializable(SavingsAccountState::class.java, Constants.SAVINGS_ACCOUNT_STATE) as SavingsAccountState) - viewModel.setSavingsWithAssociations(arguments?.getCheckedParcelable(SavingsWithAssociations::class.java, Constants.SAVINGS_ACCOUNTS)) + viewModel.setSavingsWithAssociations(arguments?.getCheckedParcelable( + SavingsWithAssociations::class.java, Constants.SAVINGS_ACCOUNTS)) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationScreen.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationScreen.kt index 2a0301a39..88d4f885b 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationScreen.kt @@ -19,9 +19,9 @@ import org.mifos.mobile.core.ui.component.MifosProgressIndicator import org.mifos.mobile.core.ui.component.MifosTopBar 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.ui.enums.SavingsAccountState -import org.mifos.mobile.utils.Network +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.model.enums.SavingsAccountState @Composable diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationViewModel.kt index 1dc27a755..16bd2c2e2 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_application/SavingsAccountApplicationViewModel.kt @@ -8,15 +8,15 @@ import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch import org.mifos.mobile.R -import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.models.accounts.savings.SavingsAccountApplicationPayload -import org.mifos.mobile.models.accounts.savings.SavingsAccountUpdatePayload -import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations -import org.mifos.mobile.models.templates.savings.SavingsAccountTemplate -import org.mifos.mobile.repositories.SavingsAccountRepository -import org.mifos.mobile.ui.enums.SavingsAccountState -import org.mifos.mobile.utils.DateHelper -import org.mifos.mobile.utils.getTodayFormatted +import org.mifos.mobile.core.data.repositories.SavingsAccountRepository +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountApplicationPayload +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountUpdatePayload +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.model.entity.templates.savings.SavingsAccountTemplate +import org.mifos.mobile.core.model.enums.SavingsAccountState +import org.mifos.mobile.core.common.utils.DateHelper +import org.mifos.mobile.core.common.utils.getTodayFormatted import javax.inject.Inject @HiltViewModel @@ -76,7 +76,7 @@ class SavingsAccountApplicationViewModel @Inject constructor( } } - fun setSavingsAccountState(savingsAccountState: SavingsAccountState) { + fun setSavingsAccountState(savingsAccountState: org.mifos.mobile.core.model.enums.SavingsAccountState) { _savingsAccountState = savingsAccountState } @@ -89,7 +89,7 @@ class SavingsAccountApplicationViewModel @Inject constructor( } fun onSubmit(productId: Int, clientId: Int, showToast: (Int) -> Unit) { - if (savingsAccountState == SavingsAccountState.CREATE) { + if (savingsAccountState == org.mifos.mobile.core.model.enums.SavingsAccountState.CREATE) { submitSavingsAccount(productId = productId, clientId = clientId, showToast = showToast) } else { updateSavingAccount(productId = productId, clientId = clientId) diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountTransactionContent.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountTransactionContent.kt new file mode 100644 index 000000000..a5316f33e --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountTransactionContent.kt @@ -0,0 +1,154 @@ +package org.mifos.mobile.ui.savings_account_transaction + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.material3.HorizontalDivider +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.draw.alpha +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.accounts.savings.Transactions +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.core.common.utils.CurrencyUtil +import org.mifos.mobile.core.common.utils.DateHelper + +@Composable +fun SavingsAccountTransactionContent( + transactionList: List, +) { + Column( + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.SpaceBetween + ) { + LazyColumn { + items(items = transactionList) { + SavingsAccountTransactionListItem(it) + HorizontalDivider( + thickness = 1.dp, + color = Color.Gray, + modifier = Modifier.padding(vertical = 4.dp) + ) + } + } + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 8.dp, horizontal = 10.dp), + horizontalArrangement = Arrangement.spacedBy(4.dp), + verticalAlignment = Alignment.Bottom + ) { + Text( + text = stringResource(id = R.string.need_help), + color = MaterialTheme.colorScheme.onSurface + ) + Spacer(modifier = Modifier.width(2.dp)) + Text( + text = stringResource(id = R.string.help_line_number), + color = MaterialTheme.colorScheme.primary + ) + } + } +} + + +@Composable +fun SavingsAccountTransactionListItem(transaction: Transactions) { + val context = LocalContext.current + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 6.dp) + ) { + Image( + painter = painterResource( + id = getTransactionTriangleResId(transaction.transactionType) + ), + contentDescription = stringResource(id = R.string.savings_account_transaction), + modifier = Modifier + .size(56.dp) + .padding(4.dp) + ) + Column( + modifier = Modifier.padding(4.dp) + ) { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Text( + text = DateHelper.getDateAsString(transaction.date), + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = stringResource( + id = R.string.string_and_string, + transaction.currency?.displaySymbol ?: transaction.currency?.code ?: "", + CurrencyUtil.formatCurrency(context, transaction.amount,) + ), + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.onSurface + ) + } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = transaction.transactionType?.value ?: "", + style = MaterialTheme.typography.labelMedium, + modifier = Modifier.alpha(0.7f), + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = stringResource( + id = R.string.string_and_string, + transaction.currency?.displaySymbol ?: transaction.currency?.code ?: "", + CurrencyUtil.formatCurrency(context, transaction.runningBalance) + ), + style = MaterialTheme.typography.labelMedium, + modifier = Modifier.alpha(0.7f), + color = MaterialTheme.colorScheme.onSurface + ) + } + Row( + modifier = Modifier.fillMaxWidth() + ) { + Text( + text = transaction.paymentDetailData?.paymentType?.name.toString(), + style = MaterialTheme.typography.labelMedium, + modifier = Modifier.alpha(0.7f), + color = MaterialTheme.colorScheme.onSurface + ) + } + } + } +} + +@Preview +@Composable +fun SavingsAccountTransactionContentPreview() { + MifosMobileTheme { + SavingsAccountTransactionContent(transactionList = listOf()) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionFilterDialog.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionFilterDialog.kt new file mode 100644 index 000000000..685f49cff --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionFilterDialog.kt @@ -0,0 +1,280 @@ +package org.mifos.mobile.ui.savings_account_transaction + + +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.scrollable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.CheckboxDefaults +import androidx.compose.material3.DatePicker +import androidx.compose.material3.DatePickerDialog +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.material3.rememberDatePickerState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.MifosCheckBox +import org.mifos.mobile.core.ui.component.MifosIconTextButton +import org.mifos.mobile.core.ui.component.MifosIcons +import org.mifos.mobile.core.ui.component.MifosRadioButton +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.core.common.utils.DateHelper +import org.mifos.mobile.core.common.utils.DateHelper.getDateAsStringFromLong +import java.time.Instant + +@Composable +fun SavingsTransactionFilterDialog( + onDismiss: () -> Unit, + savingsTransactionFilterDataModel: SavingsTransactionFilterDataModel, + filter: (SavingsTransactionFilterDataModel) -> Unit, +) { + + var radioFilter by rememberSaveable { mutableStateOf(savingsTransactionFilterDataModel.radioFilter) } + val checkBoxFilters by rememberSaveable { mutableStateOf(savingsTransactionFilterDataModel.checkBoxFilters) } + var startDate by rememberSaveable { mutableStateOf(savingsTransactionFilterDataModel.startDate) } + var endDate by rememberSaveable { mutableStateOf(savingsTransactionFilterDataModel.endDate) } + + var isDepositChecked by rememberSaveable { mutableStateOf(false) } + var isDividendPayoutChecked by rememberSaveable { mutableStateOf(false) } + var isWithdrawalChecked by rememberSaveable { mutableStateOf(false) } + var isInterestPostingChecked by rememberSaveable { mutableStateOf(false) } + + LaunchedEffect(key1 = checkBoxFilters) { + checkBoxFilters.forEach { filter -> + when(filter) { + SavingsTransactionCheckBoxFilter.DEPOSIT -> isDepositChecked = true + SavingsTransactionCheckBoxFilter.DIVIDEND_PAYOUT -> isDividendPayoutChecked = true + SavingsTransactionCheckBoxFilter.WITHDRAWAL -> isWithdrawalChecked = true + SavingsTransactionCheckBoxFilter.INTEREST_POSTING -> isInterestPostingChecked = true + } + } + } + + Dialog( + onDismissRequest = { onDismiss.invoke() }, + ) { + Card(shape = RoundedCornerShape(20.dp)) { + Column( + modifier = Modifier.padding(vertical = 20.dp, horizontal = 10.dp) + ) { + Text(text = stringResource(id = R.string.select_you_want)) + + Spacer(modifier = Modifier.height(20.dp)) + + SavingsTransactionFilterDialogContent( + selectedStartDate = startDate, + selectedEndDate = endDate, + radioFilter = radioFilter, + selectRadioFilter = { radioFilter = it }, + setStartDate = { startDate = it }, + isDepositChecked = isDepositChecked, + isWithdrawalChecked = isWithdrawalChecked, + isInterestPostingChecked = isInterestPostingChecked, + isDividendPayoutChecked = isDividendPayoutChecked, + setEndDate = { endDate = it }, + toggleCheckBox = { filter, isEnabled -> + when(filter) { + SavingsTransactionCheckBoxFilter.DEPOSIT -> isDepositChecked = isEnabled + SavingsTransactionCheckBoxFilter.DIVIDEND_PAYOUT -> isDividendPayoutChecked = isEnabled + SavingsTransactionCheckBoxFilter.WITHDRAWAL -> isWithdrawalChecked = isEnabled + SavingsTransactionCheckBoxFilter.INTEREST_POSTING -> isInterestPostingChecked = isEnabled + } + if(isEnabled) checkBoxFilters.add(filter) + else checkBoxFilters.remove(filter) + } + ) + + Spacer(modifier = Modifier.height(20.dp)) + + Row { + TextButton( + onClick = { + radioFilter = null + isDepositChecked = false + isWithdrawalChecked = false + isInterestPostingChecked = false + isDividendPayoutChecked = false + checkBoxFilters.clear() + } + ) { + Text(text = stringResource(id = R.string.clear_filters)) + } + + Spacer(modifier = Modifier.weight(1f)) + + TextButton( + onClick = { onDismiss() } + ) { + Text(text = stringResource(id = R.string.cancel)) + } + + TextButton( + onClick = { + onDismiss() + filter( + SavingsTransactionFilterDataModel( + startDate = startDate, + endDate = endDate, + radioFilter = radioFilter, + checkBoxFilters = checkBoxFilters + ) + ) + } + ) { + Text(text = stringResource(id = R.string.filter)) + } + } + } + } + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun SavingsTransactionFilterDialogContent( + selectedStartDate: Long, + selectedEndDate: Long, + radioFilter: SavingsTransactionRadioFilter?, + selectRadioFilter: (SavingsTransactionRadioFilter) -> Unit, + isDepositChecked: Boolean, + isDividendPayoutChecked: Boolean, + isWithdrawalChecked: Boolean, + isInterestPostingChecked: Boolean, + toggleCheckBox: (SavingsTransactionCheckBoxFilter, Boolean) -> Unit, + setStartDate: (Long) -> Unit, + setEndDate: (Long) -> Unit +) { + val scrollState = rememberScrollState() + var showStartDatePickerDialog by rememberSaveable { mutableStateOf(false) } + var showEndDatePickerDialog by rememberSaveable { mutableStateOf(false) } + val startDatePickerState = rememberDatePickerState(initialSelectedDateMillis = selectedStartDate) + val endDatePickerState = rememberDatePickerState(initialSelectedDateMillis = selectedEndDate) + var isDatesEnabled by rememberSaveable { mutableStateOf(false) } + + LaunchedEffect(key1 = radioFilter) { + isDatesEnabled = radioFilter == SavingsTransactionRadioFilter.DATE + + when (radioFilter) { + SavingsTransactionRadioFilter.FOUR_WEEKS -> { + setStartDate(DateHelper.subtractWeeks(4)) + setEndDate(System.currentTimeMillis()) + } + + SavingsTransactionRadioFilter.THREE_MONTHS -> { + setStartDate(DateHelper.subtractMonths(3)) + setEndDate(System.currentTimeMillis()) + } + + SavingsTransactionRadioFilter.SIX_MONTHS -> { + setStartDate(DateHelper.subtractMonths(6)) + setEndDate(System.currentTimeMillis()) + } + + else -> Unit + } + } + + Column( + modifier = Modifier.scrollable(state = scrollState, orientation = Orientation.Vertical) + ) { + SavingsTransactionRadioFilter.entries.forEach { filter -> + MifosRadioButton( + selected = radioFilter == filter, + onClick = { selectRadioFilter(filter) }, + textResId = filter.textResId + ) + + if (filter == SavingsTransactionRadioFilter.DATE) { + Row { + MifosIconTextButton( + text = getDateAsStringFromLong(selectedStartDate), + imageVector = MifosIcons.Edit, + enabled = radioFilter == SavingsTransactionRadioFilter.DATE, + onClick = { showStartDatePickerDialog = true } + ) + MifosIconTextButton( + text = getDateAsStringFromLong(selectedEndDate), + imageVector = MifosIcons.Edit, + enabled = radioFilter == SavingsTransactionRadioFilter.DATE, + onClick = { showEndDatePickerDialog = true } + ) + } + } + } + + SavingsTransactionCheckBoxFilter.entries.forEach { filter -> + MifosCheckBox( + checked = when(filter) { + SavingsTransactionCheckBoxFilter.DEPOSIT -> isDepositChecked + SavingsTransactionCheckBoxFilter.DIVIDEND_PAYOUT -> isDividendPayoutChecked + SavingsTransactionCheckBoxFilter.WITHDRAWAL -> isWithdrawalChecked + SavingsTransactionCheckBoxFilter.INTEREST_POSTING -> isInterestPostingChecked + }, + onCheckChanged = { + toggleCheckBox(filter, it) + }, + text = stringResource(id = filter.textResId), + checkboxColors = CheckboxDefaults.colors().copy( + checkedBorderColor = filter.checkBoxColor, + uncheckedBorderColor = filter.checkBoxColor, + checkedBoxColor = filter.checkBoxColor, + ) + ) + } + } + + if (showStartDatePickerDialog) { + DatePickerDialog( + onDismissRequest = { showStartDatePickerDialog = false }, + confirmButton = { + startDatePickerState.selectedDateMillis?.let{ setStartDate(it) } + } + ) { DatePicker(state = startDatePickerState) } + } + + if (showEndDatePickerDialog) { + DatePickerDialog( + onDismissRequest = { showEndDatePickerDialog = false }, + confirmButton = { + endDatePickerState.selectedDateMillis?.let { setEndDate(it) } + } + ) { DatePicker(state = endDatePickerState) } + } +} + + +@Preview +@Composable +fun SavingsTransactionFilterDialogPreview() { + MifosMobileTheme { + SavingsTransactionFilterDialog( + savingsTransactionFilterDataModel = SavingsTransactionFilterDataModel( + radioFilter = null, + checkBoxFilters = mutableListOf(), + startDate = Instant.now().toEpochMilli(), + endDate = Instant.now().toEpochMilli() + ), + filter = {}, + onDismiss = {}, + ) + } +} + + diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionFragment.kt similarity index 86% rename from app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt rename to app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionFragment.kt index deb69d889..d1191ddd3 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SavingAccountsTransactionFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionFragment.kt @@ -1,9 +1,8 @@ -package org.mifos.mobile.ui.fragments +package org.mifos.mobile.ui.savings_account_transaction 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 @@ -27,28 +26,26 @@ import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.launch import org.mifos.mobile.R 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 import org.mifos.mobile.utils.CheckBoxStatusUtil -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.DateHelper +import org.mifos.mobile.core.common.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.core.common.Network +import org.mifos.mobile.core.model.entity.CheckboxStatus +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.model.entity.accounts.savings.Transactions +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.StatusUtils import org.mifos.mobile.utils.Toaster -import org.mifos.mobile.utils.getDatePickerDialog -import org.mifos.mobile.viewModels.SavingAccountsTransactionViewModel +import org.mifos.mobile.core.common.utils.getDatePickerDialog import java.time.Instant import javax.inject.Inject + /** * Created by dilpreet on 6/3/17. */ @@ -84,7 +81,7 @@ class SavingAccountsTransactionFragment : BaseFragment() { (activity as? SavingsAccountContainerActivity)?.showToolbar() setHasOptionsMenu(true) setToolbarTitle(getString(R.string.saving_account_transactions_details)) - if (arguments != null) savingsId = arguments?.getLong(Constants.SAVINGS_ID)!! + if (arguments != null) savingsId = arguments?.getLong(org.mifos.mobile.core.common.Constants.SAVINGS_ID)!! } override fun onCreateView( @@ -116,29 +113,29 @@ class SavingAccountsTransactionFragment : BaseFragment() { viewLifecycleOwner.lifecycleScope.launch { repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.savingAccountsTransactionUiState.collect { state -> - when (state) { - SavingsAccountUiState.Loading -> showProgress() - - SavingsAccountUiState.Error -> { - hideProgress() - showErrorFetchingSavingAccountsDetail(context?.getString(R.string.saving_account_details)) - } - - is SavingsAccountUiState.SuccessLoadingSavingsWithAssociations -> { - hideProgress() - showSavingAccountsDetail(state.savingAccount) - } - - is SavingsAccountUiState.ShowFilteredTransactionsList -> { - showFilteredList(state.savingAccountsTransactionList) - } - - is SavingsAccountUiState.Initial -> {} - - else -> throw IllegalStateException("Unexpected State : $state") - } - } +// viewModel.savingAccountsTransactionUiState.collect { state -> +// when (state) { +// SavingsAccountUiState.Loading -> showProgress() +// +// SavingsAccountUiState.Error -> { +// hideProgress() +// showErrorFetchingSavingAccountsDetail(context?.getString(R.string.saving_account_details)) +// } +// +// is SavingsAccountUiState.SuccessLoadingSavingsWithAssociations -> { +// hideProgress() +// showSavingAccountsDetail(state.savingAccount) +// } +// +// is SavingsAccountUiState.ShowFilteredTransactionsList -> { +// showFilteredList(state.savingAccountsTransactionList) +// } +// +// is SavingsAccountUiState.Initial -> {} +// +// else -> throw IllegalStateException("Unexpected State : $state") +// } +// } } } } @@ -152,7 +149,7 @@ class SavingAccountsTransactionFragment : BaseFragment() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - outState.putParcelable(Constants.SAVINGS_ACCOUNTS, savingsWithAssociations) + outState.putParcelable(org.mifos.mobile.core.common.Constants.SAVINGS_ACCOUNTS, savingsWithAssociations) } override fun onActivityCreated(savedInstanceState: Bundle?) { @@ -161,7 +158,7 @@ class SavingAccountsTransactionFragment : BaseFragment() { showSavingAccountsDetail( savedInstanceState.getCheckedParcelable( SavingsWithAssociations::class.java, - Constants.SAVINGS_ACCOUNTS + org.mifos.mobile.core.common.Constants.SAVINGS_ACCOUNTS ) ) } } @@ -273,7 +270,7 @@ class SavingAccountsTransactionFragment : BaseFragment() { tvEndDate?.isEnabled = true tvStartDate?.text = DateHelper.getDateAsStringFromLong(it) startDate = it - }.show(requireActivity().supportFragmentManager, Constants.DFRAG_DATE_PICKER) + }.show(requireActivity().supportFragmentManager, org.mifos.mobile.core.common.Constants.DFRAG_DATE_PICKER) } private fun endDatePick() { @@ -282,7 +279,7 @@ class SavingAccountsTransactionFragment : BaseFragment() { endDate = it tvEndDate?.text = DateHelper.getDateAsStringFromLong(it) isReady = true - }.show(requireActivity().supportFragmentManager, Constants.DFRAG_DATE_PICKER) + }.show(requireActivity().supportFragmentManager, org.mifos.mobile.core.common.Constants.DFRAG_DATE_PICKER) } /** @@ -428,11 +425,11 @@ class SavingAccountsTransactionFragment : BaseFragment() { val hasOtherFilters = statusModelList?.any { it!!.isChecked } val transactionListToFilter = if (hasOtherFilters == true) filterSavingsAccountTransactionsByType(statusModelList) else transactionsList - viewModel.filterTransactionList( - transactionListToFilter, - startDate, - endDate, - ) +// viewModel.filterTransactionList( +// transactionListToFilter, +// startDate, +// endDate, +// ) } /** @@ -450,12 +447,12 @@ class SavingAccountsTransactionFragment : BaseFragment() { */ private fun filterSavingsAccountTransactionsByType(statusModelList: List?): List { val filteredSavingsTransactions: MutableList = ArrayList() - for (status in viewModel - .getCheckedStatus(statusModelList)!!) { - viewModel - .filterTransactionListByType(transactionsList, status, getCheckBoxStatusStrings()) - ?.let { filteredSavingsTransactions.addAll(it) } - } +// for (status in viewModel +// .getCheckedStatus(statusModelList)!!) { +// viewModel +// .filterTransactionListByType(transactionsList, status, getCheckBoxStatusStrings()) +// ?.let { filteredSavingsTransactions.addAll(it) } +// } return filteredSavingsTransactions } @@ -489,7 +486,7 @@ class SavingAccountsTransactionFragment : BaseFragment() { fun newInstance(savingsId: Long?): SavingAccountsTransactionFragment { val fragment = SavingAccountsTransactionFragment() val args = Bundle() - if (savingsId != null) args.putLong(Constants.SAVINGS_ID, savingsId) + if (savingsId != null) args.putLong(org.mifos.mobile.core.common.Constants.SAVINGS_ID, savingsId) fragment.arguments = args return fragment } diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionScreen.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionScreen.kt new file mode 100644 index 000000000..a0b137f13 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionScreen.kt @@ -0,0 +1,161 @@ +package org.mifos.mobile.ui.savings_account_transaction + + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.EmptyDataView +import org.mifos.mobile.core.ui.component.MFScaffold +import org.mifos.mobile.core.ui.component.MifosErrorComponent +import org.mifos.mobile.core.ui.component.MifosIcons +import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay +import org.mifos.mobile.core.ui.component.MifosTopBar +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.model.entity.accounts.savings.Transactions +import java.time.Instant + +@Composable +fun SavingsAccountTransactionScreen( + viewModel: SavingAccountsTransactionViewModel = hiltViewModel(), + navigateBack: () -> Unit, +) { + val uiState by viewModel.savingAccountsTransactionUiState.collectAsStateWithLifecycle() + SavingsAccountTransactionScreen( + uiState = uiState, + navigateBack = navigateBack, + retryConnection = { viewModel.loadSavingsWithAssociations(viewModel.savingsId) }, + filterList = { viewModel.filterList(filter = it) } + ) +} + +@Composable +fun SavingsAccountTransactionScreen( + uiState: SavingsAccountTransactionUiState, + navigateBack: () -> Unit, + retryConnection: () -> Unit, + filterList: (SavingsTransactionFilterDataModel) -> Unit, +) { + val context = LocalContext.current + var transactionList by rememberSaveable { mutableStateOf(listOf()) } + var isDialogOpen by rememberSaveable { mutableStateOf(false) } + var savingsTransactionFilterDataModel by rememberSaveable { + mutableStateOf( + SavingsTransactionFilterDataModel( + startDate = Instant.now().toEpochMilli(), + endDate = Instant.now().toEpochMilli(), + radioFilter = null, + checkBoxFilters = mutableListOf() + ) + ) + } + + MFScaffold( + topBar = { + MifosTopBar( + navigateBack = navigateBack, + title = { + Text( + text = stringResource(id = R.string.savings_account_transaction), + overflow = TextOverflow.Ellipsis, + maxLines = 1 + ) + }, + actions = { + IconButton(onClick = { isDialogOpen = true }) { + Icon( + imageVector = MifosIcons.FilterList, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurface + ) + } + } + ) + }, + scaffoldContent = { paddingValues -> + Box(modifier = Modifier.padding(paddingValues = paddingValues)) { + when (uiState) { + is SavingsAccountTransactionUiState.Loading -> { + MifosProgressIndicatorOverlay() + } + + is SavingsAccountTransactionUiState.Error -> { + MifosErrorComponent( + isNetworkConnected = Network.isConnected(context), + isEmptyData = false, + isRetryEnabled = true, + onRetry = retryConnection + ) + } + + is SavingsAccountTransactionUiState.Success -> { + if (uiState.savingAccountsTransactionList.isNullOrEmpty()) { + EmptyDataView( + icon = R.drawable.ic_compare_arrows_black_24dp, + error = R.string.no_transaction_found + ) + } else { + transactionList = uiState.savingAccountsTransactionList + SavingsAccountTransactionContent(transactionList = transactionList) + } + } + } + } + } + ) + + if (isDialogOpen) { + SavingsTransactionFilterDialog( + savingsTransactionFilterDataModel = savingsTransactionFilterDataModel, + onDismiss = { isDialogOpen = false }, + filter = { filters -> + savingsTransactionFilterDataModel = filters + filterList(filters) + }, + ) + } +} + +class SavingsAccountTransactionUiStatesParameterProvider : + PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + SavingsAccountTransactionUiState.Success(listOf()), + SavingsAccountTransactionUiState.Error(""), + SavingsAccountTransactionUiState.Loading, + ) +} + +@Preview(showSystemUi = true) +@Composable +fun SavingsAccountTransactionScreenPreview( + @PreviewParameter(SavingsAccountTransactionUiStatesParameterProvider::class) savingsAccountUiState: SavingsAccountTransactionUiState +) { + MifosMobileTheme { + SavingsAccountTransactionScreen( + uiState = savingsAccountUiState, + navigateBack = { }, + retryConnection = { }, + filterList = { } + ) + } +} + diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionViewModel.kt new file mode 100644 index 000000000..fdfb02fec --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingAccountsTransactionViewModel.kt @@ -0,0 +1,203 @@ +package org.mifos.mobile.ui.savings_account_transaction + + +import android.os.Parcelable +import androidx.compose.ui.graphics.Color +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 kotlinx.parcelize.Parcelize +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.theme.DepositGreen +import org.mifos.mobile.core.ui.theme.GreenSuccess +import org.mifos.mobile.core.ui.theme.RedLight +import org.mifos.mobile.core.data.repositories.SavingsAccountRepository +import org.mifos.mobile.core.model.entity.accounts.savings.TransactionType +import org.mifos.mobile.core.model.entity.accounts.savings.Transactions +import org.mifos.mobile.core.common.utils.DateHelper +import javax.inject.Inject + +@HiltViewModel +class SavingAccountsTransactionViewModel @Inject constructor(private val savingsAccountRepositoryImp: SavingsAccountRepository) : + ViewModel() { + + private val _savingAccountsTransactionUiState = MutableStateFlow(SavingsAccountTransactionUiState.Loading) + val savingAccountsTransactionUiState: StateFlow get() = _savingAccountsTransactionUiState + + private var _transactionsList: List = mutableListOf() + private val transactionsList: List get() = _transactionsList + + private var _savingsId: Long = 0 + val savingsId get() = _savingsId + + fun setSavingsId(savingsId: Long) { + _savingsId = savingsId + loadSavingsWithAssociations(savingsId) + } + + fun loadSavingsWithAssociations(accountId: Long) { + viewModelScope.launch { + _savingAccountsTransactionUiState.value = SavingsAccountTransactionUiState.Loading + savingsAccountRepositoryImp.getSavingsWithAssociations( + accountId, + org.mifos.mobile.core.common.Constants.TRANSACTIONS, + ).catch { + _savingAccountsTransactionUiState.value = + SavingsAccountTransactionUiState.Error(it.message) + }.collect { + _transactionsList = it.transactions + _savingAccountsTransactionUiState.value = + SavingsAccountTransactionUiState.Success(it.transactions) + } + } + } + + fun filterList(filter: SavingsTransactionFilterDataModel) { + when { + filter.radioFilter != null && filter.checkBoxFilters.isNotEmpty() -> { + filterByDateAndType( + startDate = filter.startDate, + endDate = filter.endDate, + checkBoxFilters = filter.checkBoxFilters + ) + } + filter.radioFilter != null -> { + filterByDate( + startDate = filter.startDate, + endDate = filter.endDate + ) + } + filter.checkBoxFilters.isNotEmpty() -> { + filterByType( + checkBoxFilters = filter.checkBoxFilters + ) + } + else -> { + _savingAccountsTransactionUiState.value = SavingsAccountTransactionUiState.Success(transactionsList) + } + } + } + + + private fun filterByDateAndType( + startDate: Long, + endDate: Long, + checkBoxFilters: MutableList + ) { + val typeFilteredList = filterSavingsAccountTransactionsByType(checkBoxFilters = checkBoxFilters) + val dateAndTypeFilteredList = filterTransactionListByDate(transactions = typeFilteredList, startDate = startDate, endDate = endDate) + _savingAccountsTransactionUiState.value = SavingsAccountTransactionUiState.Success(dateAndTypeFilteredList) + } + + private fun filterByDate(startDate: Long, endDate: Long) { + val list = filterTransactionListByDate(transactions = transactionsList, startDate = startDate, endDate = endDate) + _savingAccountsTransactionUiState.value = SavingsAccountTransactionUiState.Success(list) + } + + private fun filterByType( + checkBoxFilters: MutableList + ) { + val list = filterSavingsAccountTransactionsByType(checkBoxFilters = checkBoxFilters) + _savingAccountsTransactionUiState.value = SavingsAccountTransactionUiState.Success(list) + } + + private fun filterTransactionListByDate( + transactions: List, + startDate: Long, + endDate: Long + ): List { + return transactions.filter { + (DateHelper.getDateAsLongFromList(it.date) in startDate..endDate) + } + } + + private fun filterSavingsAccountTransactionsByType( + checkBoxFilters: MutableList + ): List { + var filteredSavingsTransactions: List = ArrayList() + checkBoxFilters.forEach { filter -> + val list = when (filter) { + SavingsTransactionCheckBoxFilter.DEPOSIT -> { + transactionsList.filter { it.transactionType?.deposit == true } + } + SavingsTransactionCheckBoxFilter.DIVIDEND_PAYOUT -> { + transactionsList.filter { it.transactionType?.dividendPayout == true } + } + SavingsTransactionCheckBoxFilter.WITHDRAWAL -> { + transactionsList.filter { it.transactionType?.withdrawal == true } + } + SavingsTransactionCheckBoxFilter.INTEREST_POSTING -> { + transactionsList.filter { it.transactionType?.interestPosting == true } + } + } + filteredSavingsTransactions = filteredSavingsTransactions.plus(list) + } + return filteredSavingsTransactions + } +} + +sealed class SavingsAccountTransactionUiState { + data object Loading : SavingsAccountTransactionUiState() + data class Error(val errorMessage: String?) : SavingsAccountTransactionUiState() + data class Success(val savingAccountsTransactionList: List?) : SavingsAccountTransactionUiState() +} + +fun getTransactionTriangleResId(transactionType: TransactionType?): Int { + return transactionType?.run { + when { + deposit == true -> R.drawable.triangular_green_view + dividendPayout == true -> R.drawable.triangular_red_view + withdrawal == true -> R.drawable.triangular_red_view + interestPosting == true -> R.drawable.triangular_green_view + feeDeduction == true -> R.drawable.triangular_red_view + initiateTransfer == true -> R.drawable.triangular_red_view + approveTransfer == true -> R.drawable.triangular_red_view + withdrawTransfer == true -> R.drawable.triangular_red_view + rejectTransfer == true -> R.drawable.triangular_green_view + overdraftFee == true -> R.drawable.triangular_red_view + else -> R.drawable.triangular_green_view + } + } ?: R.drawable.triangular_red_view +} + +@Parcelize +data class SavingsTransactionFilterDataModel( + val startDate: Long, + val endDate: Long, + val radioFilter: SavingsTransactionRadioFilter?, + val checkBoxFilters: MutableList +): Parcelable + +enum class SavingsTransactionRadioFilter(val textResId: Int) { + DATE(textResId = R.string.date), + FOUR_WEEKS(textResId = R.string.four_weeks), + THREE_MONTHS(textResId = R.string.three_months), + SIX_MONTHS(textResId = R.string.six_months) +} + +enum class SavingsTransactionCheckBoxFilter( + val textResId: Int, + val checkBoxColor: Color, +) { + DEPOSIT( + textResId = R.string.deposit, + checkBoxColor = DepositGreen + ), + DIVIDEND_PAYOUT( + textResId = R.string.dividend_payout, + checkBoxColor = RedLight + ), + WITHDRAWAL( + textResId = R.string.withdrawal, + checkBoxColor = RedLight + ), + INTEREST_POSTING( + textResId = R.string.interest_posting, + checkBoxColor = GreenSuccess + ) +} + diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingsAccountTransactionComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingsAccountTransactionComposeFragment.kt new file mode 100644 index 000000000..9c57916be --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_transaction/SavingsAccountTransactionComposeFragment.kt @@ -0,0 +1,51 @@ +package org.mifos.mobile.ui.savings_account_transaction + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.viewModels +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity +import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.core.common.Constants + + +@AndroidEntryPoint +class SavingAccountsTransactionComposeFragment : BaseFragment() { + + private val viewModel: SavingAccountsTransactionViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + (activity as? SavingsAccountContainerActivity)?.hideToolbar() + if (arguments != null) { + arguments?.getLong(Constants.SAVINGS_ID)?.let { + viewModel.setSavingsId(it) + } + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + return mifosComposeView(requireContext()) { + SavingsAccountTransactionScreen( + navigateBack = { activity?.supportFragmentManager?.popBackStack() }, + ) + } + } + + companion object { + fun newInstance(savingsId: Long?): SavingAccountsTransactionComposeFragment { + val fragment = SavingAccountsTransactionComposeFragment() + val args = Bundle() + if (savingsId != null) args.putLong(Constants.SAVINGS_ID, savingsId) + fragment.arguments = args + return fragment + } + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawFragment.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawFragment.kt index 29a3e11b4..d52d91b5d 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawFragment.kt @@ -9,11 +9,10 @@ import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.fragment.app.viewModels import dagger.hilt.android.AndroidEntryPoint 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.fragments.base.BaseFragment -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable /* * Created by saksham on 02/July/2018 @@ -26,7 +25,7 @@ class SavingsAccountWithdrawFragment : BaseFragment() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) (activity as? SavingsAccountContainerActivity)?.hideToolbar() - arguments?.getCheckedParcelable(SavingsWithAssociations::class.java, Constants.SAVINGS_ACCOUNTS)?.let { + arguments?.getCheckedParcelable(SavingsWithAssociations::class.java, org.mifos.mobile.core.common.Constants.SAVINGS_ACCOUNTS)?.let { viewModel.setContent(it) } } @@ -61,7 +60,7 @@ class SavingsAccountWithdrawFragment : BaseFragment() { ): SavingsAccountWithdrawFragment { val fragment = SavingsAccountWithdrawFragment() val bundle = Bundle() - bundle.putParcelable(Constants.SAVINGS_ACCOUNTS, savingsWithAssociations) + bundle.putParcelable(org.mifos.mobile.core.common.Constants.SAVINGS_ACCOUNTS, savingsWithAssociations) fragment.arguments = bundle return fragment } diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawScreen.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawScreen.kt index 3f192b4d4..95230fcce 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawScreen.kt @@ -35,9 +35,9 @@ import org.mifos.mobile.core.ui.component.MifosTitleDescSingleLineEqual import org.mifos.mobile.core.ui.component.MifosTopBar 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 -import org.mifos.mobile.utils.getTodayFormatted +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.common.utils.getTodayFormatted @Composable diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawViewModel.kt index 7f5a08778..a7e16928d 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_account_withdraw/SavingsAccountWithdrawViewModel.kt @@ -1,7 +1,5 @@ package org.mifos.mobile.ui.savings_account_withdraw -import androidx.compose.runtime.MutableState -import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -9,10 +7,10 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch -import org.mifos.mobile.models.accounts.savings.SavingsAccountWithdrawPayload -import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations -import org.mifos.mobile.repositories.SavingsAccountRepository -import org.mifos.mobile.utils.getTodayFormatted +import org.mifos.mobile.core.data.repositories.SavingsAccountRepository +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountWithdrawPayload +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.common.utils.getTodayFormatted import javax.inject.Inject @HiltViewModel diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferComposeFragment.kt index cf735fddd..9e74def24 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferComposeFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferComposeFragment.kt @@ -2,25 +2,19 @@ package org.mifos.mobile.ui.savings_make_transfer import android.os.Bundle 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 androidx.fragment.app.viewModels -import androidx.navigation.findNavController import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.launch import org.mifos.mobile.R import org.mifos.mobile.core.ui.component.mifosComposeView -import org.mifos.mobile.models.payload.TransferPayload import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.enums.TransferType -import org.mifos.mobile.ui.fragments.TransferProcessFragment +import org.mifos.mobile.core.model.enums.TransferType 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.getTodayFormatted +import org.mifos.mobile.ui.transfer_process.TransferProcessComposeFragment +import org.mifos.mobile.core.model.entity.payload.TransferPayload +import org.mifos.mobile.core.common.utils.DateHelper +import org.mifos.mobile.core.common.utils.getTodayFormatted @AndroidEntryPoint @@ -32,9 +26,9 @@ class SavingsMakeTransferComposeFragment : BaseFragment() { (activity as? BaseActivity)?.hideToolbar() if (arguments != null) { viewModel.initArgs( - accountId = arguments?.getLong(Constants.ACCOUNT_ID), - transferType = arguments?.getString(Constants.TRANSFER_TYPE), - outstandingBalance = arguments?.getDouble(Constants.OUTSTANDING_BALANCE) + accountId = arguments?.getLong(org.mifos.mobile.core.common.Constants.ACCOUNT_ID), + transferType = arguments?.getString(org.mifos.mobile.core.common.Constants.TRANSFER_TYPE), + outstandingBalance = arguments?.getDouble(org.mifos.mobile.core.common.Constants.OUTSTANDING_BALANCE) ) } } @@ -71,7 +65,7 @@ class SavingsMakeTransferComposeFragment : BaseFragment() { } (activity as BaseActivity?)?.replaceFragment( - TransferProcessFragment.newInstance(transferPayload, TransferType.SELF), + TransferProcessComposeFragment.newInstance(transferPayload, TransferType.SELF), true, R.id.container, ) @@ -92,8 +86,8 @@ class SavingsMakeTransferComposeFragment : BaseFragment() { fun newInstance(accountId: Long?, transferType: String?): SavingsMakeTransferComposeFragment { val transferFragment = SavingsMakeTransferComposeFragment() val args = Bundle() - if (accountId != null) args.putLong(Constants.ACCOUNT_ID, accountId) - args.putString(Constants.TRANSFER_TYPE, transferType) + if (accountId != null) args.putLong(org.mifos.mobile.core.common.Constants.ACCOUNT_ID, accountId) + args.putString(org.mifos.mobile.core.common.Constants.TRANSFER_TYPE, transferType) transferFragment.arguments = args return transferFragment } @@ -105,15 +99,15 @@ class SavingsMakeTransferComposeFragment : BaseFragment() { ): SavingsMakeTransferComposeFragment { val transferFragment = SavingsMakeTransferComposeFragment() val args = Bundle() - if (accountId != null) args.putLong(Constants.ACCOUNT_ID, accountId) - args.putString(Constants.TRANSFER_TYPE, transferType) + if (accountId != null) args.putLong(org.mifos.mobile.core.common.Constants.ACCOUNT_ID, accountId) + args.putString(org.mifos.mobile.core.common.Constants.TRANSFER_TYPE, transferType) if (outstandingBalance != null) { args.putDouble( - Constants.OUTSTANDING_BALANCE, + org.mifos.mobile.core.common.Constants.OUTSTANDING_BALANCE, outstandingBalance, ) } - args.putBoolean(Constants.LOAN_REPAYMENT, true) + args.putBoolean(org.mifos.mobile.core.common.Constants.LOAN_REPAYMENT, true) transferFragment.arguments = args return transferFragment } diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferContent.kt b/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferContent.kt index 271888eaa..4df86fe2c 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferContent.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferContent.kt @@ -41,6 +41,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.templates.account.AccountOption import org.mifos.mobile.core.ui.component.MFStepProcess import org.mifos.mobile.core.ui.component.MifosDropDownDoubleTextField import org.mifos.mobile.core.ui.component.MifosOutlinedTextField @@ -49,11 +50,6 @@ import org.mifos.mobile.core.ui.component.getStepState import org.mifos.mobile.core.ui.theme.DarkGray import org.mifos.mobile.core.ui.theme.MifosMobileTheme import org.mifos.mobile.core.ui.theme.Primary -import org.mifos.mobile.models.accounts.loan.LoanWithAssociations -import org.mifos.mobile.models.payload.AccountDetail -import org.mifos.mobile.models.templates.account.AccountOption -import org.mifos.mobile.ui.loan_account_withdraw.LoanAccountWithdrawScreen -import org.mifos.mobile.ui.loan_account_withdraw.LoanAccountWithdrawUiState @Composable fun SavingsMakeTransferContent( diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferFragment.kt b/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferFragment.kt index dcd1e3ab3..51be6d7ac 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferFragment.kt @@ -1,464 +1,432 @@ package org.mifos.mobile.ui.savings_make_transfer -import android.os.Bundle -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.EditText -import android.widget.Spinner -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.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.base.BaseActivity -import org.mifos.mobile.ui.adapters.AccountsSpinnerAdapter -import org.mifos.mobile.ui.enums.TransferType -import org.mifos.mobile.ui.fragments.TransferProcessFragment 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 -import org.mifos.mobile.utils.getTodayFormatted /** * Created by Rajan Maurya on 10/03/17. */ @AndroidEntryPoint class SavingsMakeTransferFragment : BaseFragment() { - - private var _binding: FragmentSavingsMakeTransferBinding? = null - private val binding get() = _binding!! - private val viewModel: SavingsMakeTransferViewModel by viewModels() - private var transferPayload: TransferPayload? = null - private var transferDate: String? = null - private var toAccountOption: AccountOption? = null - private var fromAccountOption: AccountOption? = null - private var accountOptionsTemplate: AccountOptionsTemplate? = null - private var transferType: String? = null - private var payTo: String? = null - private var payFrom: String? = null - private var accountId: Long? = 0 - private var outStandingBalance: Double? = 0.0 - private var isLoanRepayment = false - private var sweetUIErrorHandler: SweetUIErrorHandler? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - (activity as? BaseActivity)?.showToolbar() - if (arguments != null) { - accountId = arguments?.getLong(Constants.ACCOUNT_ID) - transferType = arguments?.getString(Constants.TRANSFER_TYPE) - if (arguments?.getBoolean(Constants.LOAN_REPAYMENT, false) == true) { - isLoanRepayment = true - outStandingBalance = arguments?.getDouble(Constants.OUTSTANDING_BALANCE) - } - } - setHasOptionsMenu(true) - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = FragmentSavingsMakeTransferBinding.inflate(inflater, container, false) - setToolbarTitle(getString(R.string.transfer)) - sweetUIErrorHandler = SweetUIErrorHandler(activity, binding.root) - showUserInterface() - if (savedInstanceState == null) { - //viewModel.loanAccountTransferTemplate() - } - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - with(binding) { - btnCancelTransfer.setOnClickListener { - cancelTransfer() - } - - btnReviewTransfer.setOnClickListener { - reviewTransfer() - } - - btnPayFrom.setOnClickListener { - payFromSelected() - } - - btnPayTo.setOnClickListener { - payToSelected() - } - - btnAmount.setOnClickListener { - amountSet() - } - - layoutError.btnTryAgain.setOnClickListener { - onRetry() - } - } - -// viewLifecycleOwner.lifecycleScope.launch { -// repeatOnLifecycle(Lifecycle.State.STARTED) { -// viewModel.savingsMakeTransferUiState.collect { state -> -// when (state) { -// SavingsAccountUiState.Loading -> showProgress() -// -// is SavingsAccountUiState.ErrorMessage -> { -// hideProgress() -// showError(context?.getString(R.string.error_fetching_account_transfer_template)) -// } -// -// is SavingsAccountUiState.ShowSavingsAccountTemplate -> { -// hideProgress() -// showSavingsAccountTemplate(state.accountOptionsTemplate) -// } -// -// is SavingsAccountUiState.Initial -> {} -// -// else -> throw IllegalStateException("Unexpected state : $state") -// } -// } +// +// private var _binding: FragmentSavingsMakeTransferBinding? = null +// private val binding get() = _binding!! +// private val viewModel: SavingsMakeTransferViewModel by viewModels() +// private var transferPayload: TransferPayload? = null +// private var transferDate: String? = null +// private var toAccountOption: AccountOption? = null +// private var fromAccountOption: AccountOption? = null +// private var accountOptionsTemplate: AccountOptionsTemplate? = null +// private var transferType: String? = null +// private var payTo: String? = null +// private var payFrom: String? = null +// private var accountId: Long? = 0 +// private var outStandingBalance: Double? = 0.0 +// private var isLoanRepayment = false +// private var sweetUIErrorHandler: SweetUIErrorHandler? = null +// +// override fun onCreate(savedInstanceState: Bundle?) { +// super.onCreate(savedInstanceState) +// (activity as? BaseActivity)?.showToolbar() +// if (arguments != null) { +// accountId = arguments?.getLong(Constants.ACCOUNT_ID) +// transferType = arguments?.getString(Constants.TRANSFER_TYPE) +// if (arguments?.getBoolean(Constants.LOAN_REPAYMENT, false) == true) { +// isLoanRepayment = true +// outStandingBalance = arguments?.getDouble(Constants.OUTSTANDING_BALANCE) // } // } - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putParcelable(Constants.TEMPLATE, accountOptionsTemplate) - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) - if (savedInstanceState != null) { - showSavingsAccountTemplate( - savedInstanceState.getCheckedParcelable( - AccountOptionsTemplate::class.java, - Constants.TEMPLATE - ) - ) } - } - - /** - * Checks validation of `etRemark` and then opens [TransferProcessFragment] for - * initiating the transfer - */ - private fun reviewTransfer() { - if (binding.etRemark.text.toString().trim { it <= ' ' } == "") { - showToaster(getString(R.string.remark_is_mandatory)) - return - } - transferPayload = TransferPayload() - transferPayload?.fromAccountId = fromAccountOption?.accountId - transferPayload?.fromClientId = fromAccountOption?.clientId - transferPayload?.fromAccountType = fromAccountOption?.accountType?.id - transferPayload?.fromOfficeId = fromAccountOption?.officeId - transferPayload?.toOfficeId = toAccountOption?.officeId - transferPayload?.toAccountId = toAccountOption?.accountId - transferPayload?.toClientId = toAccountOption?.clientId - transferPayload?.toAccountType = toAccountOption?.accountType?.id - transferPayload?.transferDate = transferDate - transferPayload?.transferAmount = binding.amountField.text.toString().toDouble() - transferPayload?.transferDescription = binding.etRemark.text.toString() - transferPayload?.fromAccountNumber = fromAccountOption?.accountNo - transferPayload?.toAccountNumber = toAccountOption?.accountNo - (activity as BaseActivity?)?.replaceFragment( - TransferProcessFragment.newInstance( - transferPayload, - TransferType.SELF, - ), - true, - R.id.container, - ) - } - - /** - * Cancels the transfer by popping current Fragment - */ - private fun cancelTransfer() { - activity?.supportFragmentManager?.popBackStack() - } - - private fun onRetry() { - if (Network.isConnected(context)) { - sweetUIErrorHandler?.hideSweetErrorLayoutUI( - binding.llMakeTransfer, - binding.layoutError.root, - ) - //viewModel.loanAccountTransferTemplate() - } else { - Toaster.show(binding.root, getString(R.string.internet_not_connected)) - } - } - - /** - * Setting up basic components - */ - fun showUserInterface() { - binding.processOne.setCurrentActive() - binding.payFromField.setOnItemClickListener { _, _, position, _ -> - toAccountOption = accountOptionsTemplate?.toAccountOptions?.get(position) - payTo = toAccountOption?.accountNo - println("paytofield item selected payTo:$payTo") - updateDetails() - } - binding.payToField.setOnItemClickListener { _, _, position, _ -> - fromAccountOption = accountOptionsTemplate?.fromAccountOptions?.get(position) - payFrom = fromAccountOption?.accountNo - println("payfrom item selected payFrom:$payFrom") - updateDetails() - } - transferDate = DateHelper.getSpecificFormat( - DateHelper.FORMAT_dd_MMMM_yyyy, - getTodayFormatted(), - ) - if (isLoanRepayment) { - binding.amountField.setText(outStandingBalance.toString()) - binding.amountFieldWrapper.isFocusable = false - } - } - - private fun updateDetails() { -// when (transferType) { -// Constants.TRANSFER_PAY_TO -> { -// setToolbarTitle(getString(R.string.deposit)) -// toAccountOption = -// viewModel.searchAccount(accountOptionsTemplate?.toAccountOptions, accountId) -// binding.payToFieldWrapper.isEnabled = false -// binding.processOne.setCurrentCompleted() +// setHasOptionsMenu(true) +// } +// +// override fun onCreateView( +// inflater: LayoutInflater, +// container: ViewGroup?, +// savedInstanceState: Bundle?, +// ): View { +// _binding = FragmentSavingsMakeTransferBinding.inflate(inflater, container, false) +// setToolbarTitle(getString(R.string.transfer)) +// sweetUIErrorHandler = SweetUIErrorHandler(activity, binding.root) +// showUserInterface() +// if (savedInstanceState == null) { +// //viewModel.loanAccountTransferTemplate() +// } +// return binding.root +// } +// +// override fun onViewCreated(view: View, savedInstanceState: Bundle?) { +// super.onViewCreated(view, savedInstanceState) +// +// with(binding) { +// btnCancelTransfer.setOnClickListener { +// cancelTransfer() +// } +// +// btnReviewTransfer.setOnClickListener { +// reviewTransfer() +// } +// +// btnPayFrom.setOnClickListener { +// payFromSelected() // } // -// Constants.TRANSFER_PAY_FROM -> { -// setToolbarTitle(getString(R.string.transfer)) -// fromAccountOption = -// viewModel.searchAccount(accountOptionsTemplate?.fromAccountOptions, accountId) -// binding.payFromFieldWrapper.isEnabled = false -// binding.payFromFieldWrapper.visibility = View.VISIBLE -// binding.processTwo.setCurrentCompleted() +// btnPayTo.setOnClickListener { +// payToSelected() +// } +// +// btnAmount.setOnClickListener { +// amountSet() +// } +// +// layoutError.btnTryAgain.setOnClickListener { +// onRetry() // } // } - } - - /** - * Provides with `accountOptionsTemplate` fetched from server which is used to update - * `listPayFrom` and `listPayTo` - * - * @param accountOptionsTemplate Template for account transfer - */ - private fun showSavingsAccountTemplate(accountOptionsTemplate: AccountOptionsTemplate?) { - this.accountOptionsTemplate = accountOptionsTemplate -// binding.payToField.setAdapter( -// AccountsSpinnerAdapter( -// requireContext(), -// viewModel.getAccountNumbers( -// accountOptionsTemplate?.toAccountOptions, -// false, -// context?.getString(R.string.account_type_loan) -// ), +// +//// viewLifecycleOwner.lifecycleScope.launch { +//// repeatOnLifecycle(Lifecycle.State.STARTED) { +//// viewModel.savingsMakeTransferUiState.collect { state -> +//// when (state) { +//// SavingsAccountUiState.Loading -> showProgress() +//// +//// is SavingsAccountUiState.ErrorMessage -> { +//// hideProgress() +//// showError(context?.getString(R.string.error_fetching_account_transfer_template)) +//// } +//// +//// is SavingsAccountUiState.ShowSavingsAccountTemplate -> { +//// hideProgress() +//// showSavingsAccountTemplate(state.accountOptionsTemplate) +//// } +//// +//// is SavingsAccountUiState.Initial -> {} +//// +//// else -> throw IllegalStateException("Unexpected state : $state") +//// } +//// } +//// } +//// } +// } +// +// override fun onSaveInstanceState(outState: Bundle) { +// super.onSaveInstanceState(outState) +// outState.putParcelable(Constants.TEMPLATE, accountOptionsTemplate) +// } +// +// override fun onActivityCreated(savedInstanceState: Bundle?) { +// super.onActivityCreated(savedInstanceState) +// if (savedInstanceState != null) { +// showSavingsAccountTemplate( +// savedInstanceState.getCheckedParcelable( +// AccountOptionsTemplate::class.java, +// Constants.TEMPLATE +// ) +// ) } +// } +// +// /** +// * Checks validation of `etRemark` and then opens [TransferProcessComposeFragment] for +// * initiating the transfer +// */ +// private fun reviewTransfer() { +// if (binding.etRemark.text.toString().trim { it <= ' ' } == "") { +// showToaster(getString(R.string.remark_is_mandatory)) +// return +// } +// transferPayload = TransferPayload() +// transferPayload?.fromAccountId = fromAccountOption?.accountId +// transferPayload?.fromClientId = fromAccountOption?.clientId +// transferPayload?.fromAccountType = fromAccountOption?.accountType?.id +// transferPayload?.fromOfficeId = fromAccountOption?.officeId +// transferPayload?.toOfficeId = toAccountOption?.officeId +// transferPayload?.toAccountId = toAccountOption?.accountId +// transferPayload?.toClientId = toAccountOption?.clientId +// transferPayload?.toAccountType = toAccountOption?.accountType?.id +// transferPayload?.transferDate = transferDate +// transferPayload?.transferAmount = binding.amountField.text.toString().toDouble() +// transferPayload?.transferDescription = binding.etRemark.text.toString() +// transferPayload?.fromAccountNumber = fromAccountOption?.accountNo +// transferPayload?.toAccountNumber = toAccountOption?.accountNo +// (activity as BaseActivity?)?.replaceFragment( +// TransferProcessComposeFragment.newInstance( +// transferPayload, +// TransferType.SELF, // ), +// true, +// R.id.container, // ) -// binding.payFromField.setAdapter( -// AccountsSpinnerAdapter( -// requireContext(), -// viewModel.getAccountNumbers( -// accountOptionsTemplate?.toAccountOptions, -// true, -// context?.getString(R.string.account_type_loan) -// ), -// ), +// } +// +// /** +// * Cancels the transfer by popping current Fragment +// */ +// private fun cancelTransfer() { +// activity?.supportFragmentManager?.popBackStack() +// } +// +// private fun onRetry() { +// if (Network.isConnected(context)) { +// sweetUIErrorHandler?.hideSweetErrorLayoutUI( +// binding.llMakeTransfer, +// binding.layoutError.root, +// ) +// //viewModel.loanAccountTransferTemplate() +// } else { +// Toaster.show(binding.root, getString(R.string.internet_not_connected)) +// } +// } +// +// /** +// * Setting up basic components +// */ +// fun showUserInterface() { +// binding.processOne.setCurrentActive() +// binding.payFromField.setOnItemClickListener { _, _, position, _ -> +// toAccountOption = accountOptionsTemplate?.toAccountOptions?.get(position) +// payTo = toAccountOption?.accountNo +// println("paytofield item selected payTo:$payTo") +// updateDetails() +// } +// binding.payToField.setOnItemClickListener { _, _, position, _ -> +// fromAccountOption = accountOptionsTemplate?.fromAccountOptions?.get(position) +// payFrom = fromAccountOption?.accountNo +// println("payfrom item selected payFrom:$payFrom") +// updateDetails() +// } +// transferDate = DateHelper.getSpecificFormat( +// DateHelper.FORMAT_dd_MMMM_yyyy, +// getTodayFormatted(), // ) - } - - /** - * Shows a {@link Snackbar} with `message` - *f - * @param message String to be shown - */ - private fun showToaster(message: String?) { - Toaster.show(binding.root, message) - } - - /** - * It is called whenever any error occurs while executing a request - * - * @param message Error message that tells the user about the problem. - */ - fun showError(message: String?) { - if (!Network.isConnected(context)) { - sweetUIErrorHandler?.showSweetNoInternetUI( - binding.llMakeTransfer, - binding.layoutError.root, - ) - } else { - sweetUIErrorHandler?.showSweetErrorUI( - message, - binding.llMakeTransfer, - binding.layoutError.root, - ) - Toaster.show(binding.root, message) - } - } - - fun showProgress() { - binding.llMakeTransfer.visibility = View.GONE - showProgressBar() - } - - fun hideProgress() { - binding.llMakeTransfer.visibility = View.VISIBLE - hideProgressBar() - } - - /** - * Callback for `spPayFrom` and `spPayTo` - */ - - /** - * Disables `spPayTo` [Spinner] and sets `pvOne` to completed and make - * `pvTwo` active - */ - private fun payToSelected() { - with(binding) { - processOne.setCurrentCompleted() - processTwo.setCurrentActive() - btnPayTo.visibility = View.GONE - btnPayFrom.visibility = View.VISIBLE - payFromFieldWrapper.visibility = View.VISIBLE - payToFieldWrapper.isEnabled = false - } - } - - /** - * Checks validation of `spPayTo` [Spinner].

- * Disables `spPayFrom` [Spinner] and sets `pvTwo` to completed and make - * `pvThree` active - */ - private fun payFromSelected() { - if (payTo == payFrom) { - showToaster(getString(R.string.error_same_account_transfer)) - return - } - with(binding) { - processTwo.setCurrentCompleted() - processThree.setCurrentActive() - btnPayFrom.visibility = View.GONE - amountFieldWrapper.visibility = View.VISIBLE - btnAmount.visibility = View.VISIBLE - payFromFieldWrapper.isEnabled = false - } - } - - /** - * Checks validation of `etAmount` [EditText].

- * Disables `etAmount` and sets `pvThree` to completed and make - * `pvFour` active - */ - private fun amountSet() { - if (binding.amountField.text.toString() == "") { - showToaster(getString(R.string.enter_amount)) - return - } - if (binding.amountField.text.toString() == ".") { - showToaster(getString(R.string.invalid_amount)) - return - } - if (binding.amountField.text.toString().toDouble() == 0.0) { - showToaster(getString(R.string.amount_greater_than_zero)) - return - } - with(binding) { - processThree.setCurrentCompleted() - processFour.setCurrentActive() - btnAmount.visibility = View.GONE - tvEnterRemark.visibility = View.GONE - etRemark.visibility = View.VISIBLE - llReview.visibility = View.VISIBLE - amountFieldWrapper.isEnabled = false - } - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - super.onCreateOptionsMenu(menu, inflater) - inflater.inflate(R.menu.menu_transfer, menu) - Utils.setToolbarIconColor(activity, menu, R.color.white) - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - if (item.itemId == R.id.menu_refresh_transfer) { - val transaction = fragmentManager?.beginTransaction() - val currFragment = activity?.supportFragmentManager - ?.findFragmentById(R.id.container) - if (currFragment != null) { - transaction?.detach(currFragment) - transaction?.attach(currFragment) - } - transaction?.commit() - } - return super.onOptionsItemSelected(item) - } - - override fun onDestroyView() { - super.onDestroyView() - hideProgress() - hideMifosProgressDialog() - _binding = null - } - - companion object { - /** - * Provides an instance of [SavingsMakeTransferFragment], use `transferType` as - * `Constants.TRANSFER_PAY_TO` when we want to deposit and - * `Constants.TRANSFER_PAY_FROM` when we want to make a transfer - * - * @param accountId Saving account Id - * @param transferType Type of transfer i.e. `Constants.TRANSFER_PAY_TO` or - * `Constants.TRANSFER_PAY_FROM` - * @return Instance of [SavingsMakeTransferFragment] - */ - fun newInstance(accountId: Long?, transferType: String?): SavingsMakeTransferFragment { - val transferFragment = SavingsMakeTransferFragment() - val args = Bundle() - if (accountId != null) args.putLong(Constants.ACCOUNT_ID, accountId) - args.putString(Constants.TRANSFER_TYPE, transferType) - transferFragment.arguments = args - return transferFragment - } - - fun newInstance( - accountId: Long?, - outstandingBalance: Double?, - transferType: String?, - ): SavingsMakeTransferFragment { - val transferFragment = SavingsMakeTransferFragment() - val args = Bundle() - if (accountId != null) args.putLong(Constants.ACCOUNT_ID, accountId) - args.putString(Constants.TRANSFER_TYPE, transferType) - if (outstandingBalance != null) { - args.putDouble( - Constants.OUTSTANDING_BALANCE, - outstandingBalance, - ) - } - args.putBoolean(Constants.LOAN_REPAYMENT, true) - transferFragment.arguments = args - return transferFragment - } - } +// if (isLoanRepayment) { +// binding.amountField.setText(outStandingBalance.toString()) +// binding.amountFieldWrapper.isFocusable = false +// } +// } +// +// private fun updateDetails() { +//// when (transferType) { +//// Constants.TRANSFER_PAY_TO -> { +//// setToolbarTitle(getString(R.string.deposit)) +//// toAccountOption = +//// viewModel.searchAccount(accountOptionsTemplate?.toAccountOptions, accountId) +//// binding.payToFieldWrapper.isEnabled = false +//// binding.processOne.setCurrentCompleted() +//// } +//// +//// Constants.TRANSFER_PAY_FROM -> { +//// setToolbarTitle(getString(R.string.transfer)) +//// fromAccountOption = +//// viewModel.searchAccount(accountOptionsTemplate?.fromAccountOptions, accountId) +//// binding.payFromFieldWrapper.isEnabled = false +//// binding.payFromFieldWrapper.visibility = View.VISIBLE +//// binding.processTwo.setCurrentCompleted() +//// } +//// } +// } +// +// /** +// * Provides with `accountOptionsTemplate` fetched from server which is used to update +// * `listPayFrom` and `listPayTo` +// * +// * @param accountOptionsTemplate Template for account transfer +// */ +// private fun showSavingsAccountTemplate(accountOptionsTemplate: AccountOptionsTemplate?) { +// this.accountOptionsTemplate = accountOptionsTemplate +//// binding.payToField.setAdapter( +//// AccountsSpinnerAdapter( +//// requireContext(), +//// viewModel.getAccountNumbers( +//// accountOptionsTemplate?.toAccountOptions, +//// false, +//// context?.getString(R.string.account_type_loan) +//// ), +//// ), +//// ) +//// binding.payFromField.setAdapter( +//// AccountsSpinnerAdapter( +//// requireContext(), +//// viewModel.getAccountNumbers( +//// accountOptionsTemplate?.toAccountOptions, +//// true, +//// context?.getString(R.string.account_type_loan) +//// ), +//// ), +//// ) +// } +// +// /** +// * Shows a {@link Snackbar} with `message` +// *f +// * @param message String to be shown +// */ +// private fun showToaster(message: String?) { +// Toaster.show(binding.root, message) +// } +// +// /** +// * It is called whenever any error occurs while executing a request +// * +// * @param message Error message that tells the user about the problem. +// */ +// fun showError(message: String?) { +// if (!Network.isConnected(context)) { +// sweetUIErrorHandler?.showSweetNoInternetUI( +// binding.llMakeTransfer, +// binding.layoutError.root, +// ) +// } else { +// sweetUIErrorHandler?.showSweetErrorUI( +// message, +// binding.llMakeTransfer, +// binding.layoutError.root, +// ) +// Toaster.show(binding.root, message) +// } +// } +// +// fun showProgress() { +// binding.llMakeTransfer.visibility = View.GONE +// showProgressBar() +// } +// +// fun hideProgress() { +// binding.llMakeTransfer.visibility = View.VISIBLE +// hideProgressBar() +// } +// +// /** +// * Callback for `spPayFrom` and `spPayTo` +// */ +// +// /** +// * Disables `spPayTo` [Spinner] and sets `pvOne` to completed and make +// * `pvTwo` active +// */ +// private fun payToSelected() { +// with(binding) { +// processOne.setCurrentCompleted() +// processTwo.setCurrentActive() +// btnPayTo.visibility = View.GONE +// btnPayFrom.visibility = View.VISIBLE +// payFromFieldWrapper.visibility = View.VISIBLE +// payToFieldWrapper.isEnabled = false +// } +// } +// +// /** +// * Checks validation of `spPayTo` [Spinner].

+// * Disables `spPayFrom` [Spinner] and sets `pvTwo` to completed and make +// * `pvThree` active +// */ +// private fun payFromSelected() { +// if (payTo == payFrom) { +// showToaster(getString(R.string.error_same_account_transfer)) +// return +// } +// with(binding) { +// processTwo.setCurrentCompleted() +// processThree.setCurrentActive() +// btnPayFrom.visibility = View.GONE +// amountFieldWrapper.visibility = View.VISIBLE +// btnAmount.visibility = View.VISIBLE +// payFromFieldWrapper.isEnabled = false +// } +// } +// +// /** +// * Checks validation of `etAmount` [EditText].

+// * Disables `etAmount` and sets `pvThree` to completed and make +// * `pvFour` active +// */ +// private fun amountSet() { +// if (binding.amountField.text.toString() == "") { +// showToaster(getString(R.string.enter_amount)) +// return +// } +// if (binding.amountField.text.toString() == ".") { +// showToaster(getString(R.string.invalid_amount)) +// return +// } +// if (binding.amountField.text.toString().toDouble() == 0.0) { +// showToaster(getString(R.string.amount_greater_than_zero)) +// return +// } +// with(binding) { +// processThree.setCurrentCompleted() +// processFour.setCurrentActive() +// btnAmount.visibility = View.GONE +// tvEnterRemark.visibility = View.GONE +// etRemark.visibility = View.VISIBLE +// llReview.visibility = View.VISIBLE +// amountFieldWrapper.isEnabled = false +// } +// } +// +// override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { +// super.onCreateOptionsMenu(menu, inflater) +// inflater.inflate(R.menu.menu_transfer, menu) +// Utils.setToolbarIconColor(activity, menu, R.color.white) +// } +// +// override fun onOptionsItemSelected(item: MenuItem): Boolean { +// if (item.itemId == R.id.menu_refresh_transfer) { +// val transaction = fragmentManager?.beginTransaction() +// val currFragment = activity?.supportFragmentManager +// ?.findFragmentById(R.id.container) +// if (currFragment != null) { +// transaction?.detach(currFragment) +// transaction?.attach(currFragment) +// } +// transaction?.commit() +// } +// return super.onOptionsItemSelected(item) +// } +// +// override fun onDestroyView() { +// super.onDestroyView() +// hideProgress() +// hideMifosProgressDialog() +// _binding = null +// } +// +// companion object { +// /** +// * Provides an instance of [SavingsMakeTransferFragment], use `transferType` as +// * `Constants.TRANSFER_PAY_TO` when we want to deposit and +// * `Constants.TRANSFER_PAY_FROM` when we want to make a transfer +// * +// * @param accountId Saving account Id +// * @param transferType Type of transfer i.e. `Constants.TRANSFER_PAY_TO` or +// * `Constants.TRANSFER_PAY_FROM` +// * @return Instance of [SavingsMakeTransferFragment] +// */ +// fun newInstance(accountId: Long?, transferType: String?): SavingsMakeTransferFragment { +// val transferFragment = SavingsMakeTransferFragment() +// val args = Bundle() +// if (accountId != null) args.putLong(Constants.ACCOUNT_ID, accountId) +// args.putString(Constants.TRANSFER_TYPE, transferType) +// transferFragment.arguments = args +// return transferFragment +// } +// +// fun newInstance( +// accountId: Long?, +// outstandingBalance: Double?, +// transferType: String?, +// ): SavingsMakeTransferFragment { +// val transferFragment = SavingsMakeTransferFragment() +// val args = Bundle() +// if (accountId != null) args.putLong(Constants.ACCOUNT_ID, accountId) +// args.putString(Constants.TRANSFER_TYPE, transferType) +// if (outstandingBalance != null) { +// args.putDouble( +// Constants.OUTSTANDING_BALANCE, +// outstandingBalance, +// ) +// } +// args.putBoolean(Constants.LOAN_REPAYMENT, true) +// transferFragment.arguments = args +// return transferFragment +// } +// } } diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferScreen.kt b/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferScreen.kt index 67b1510f3..280eb6271 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferScreen.kt @@ -1,13 +1,8 @@ package org.mifos.mobile.ui.savings_make_transfer -import androidx.compose.foundation.gestures.Orientation -import androidx.compose.foundation.gestures.scrollable import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext @@ -21,9 +16,7 @@ import org.mifos.mobile.core.ui.component.MFScaffold import org.mifos.mobile.core.ui.component.MifosErrorComponent import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.ui.loan_account_withdraw.LoanAccountWithdrawUiState -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.Network +import org.mifos.mobile.core.common.Network @Composable fun SavingsMakeTransferScreen( @@ -55,7 +48,7 @@ fun SavingsMakeTransferScreen( val context = LocalContext.current MFScaffold( - topBarTitleResId = if(uiData.transferType == Constants.TRANSFER_PAY_TO) R.string.deposit + topBarTitleResId = if(uiData.transferType == org.mifos.mobile.core.common.Constants.TRANSFER_PAY_TO) R.string.deposit else R.string.transfer, navigateBack = navigateBack, scaffoldContent = { diff --git a/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferViewModel.kt index 040048ae7..919aee655 100644 --- a/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/savings_make_transfer/SavingsMakeTransferViewModel.kt @@ -1,6 +1,5 @@ package org.mifos.mobile.ui.savings_make_transfer -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -10,14 +9,14 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -import org.mifos.mobile.models.templates.account.AccountOption -import org.mifos.mobile.models.templates.account.AccountOptionsTemplate -import org.mifos.mobile.repositories.SavingsAccountRepository -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.Result -import org.mifos.mobile.utils.asResult +import org.mifos.mobile.core.data.repositories.SavingsAccountRepository +import org.mifos.mobile.core.model.entity.templates.account.AccountOption +import org.mifos.mobile.core.model.entity.templates.account.AccountOptionsTemplate +import org.mifos.mobile.core.network.asResult +import org.mifos.mobile.core.network.Result import javax.inject.Inject + @HiltViewModel class SavingsMakeTransferViewModel @Inject constructor(private val savingsAccountRepositoryImp: SavingsAccountRepository) : ViewModel() { diff --git a/app/src/main/java/org/mifos/mobile/ui/activities/SettingsActivity.kt b/app/src/main/java/org/mifos/mobile/ui/settings/SettingsActivity.kt similarity index 57% rename from app/src/main/java/org/mifos/mobile/ui/activities/SettingsActivity.kt rename to app/src/main/java/org/mifos/mobile/ui/settings/SettingsActivity.kt index e390c9dc1..af8f5166c 100644 --- a/app/src/main/java/org/mifos/mobile/ui/activities/SettingsActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/settings/SettingsActivity.kt @@ -1,32 +1,32 @@ -package org.mifos.mobile.ui.activities +package org.mifos.mobile.ui.settings import android.content.Intent import android.os.Bundle import androidx.core.app.ActivityCompat import org.mifos.mobile.R -import org.mifos.mobile.databinding.ActivitySettingsBinding +import org.mifos.mobile.databinding.ActivityUserProfileBinding +import org.mifos.mobile.ui.activities.HomeActivity import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.fragments.SettingsFragment -import org.mifos.mobile.utils.Constants class SettingsActivity : BaseActivity() { - private lateinit var binding: ActivitySettingsBinding - private var hasSettingsChanged = false + private lateinit var binding: ActivityUserProfileBinding + var hasSettingsChanged = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - binding = ActivitySettingsBinding.inflate(layoutInflater) + binding = ActivityUserProfileBinding.inflate(layoutInflater) setContentView(binding.root) - setToolbarTitle(getString(R.string.settings)) - showBackButton() - replaceFragment(SettingsFragment.newInstance(), false, R.id.container) - if (intent.hasExtra(Constants.HAS_SETTINGS_CHANGED)) { + + replaceFragment(SettingsComposeFragment.newInstance(), false, R.id.container) + if (intent.hasExtra(org.mifos.mobile.core.common.Constants.HAS_SETTINGS_CHANGED)) { hasSettingsChanged = intent.getBooleanExtra( - Constants.HAS_SETTINGS_CHANGED, + org.mifos.mobile.core.common.Constants.HAS_SETTINGS_CHANGED, false, ) } } + @Deprecated("Deprecated in Java") override fun onBackPressed() { if (supportFragmentManager.backStackEntryCount == 0) { super.onBackPressed() @@ -38,4 +38,4 @@ class SettingsActivity : BaseActivity() { supportFragmentManager.popBackStack() } } -} +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/settings/SettingsComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/settings/SettingsComposeFragment.kt new file mode 100644 index 000000000..95651306f --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/settings/SettingsComposeFragment.kt @@ -0,0 +1,89 @@ +package org.mifos.mobile.ui.settings + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.ui.activities.HomeActivity +import org.mifos.mobile.ui.activities.PassCodeActivity +import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.ui.login.LoginActivity +import org.mifos.mobile.ui.update_password.UpdatePasswordFragment + +@AndroidEntryPoint +class SettingsComposeFragment : BaseFragment() { + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + return mifosComposeView(requireContext()) { + MifosMobileTheme { + SettingsScreen( + navigateBack = { goBackToPreviousScreen() }, + navigateToLoginScreen = { navigateToLoginScreen() }, + changePassword = { changePassword() }, + changePasscode = { changePasscode(it) }, + languageChanged = { languageChanged() } + ) + } + } + } + + private fun navigateToLoginScreen() { + val loginIntent = Intent(activity, LoginActivity::class.java) + loginIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK + startActivity(loginIntent) + activity?.finish() + } + + private fun changePassword() { + (activity as BaseActivity?)?.replaceFragment( + UpdatePasswordFragment.newInstance(), + true, + R.id.container, + ) + } + + private fun changePasscode(passcode: String) { + val intent = Intent(activity, PassCodeActivity::class.java).apply { + putExtra(org.mifos.mobile.core.common.Constants.CURR_PASSWORD, passcode) + putExtra(org.mifos.mobile.core.common.Constants.IS_TO_UPDATE_PASS_CODE, true) + } + startActivity(intent) + } + + private fun languageChanged() { + val intent = Intent(activity, activity?.javaClass) + intent.putExtra(org.mifos.mobile.core.common.Constants.HAS_SETTINGS_CHANGED, true) + startActivity(intent) + activity?.finish() + } + + private fun goBackToPreviousScreen() { + val settingsActivity = activity as? SettingsActivity + val hasSettingsChanged = settingsActivity?.hasSettingsChanged + + if (hasSettingsChanged == true) { + activity?.finish() + startActivity(Intent(activity, HomeActivity::class.java)) + } else { + activity?.finish() + } + } + + companion object { + fun newInstance(): SettingsComposeFragment { + return SettingsComposeFragment() + } + } +} + + diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/SettingsFragment.kt b/app/src/main/java/org/mifos/mobile/ui/settings/SettingsFragment.kt similarity index 90% rename from app/src/main/java/org/mifos/mobile/ui/fragments/SettingsFragment.kt rename to app/src/main/java/org/mifos/mobile/ui/settings/SettingsFragment.kt index 1bc357b51..1d86d4ffc 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/SettingsFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/settings/SettingsFragment.kt @@ -1,4 +1,4 @@ -package org.mifos.mobile.ui.fragments +package org.mifos.mobile.ui.settings import android.content.Intent import android.content.SharedPreferences @@ -14,14 +14,13 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.mifos.mobile.passcode.utils.PasscodePreferencesHelper import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R -import org.mifos.mobile.api.local.PreferencesHelper import org.mifos.mobile.ui.activities.PassCodeActivity import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.update_password.UpdatePasswordFragment import org.mifos.mobile.utils.ConfigurationDialogFragmentCompat import org.mifos.mobile.utils.ConfigurationPreference -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.LanguageHelper +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.common.utils.LanguageHelper import java.util.Locale /** @@ -55,8 +54,8 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis val currPassCode = passCodePreferencesHelper.passCode passCodePreferencesHelper.savePassCode("") val intent = Intent(activity, PassCodeActivity::class.java).apply { - putExtra(Constants.CURR_PASSWORD, currPassCode) - putExtra(Constants.IS_TO_UPDATE_PASS_CODE, true) + putExtra(org.mifos.mobile.core.common.Constants.CURR_PASSWORD, currPassCode) + putExtra(org.mifos.mobile.core.common.Constants.IS_TO_UPDATE_PASS_CODE, true) } preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this) startActivity(intent) @@ -73,8 +72,8 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis val currPassCode = passCodePreferencesHelper.passCode passCodePreferencesHelper.savePassCode("") val intent = Intent(it, PassCodeActivity::class.java).apply { - putExtra(Constants.CURR_PASSWORD, currPassCode) - putExtra(Constants.IS_TO_UPDATE_PASS_CODE, true) + putExtra(org.mifos.mobile.core.common.Constants.CURR_PASSWORD, currPassCode) + putExtra(org.mifos.mobile.core.common.Constants.IS_TO_UPDATE_PASS_CODE, true) } preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this) startActivity(intent) @@ -116,7 +115,7 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis override fun onPreferenceTreeClick(preference: Preference): Boolean { when (preference.key) { - Constants.PASSWORD -> (activity as BaseActivity?)?.replaceFragment( + org.mifos.mobile.core.common.Constants.PASSWORD -> (activity as BaseActivity?)?.replaceFragment( UpdatePasswordFragment.newInstance(), true, R.id.container, @@ -153,7 +152,7 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis } } val intent = Intent(activity, activity?.javaClass) - intent.putExtra(Constants.HAS_SETTINGS_CHANGED, true) + intent.putExtra(org.mifos.mobile.core.common.Constants.HAS_SETTINGS_CHANGED, true) startActivity(intent) activity?.finish() } @@ -194,4 +193,4 @@ fun PreferencesHelper.applyTheme(applicationTheme: AppTheme) { else -> AppCompatDelegate.MODE_NIGHT_NO }, ) -} +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/settings/SettingsScreen.kt b/app/src/main/java/org/mifos/mobile/ui/settings/SettingsScreen.kt new file mode 100644 index 000000000..cc92ed3ba --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/settings/SettingsScreen.kt @@ -0,0 +1,273 @@ +package org.mifos.mobile.ui.settings + +import android.content.Context +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.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringArrayResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.MFScaffold +import org.mifos.mobile.core.ui.component.MifosRadioButtonDialog +import org.mifos.mobile.core.ui.component.MifosTopBarTitle +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.core.model.enums.AppTheme +import org.mifos.mobile.core.common.utils.LanguageHelper +import org.mifos.mobile.core.model.enums.MifosAppLanguage +import java.util.Locale + +@Composable +fun SettingsScreen( + viewModel: SettingsViewModel = hiltViewModel(), + navigateBack: () -> Unit, + navigateToLoginScreen: () -> Unit, + changePassword: () -> Unit, + changePasscode: (String) -> Unit, + languageChanged: () -> Unit +) { + + val baseURL = viewModel.baseUrl.collectAsStateWithLifecycle() + val tenant = viewModel.tenant.collectAsStateWithLifecycle() + val passcode = viewModel.passcode.collectAsStateWithLifecycle() + val theme = viewModel.theme.collectAsStateWithLifecycle() + val language = viewModel.language.collectAsStateWithLifecycle() + + val context = LocalContext.current + + SettingsScreen( + navigateBack = navigateBack, + selectedLanguage = language.value, + selectedTheme = theme.value, + baseURL = baseURL.value ?: "", + tenant = tenant.value ?: "", + updateLanguage = { + val isSystemLanguage = viewModel.updateLanguage(it) + updateLanguageLocale(context = context, language = language.value, isSystemLanguage = isSystemLanguage) + languageChanged() + }, + updateTheme = { viewModel.updateTheme(it) }, + changePassword = changePassword, + changePasscode = { changePasscode(passcode.value ?: "") }, + handleEndpointUpdate = { baseURL, tenant -> + if(viewModel.tryUpdatingEndpoint(selectedBaseUrl = baseURL, selectedTenant = tenant)) { + navigateToLoginScreen() + } + }, + ) +} + + +@Composable +fun SettingsScreen( + navigateBack: () -> Unit, + selectedLanguage: MifosAppLanguage, + selectedTheme: AppTheme, + baseURL: String, + tenant: String, + changePassword: () -> Unit, + changePasscode: () -> Unit, + handleEndpointUpdate: (baseURL: String, tenant: String) -> Unit, + updateTheme: (theme: AppTheme) -> Unit, + updateLanguage: (language: MifosAppLanguage) -> Unit +) { + + var showLanguageUpdateDialog by rememberSaveable { mutableStateOf(false) } + var showEndpointUpdateDialog by rememberSaveable { mutableStateOf(false) } + var showThemeUpdateDialog by rememberSaveable { mutableStateOf(false) } + + MFScaffold( + topBar = { + MifosTopBarTitle( + navigateBack = navigateBack, + topBarTitleResId = R.string.settings + ) + } + ) { + Column( + Modifier.padding(it) + ) { + SettingsCards( + settingsCardClicked = { item -> + when(item) { + SettingsCardItem.PASSWORD -> changePassword() + SettingsCardItem.PASSCODE -> changePasscode() + SettingsCardItem.LANGUAGE -> showLanguageUpdateDialog = true + SettingsCardItem.THEME -> showThemeUpdateDialog = true + SettingsCardItem.ENDPOINT -> showEndpointUpdateDialog = true + } + } + ) + } + } + + if(showLanguageUpdateDialog) { + MifosRadioButtonDialog( + titleResId = R.string.choose_language, + items = stringArrayResource(R.array.languages), + selectItem = { _, index -> updateLanguage(MifosAppLanguage.entries[index]) }, + onDismissRequest = { showLanguageUpdateDialog = false }, + selectedItem = selectedLanguage.displayName + ) + } + + if(showThemeUpdateDialog) { + MifosRadioButtonDialog( + titleResId = R.string.change_app_theme, + items = AppTheme.entries.map { it.themeName }.toTypedArray(), + selectItem = { _, index -> updateTheme(AppTheme.entries[index]) }, + onDismissRequest = { showThemeUpdateDialog = false }, + selectedItem = selectedTheme.themeName + ) + } + + if(showEndpointUpdateDialog) { + UpdateEndpointDialogScreen( + initialBaseURL = baseURL, + initialTenant = tenant, + onDismissRequest = { showEndpointUpdateDialog = false }, + handleEndpointUpdate = handleEndpointUpdate + ) + } +} + +@Composable +fun SettingsCards( + settingsCardClicked: (SettingsCardItem) -> Unit, +) { + LazyColumn { + items(SettingsCardItem.entries) { card -> + if (card.firstItemInSubclass) { + TitleCard(title = card.subclassOf) + } + + SettingsCardItem( + title = card.title, + details = card.details, + icon = card.icon, + onclick = { settingsCardClicked(card) } + ) + + if (card.showDividerInBottom) { + HorizontalDivider( + modifier = Modifier.fillMaxWidth().height(1.dp), + color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.4f) + ) + } + } + } +} + +@Composable +fun SettingsCardItem( + title: Int, + details: Int, + icon: Int, + onclick: () -> Unit +) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = Color.Transparent), + shape = RoundedCornerShape(0.dp), + onClick = { onclick.invoke() } + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + modifier = Modifier.padding(vertical = 16.dp), + ) { + Icon( + painter = painterResource(id = icon), + contentDescription = null, + modifier = Modifier.weight(0.2f) + ) + Column( + modifier = Modifier.weight(0.8f) + ) { + Text( + text = stringResource(id = title), + style = MaterialTheme.typography.bodyMedium + ) + Text( + modifier = Modifier.padding(end = 16.dp), + text = stringResource(id = details), + color = MaterialTheme.colorScheme.onBackground.copy(alpha = 0.8f), + style = MaterialTheme.typography.bodyMedium, + ) + } + } + } +} + +@Composable +fun TitleCard( + title: Int +) { + Spacer(modifier = Modifier.height(16.dp)) + Row(modifier = Modifier.fillMaxWidth()) { + Spacer(modifier = Modifier.weight(0.2f)) + Text( + text = stringResource(id = title), + modifier = Modifier.weight(0.8f), + fontSize = 14.sp + ) + } + Spacer(modifier = Modifier.height(12.dp)) +} + +fun updateLanguageLocale(context: Context, language: MifosAppLanguage, isSystemLanguage: Boolean) { + if (!isSystemLanguage) { + LanguageHelper.setLocale(context, language.code) + } else { + val systemLanguageCode = Locale.getDefault().language + if (MifosAppLanguage.entries.find { it.code == systemLanguageCode } == null) { + LanguageHelper.setLocale(context, MifosAppLanguage.ENGLISH.code) + } else { + LanguageHelper.setLocale(context, systemLanguageCode) + } + } +} + +@Composable +@Preview(showSystemUi = true, showBackground = true) +fun PreviewSettingsScreen() { + MifosMobileTheme { + SettingsScreen( + selectedLanguage = MifosAppLanguage.SYSTEM_LANGUAGE, + selectedTheme = AppTheme.SYSTEM, + baseURL = "", + tenant = "", + handleEndpointUpdate = { _, _ -> }, + updateLanguage = {}, + updateTheme = {}, + navigateBack = {}, + changePassword = {}, + changePasscode = {} + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/ui/settings/SettingsViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/settings/SettingsViewModel.kt new file mode 100644 index 000000000..fe03424ec --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/settings/SettingsViewModel.kt @@ -0,0 +1,122 @@ +package org.mifos.mobile.ui.settings + + +import android.os.Build +import androidx.appcompat.app.AppCompatDelegate +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.stateIn +import org.mifos.mobile.R +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.model.enums.AppTheme +import org.mifos.mobile.core.model.enums.MifosAppLanguage +import javax.inject.Inject + +@HiltViewModel +class SettingsViewModel @Inject constructor( + private val preferencesHelper: PreferencesHelper, +) : ViewModel() { + + val tenant: StateFlow = preferencesHelper + .getStringFlowForKey(PreferencesHelper.TENANT) + .stateIn(viewModelScope, SharingStarted.Eagerly, null) + + val baseUrl: StateFlow = preferencesHelper + .getStringFlowForKey(PreferencesHelper.BASE_URL) + .stateIn(viewModelScope, SharingStarted.Eagerly, null) + + val passcode: StateFlow = preferencesHelper + .getStringFlowForKey(PreferencesHelper.PASSCODE) + .stateIn(viewModelScope, SharingStarted.Eagerly, null) + + val theme: StateFlow = preferencesHelper + .getIntFlowForKey(PreferencesHelper.APPLICATION_THEME) + .flatMapLatest { + flow { emit(AppTheme.entries[preferencesHelper.appTheme]) } + }.stateIn(viewModelScope, SharingStarted.Eagerly, AppTheme.SYSTEM) + + val language: StateFlow = preferencesHelper + .getStringFlowForKey(PreferencesHelper.LANGUAGE_TYPE) + .flatMapLatest { + flow { emit(MifosAppLanguage.fromCode(preferencesHelper.language)) } + }.stateIn(viewModelScope, SharingStarted.Eagerly, MifosAppLanguage.SYSTEM_LANGUAGE) + + + fun tryUpdatingEndpoint(selectedBaseUrl: String, selectedTenant: String): Boolean { + if (!(baseUrl.equals(selectedBaseUrl) && tenant.equals(selectedTenant))) { + preferencesHelper.updateConfiguration(selectedBaseUrl, selectedTenant) + preferencesHelper.clear() + return true + } + return false + } + + fun updateLanguage(language: MifosAppLanguage): Boolean { + preferencesHelper.language = language.code + val isSystemLanguage = (language == MifosAppLanguage.SYSTEM_LANGUAGE) + preferencesHelper.isDefaultSystemLanguage = isSystemLanguage + return !isSystemLanguage + } + + fun updateTheme(theme: AppTheme) { + AppCompatDelegate.setDefaultNightMode( + when (theme) { + AppTheme.DARK -> AppCompatDelegate.MODE_NIGHT_YES + AppTheme.LIGHT -> AppCompatDelegate.MODE_NIGHT_NO + else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM + } + ) + preferencesHelper.appTheme = theme.ordinal + preferencesHelper.applySavedTheme() + } +} + +enum class SettingsCardItem( + val title: Int, + val details: Int, + val icon: Int, + val subclassOf: Int, + val firstItemInSubclass: Boolean = false, + val showDividerInBottom: Boolean = false +) { + PASSWORD( + title = R.string.change_password, + details = R.string.change_account_password, + icon = R.drawable.ic_lock_black_24dp, + firstItemInSubclass = true, + subclassOf = R.string.accounts + ), + PASSCODE( + title = R.string.change_passcode, + details = R.string.change_app_passcode, + icon = R.drawable.ic_passcode, + showDividerInBottom = true, + subclassOf = R.string.accounts + ), + LANGUAGE( + title = R.string.language, + details = R.string.choose_language, + icon = R.drawable.ic_translate, + firstItemInSubclass = true, + subclassOf = R.string.other + ), + THEME( + title = R.string.theme, + details = R.string.change_app_theme, + icon = R.drawable.ic_baseline_dark_mode_24, + subclassOf = R.string.other + ), + ENDPOINT( + title = R.string.pref_base_url_title, + details = R.string.pref_base_url_desc, + icon = R.drawable.ic_update, + subclassOf = R.string.other + ) +} + + diff --git a/app/src/main/java/org/mifos/mobile/ui/settings/UpdateEndpointDialog.kt b/app/src/main/java/org/mifos/mobile/ui/settings/UpdateEndpointDialog.kt new file mode 100644 index 000000000..82f82591d --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/settings/UpdateEndpointDialog.kt @@ -0,0 +1,100 @@ +package org.mifos.mobile.ui.settings + +import androidx.compose.foundation.layout.Arrangement +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.material3.Card +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.theme.MifosMobileTheme + +@Composable +fun UpdateEndpointDialogScreen( + initialBaseURL: String?, + initialTenant: String?, + onDismissRequest: () -> Unit, + handleEndpointUpdate: (baseURL: String, tenant: String) -> Unit +) { + var baseURL by rememberSaveable { mutableStateOf(initialBaseURL) } + var tenant by rememberSaveable { mutableStateOf(initialTenant) } + + Dialog( + onDismissRequest = { onDismissRequest.invoke() } + ) { + Card { + Column( + modifier = Modifier.fillMaxWidth().padding(20.dp), + ) { + Text(text = stringResource(id = R.string.pref_base_url_title)) + Spacer(modifier = Modifier.height(8.dp)) + + baseURL?.let { + OutlinedTextField( + value = it, + onValueChange = { baseURL = it }, + label = { Text(text = stringResource(id = R.string.enter_base_url)) } + ) + } + + Spacer(modifier = Modifier.height(8.dp)) + + tenant?.let { + OutlinedTextField( + value = it, + onValueChange = { tenant = it }, + label = { Text(text = stringResource(id = R.string.enter_tenant)) } + ) + } + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + TextButton( + onClick = { onDismissRequest.invoke() }) { + Text(text = stringResource(id = R.string.cancel)) + } + TextButton( + onClick = { + if(baseURL != null && tenant != null) { + handleEndpointUpdate.invoke(baseURL ?: "", tenant ?: "") + } + } + ) + { + Text(text = stringResource(id = R.string.dialog_action_ok)) + } + } + } + } + } +} + +@Composable +@Preview() +fun PreviewUpdateEndpointDialogScreen(modifier: Modifier = Modifier) { + MifosMobileTheme { + UpdateEndpointDialogScreen( + initialBaseURL = "URL", + initialTenant = "gsoc", + onDismissRequest = { }, + handleEndpointUpdate = { _, _ -> } + ) + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferComposeFragment.kt index dd97e01ab..94c80bb69 100644 --- a/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferComposeFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferComposeFragment.kt @@ -6,16 +6,14 @@ import android.view.View import android.view.ViewGroup import dagger.hilt.android.AndroidEntryPoint import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.payload.TransferPayload import org.mifos.mobile.core.ui.component.mifosComposeView -import org.mifos.mobile.models.payload.TransferPayload import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.beneficiary.presentation.BeneficiaryAddOptionsFragment -import org.mifos.mobile.ui.enums.TransferType -import org.mifos.mobile.ui.fragments.TransferProcessFragment 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.getTodayFormatted +import org.mifos.mobile.ui.transfer_process.TransferProcessComposeFragment +import org.mifos.mobile.core.common.utils.DateHelper +import org.mifos.mobile.core.common.utils.getTodayFormatted @AndroidEntryPoint class ThirdPartyTransferComposeFragment : BaseFragment() { @@ -53,7 +51,7 @@ class ThirdPartyTransferComposeFragment : BaseFragment() { } (activity as? BaseActivity)?.replaceFragment( - TransferProcessFragment.newInstance(transferPayload, TransferType.TPT,), + TransferProcessComposeFragment.newInstance(transferPayload, org.mifos.mobile.core.model.enums.TransferType.TPT,), true, R.id.container ) } diff --git a/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferContent.kt b/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferContent.kt index 5fd2fb0d3..5f59cec8a 100644 --- a/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferContent.kt +++ b/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferContent.kt @@ -33,6 +33,8 @@ import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import org.mifos.mobile.R +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary +import org.mifos.mobile.core.model.entity.templates.account.AccountOption import org.mifos.mobile.core.ui.component.MFStepProcess import org.mifos.mobile.core.ui.component.MifosDropDownDoubleTextField import org.mifos.mobile.core.ui.component.MifosOutlinedTextButton @@ -43,8 +45,6 @@ import org.mifos.mobile.core.ui.component.getStepState import org.mifos.mobile.core.ui.theme.DarkGray import org.mifos.mobile.core.ui.theme.MifosMobileTheme import org.mifos.mobile.core.ui.theme.Primary -import org.mifos.mobile.models.beneficiary.Beneficiary -import org.mifos.mobile.models.templates.account.AccountOption @Composable fun ThirdPartyTransferContent( diff --git a/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferFragment.kt b/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferFragment.kt index 4ac611c86..8a1aacb8a 100644 --- a/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferFragment.kt @@ -36,14 +36,15 @@ import org.mifos.mobile.ui.beneficiary.presentation.BeneficiaryAddOptionsFragmen import org.mifos.mobile.ui.enums.TransferType import org.mifos.mobile.ui.fragments.TransferProcessFragment 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.ui.transfer_process.TransferProcessComposeFragment +import org.mifos.mobile.core.common.Constants +import org.mifos.mobile.core.common.utils.DateHelper +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedArrayListFromParcelable +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.ThirdPartyTransferUiState import org.mifos.mobile.utils.Toaster -import org.mifos.mobile.utils.Utils +import org.mifos.mobile.core.common.utils.Utils import org.mifos.mobile.utils.getTodayFormatted /** @@ -207,7 +208,7 @@ class ThirdPartyTransferFragment : BaseFragment(), OnItemSelectedListener { } /** - * Checks validation of `etRemark` and then opens [TransferProcessFragment] for + * Checks validation of `etRemark` and then opens [TransferProcessComposeFragment] for * initiating the transfer */ private fun reviewTransfer() { @@ -244,7 +245,7 @@ class ThirdPartyTransferFragment : BaseFragment(), OnItemSelectedListener { transferPayload.fromAccountNumber = fromAccountOption?.accountNo transferPayload.toAccountNumber = beneficiaryAccountOption?.accountNo (activity as BaseActivity?)?.replaceFragment( - TransferProcessFragment.newInstance( + TransferProcessComposeFragment.newInstance( transferPayload, TransferType.TPT, ), diff --git a/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferScreen.kt b/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferScreen.kt index 0b299ddcf..56a89c845 100644 --- a/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferScreen.kt @@ -17,7 +17,7 @@ import org.mifos.mobile.core.ui.component.MFScaffold import org.mifos.mobile.core.ui.component.MifosErrorComponent import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay import org.mifos.mobile.core.ui.theme.MifosMobileTheme -import org.mifos.mobile.utils.Network +import org.mifos.mobile.core.common.Network @Composable fun ThirdPartyTransferScreen( diff --git a/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferViewModel.kt index fdb53c031..21ccbe6cd 100644 --- a/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/third_party_transfer/ThirdPartyTransferViewModel.kt @@ -4,25 +4,15 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.update -import kotlinx.coroutines.flow.zip import kotlinx.coroutines.launch -import org.mifos.mobile.R -import org.mifos.mobile.models.AccountOptionAndBeneficiary -import org.mifos.mobile.models.beneficiary.Beneficiary -import org.mifos.mobile.models.beneficiary.BeneficiaryDetail -import org.mifos.mobile.models.payload.AccountDetail -import org.mifos.mobile.models.templates.account.AccountOption -import org.mifos.mobile.models.templates.account.AccountOptionsTemplate -import org.mifos.mobile.repositories.BeneficiaryRepository -import org.mifos.mobile.repositories.ThirdPartyTransferRepository -import org.mifos.mobile.ui.guarantor.guarantor_add.GuarantorAddUiState -import org.mifos.mobile.utils.asResult +import org.mifos.mobile.core.data.repositories.BeneficiaryRepository +import org.mifos.mobile.core.data.repositories.ThirdPartyTransferRepository +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary +import org.mifos.mobile.core.model.entity.templates.account.AccountOption import javax.inject.Inject @HiltViewModel diff --git a/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessComposeFragment.kt b/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessComposeFragment.kt new file mode 100644 index 000000000..686ee9cd5 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessComposeFragment.kt @@ -0,0 +1,76 @@ +package org.mifos.mobile.ui.transfer_process + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.viewModels +import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.core.ui.component.mifosComposeView +import org.mifos.mobile.ui.activities.base.BaseActivity +import org.mifos.mobile.core.model.enums.TransferType +import org.mifos.mobile.ui.fragments.base.BaseFragment +import org.mifos.mobile.core.common.Constants +import org.mifos.mobile.core.model.entity.payload.TransferPayload +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedSerializable + +/** + * Created by dilpreet on 1/7/17. + */ +@AndroidEntryPoint +class TransferProcessComposeFragment : BaseFragment() { + + private val viewModel: TransferProcessViewModel by viewModels() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (activity != null) { + arguments?.getCheckedParcelable(TransferPayload::class.java, Constants.PAYLOAD)?.let { + viewModel.setContent(it) + } + (arguments?.getCheckedSerializable(TransferType::class.java, Constants.TRANSFER_TYPE) as TransferType).let { + viewModel.setTransferType(it) + } + } + } + + override fun onResume() { + super.onResume() + (activity as? BaseActivity)?.hideToolbar() + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + return mifosComposeView(requireContext()) { + TransferProcessScreen( + navigateBack = { activity?.supportFragmentManager?.popBackStack() }, + ) + } + } + + companion object { + /** + * Used for TPT Transfer and own Account Transfer.

+ * Use `type` as TransferType.TPT for TPT and TransferType.SELF for self Account Transfer + * + * @param payload Transfer Information + * @param type enum of [TransferType] + * @return Instance of [TransferProcessComposeFragment] + */ + fun newInstance( + payload: TransferPayload?, + type: TransferType? + ): TransferProcessComposeFragment { + val fragment = TransferProcessComposeFragment() + val args = Bundle() + args.putParcelable(Constants.PAYLOAD, payload) + args.putSerializable(Constants.TRANSFER_TYPE, type) + fragment.arguments = args + return fragment + } + } +} diff --git a/app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt b/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessFragment.kt similarity index 89% rename from app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt rename to app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessFragment.kt index 0d1b5fd81..02b381cb4 100644 --- a/app/src/main/java/org/mifos/mobile/ui/fragments/TransferProcessFragment.kt +++ b/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessFragment.kt @@ -1,15 +1,17 @@ -package org.mifos.mobile.ui.fragments +package org.mifos.mobile.ui.transfer_process +/* import android.graphics.drawable.Animatable -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.viewModels -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle +//import android.os.Bundle +//import android.view.LayoutInflater +//import android.view.View +//import android.view.ViewGroup +//import androidx.fragment.app.viewModels +//import androidx.lifecycle.Lifecycle +//import androidx.lifecycle.lifecycleScope +//import androidx.lifecycle.repeatOnLifecycle import dagger.hilt.android.AndroidEntryPoint +import org.mifos.mobile.databinding.FragmentTransferProcessBinding import kotlinx.coroutines.launch import org.mifos.mobile.R import org.mifos.mobile.databinding.FragmentTransferProcessBinding @@ -18,13 +20,13 @@ import org.mifos.mobile.models.templates.account.AccountOption import org.mifos.mobile.ui.activities.SavingsAccountContainerActivity import org.mifos.mobile.ui.enums.TransferType 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.core.common.Constants +import org.mifos.mobile.core.common.utils.CurrencyUtil +import org.mifos.mobile.core.common.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.core.common.Network +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedSerializable import org.mifos.mobile.utils.Toaster import org.mifos.mobile.utils.TransferUiState import org.mifos.mobile.utils.getTodayFormatted @@ -138,7 +140,7 @@ class TransferProcessFragment : BaseFragment() { DateHelper.FORMAT_dd_MMMM_yyyy, getTodayFormatted(), ), - binding.tvAmount.text.toString().replace(",", "").toDoubleOrNull(), + binding.tvAmount.text.toString().toDouble(), binding.tvRemark.text.toString(), "dd MMMM yyyy", "en", @@ -225,3 +227,5 @@ class TransferProcessFragment : BaseFragment() { } } } + + */ diff --git a/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessScreen.kt b/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessScreen.kt new file mode 100644 index 000000000..24cbad54b --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessScreen.kt @@ -0,0 +1,274 @@ +package org.mifos.mobile.ui.transfer_process + +import android.widget.Toast +import androidx.compose.foundation.BorderStroke +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.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.mifos.mobile.R +import org.mifos.mobile.core.ui.component.MFScaffold +import org.mifos.mobile.core.ui.component.MifosErrorComponent +import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.model.entity.payload.TransferPayload + + +@Composable +fun TransferProcessScreen( + viewModel: TransferProcessViewModel = hiltViewModel(), + navigateBack: () -> Unit +) { + val uiState by viewModel.transferUiState.collectAsStateWithLifecycle() + val payload by viewModel.transferPayload.collectAsStateWithLifecycle() + + TransferProcessScreen( + uiState = uiState, + transfer = { viewModel.makeTransfer() }, + payload = payload, + navigateBack = navigateBack, + ) +} + +@Composable +fun TransferProcessScreen( + uiState: TransferProcessUiState, + payload: TransferPayload?, + transfer: () -> Unit, + navigateBack: () -> Unit, +) { + val context = LocalContext.current + + MFScaffold( + topBarTitleResId = R.string.transfer, + navigateBack = navigateBack, + scaffoldContent = { paddingValues -> + Box( + modifier = Modifier + .padding(paddingValues) + .fillMaxSize() + ) { + + TransferProcessContent( + payload = payload, + transfer = transfer, + cancelClicked = navigateBack + ) + + when (uiState) { + is TransferProcessUiState.Loading -> { + MifosProgressIndicatorOverlay() + } + + is TransferProcessUiState.Success -> { + Toast.makeText( + context, + R.string.transferred_successfully, + Toast.LENGTH_SHORT + ).show() + navigateBack() + } + + is TransferProcessUiState.Error -> { + MifosErrorComponent(isNetworkConnected = Network.isConnected(context)) + } + + is TransferProcessUiState.Initial -> Unit + } + } + } + ) +} + +@Composable +fun TransferProcessContent( + payload: TransferPayload?, + transfer: () -> Unit, + cancelClicked: () -> Unit +) { + val scrollState = rememberScrollState() + + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(scrollState) + ) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.background + ), + border = BorderStroke(1.dp, Color.LightGray) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(14.dp) + ) { + Column( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = 12.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = stringResource(id = R.string.amount), + color = MaterialTheme.colorScheme.primary + ) + + Text(text = payload?.transferAmount.toString()) + } + + Text( + text = stringResource(id = R.string.transfer_from_savings), + fontWeight = FontWeight(500), + color = Color.Gray + ) + + Text( + text = stringResource(id = R.string.pay_to), + modifier = Modifier.padding(top = 8.dp), + color = MaterialTheme.colorScheme.primary + ) + + Text( + text = payload?.fromAccountNumber.toString(), + modifier = Modifier.padding(top = 4.dp, bottom = 2.dp) + ) + + HorizontalDivider() + + Text( + text = stringResource(id = R.string.pay_from), + modifier = Modifier.padding(top = 8.dp), + color = MaterialTheme.colorScheme.primary + ) + + Text( + text = payload?.fromAccountNumber.toString(), + modifier = Modifier.padding(top = 4.dp, bottom = 2.dp) + ) + + HorizontalDivider() + + Text( + text = stringResource(id = R.string.date), + modifier = Modifier.padding(top = 8.dp), + color = MaterialTheme.colorScheme.primary + ) + + Text( + text = payload?.transferDate.toString(), + modifier = Modifier.padding(top = 4.dp, bottom = 2.dp) + ) + + HorizontalDivider() + + Text( + text = stringResource(id = R.string.remark), + modifier = Modifier.padding(top = 8.dp), + color = MaterialTheme.colorScheme.primary + ) + + Text( + text = payload?.transferDescription.toString(), + modifier = Modifier.padding(top = 4.dp, bottom = 2.dp) + ) + + HorizontalDivider() + + Spacer(modifier = Modifier.height(24.dp)) + + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.End + ) { + Row( + horizontalArrangement = Arrangement.spacedBy(30.dp), + ) { + Button( + onClick = { cancelClicked() }, + colors = ButtonDefaults.buttonColors( + containerColor = Color.Transparent, + contentColor = MaterialTheme.colorScheme.primary + ) + ) { + Text(text = stringResource(id = R.string.cancel)) + } + Button( + onClick = { + transfer() + } + ) { + Text(text = stringResource(id = R.string.transfer)) + } + } + } + } + } + } +} + + +class UiStatesParameterProvider : PreviewParameterProvider { + override val values: Sequence + get() = sequenceOf( + TransferProcessUiState.Initial, + TransferProcessUiState.Loading, + TransferProcessUiState.Error(null), + TransferProcessUiState.Success + ) +} + +@Preview(showSystemUi = true) +@Composable +fun TransferProcessScreenPreview( + @PreviewParameter(UiStatesParameterProvider::class) transferUiState: TransferProcessUiState +) { + MifosMobileTheme { + TransferProcessScreen( + uiState = transferUiState, + payload = TransferPayload( + transferAmount = 100.0, + fromAccountNumber = "1234567890", + toAccountNumber = "0987654321", + transferDate = "2021-09-01", + transferDescription = "Transfer Description" + ), + transfer = {}, + navigateBack = {}, + ) + } +} + diff --git a/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessViewModel.kt new file mode 100644 index 000000000..6b648e8b4 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/ui/transfer_process/TransferProcessViewModel.kt @@ -0,0 +1,72 @@ +package org.mifos.mobile.ui.transfer_process + +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.core.data.repositories.TransferRepository +import org.mifos.mobile.core.model.entity.payload.TransferPayload +import org.mifos.mobile.core.model.enums.TransferType +import javax.inject.Inject + +@HiltViewModel +class TransferProcessViewModel @Inject constructor(private val transferRepositoryImp: TransferRepository) : + ViewModel() { + + private val _transferUiState = MutableStateFlow(TransferProcessUiState.Initial) + val transferUiState: StateFlow get() = _transferUiState + + private var _transferPayload: MutableStateFlow = MutableStateFlow(null) + val transferPayload: StateFlow get() = _transferPayload + + private var _transferType: MutableStateFlow = MutableStateFlow(null) + val transferType: StateFlow get() = _transferType + + fun makeTransfer() { + transferPayload.value?.let { payload -> + viewModelScope.launch { + _transferUiState.value = TransferProcessUiState.Loading + transferRepositoryImp.makeTransfer( + fromOfficeId = payload.fromOfficeId, + fromClientId = payload.fromClientId, + fromAccountType = payload.fromAccountType, + fromAccountId = payload.fromAccountId, + toOfficeId = payload.toOfficeId, + toClientId = payload.toClientId, + toAccountType = payload.toAccountType, + toAccountId = payload.toAccountId, + transferDate = payload.transferDate, + transferAmount = payload.transferAmount, + transferDescription = payload.transferDescription, + dateFormat = payload.dateFormat, + locale = payload.locale, + fromAccountNumber = payload.fromAccountNumber, + toAccountNumber = payload.toAccountNumber, + transferType = transferType.value + ).catch { e -> + _transferUiState.value = TransferProcessUiState.Error(e.message) + }.collect { + _transferUiState.value = TransferProcessUiState.Success + } + } + } + } + + fun setContent(payload: TransferPayload) { + _transferPayload.value = payload + } + + fun setTransferType(transferType: TransferType) { + _transferType.value = transferType + } +} + +sealed class TransferProcessUiState { + data object Initial : TransferProcessUiState() + data object Loading : TransferProcessUiState() + data object Success : TransferProcessUiState() + data class Error(val errorMessage: String?) : TransferProcessUiState() +} diff --git a/app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordScreen.kt b/app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordScreen.kt index d2564e9f7..274ed281f 100644 --- a/app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordScreen.kt +++ b/app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordScreen.kt @@ -30,8 +30,8 @@ import org.mifos.mobile.core.ui.component.MifosProgressIndicator import org.mifos.mobile.core.ui.component.MifosTopBar import org.mifos.mobile.core.ui.theme.MifosMobileTheme import org.mifos.mobile.ui.savings_account_withdraw.UiStatesParameterProvider -import org.mifos.mobile.utils.Network -import org.mifos.mobile.utils.RegistrationUiState +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.feature.registration.utils.RegistrationState @Composable @@ -49,7 +49,7 @@ fun UpdatePasswordScreen( @Composable fun UpdatePasswordScreen( - uiState: RegistrationUiState, + uiState: RegistrationState, navigateBack: () -> Unit ) { val context = LocalContext.current @@ -76,7 +76,7 @@ fun UpdatePasswordScreen( ) when (uiState) { - is RegistrationUiState.Loading -> { + is RegistrationState.Loading -> { MifosProgressIndicator( modifier = Modifier .fillMaxSize() @@ -84,7 +84,7 @@ fun UpdatePasswordScreen( ) } - is RegistrationUiState.Error -> { + is RegistrationState.Error -> { if (updatePasswordButtonClicked) { LaunchedEffect(snackbarHostState) { snackbarHostState.showSnackbar( @@ -96,9 +96,9 @@ fun UpdatePasswordScreen( } } - is RegistrationUiState.Initial -> Unit + is RegistrationState.Initial -> Unit - is RegistrationUiState.Success -> { + is RegistrationState.Success -> { LaunchedEffect(snackbarHostState) { snackbarHostState.showSnackbar( context.getString(R.string.password_changed_successfully), @@ -116,7 +116,7 @@ fun UpdatePasswordScreen( @Composable @Preview(showSystemUi = true, showBackground = true) fun UpdatePasswordScreenPreview( - @PreviewParameter(UiStatesParameterProvider::class) registrationUiState: RegistrationUiState + @PreviewParameter(UiStatesParameterProvider::class) registrationUiState: RegistrationState ) { MifosMobileTheme { UpdatePasswordScreen(navigateBack = {}) diff --git a/app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordViewModel.kt index 1b971e659..bc2b72209 100644 --- a/app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/update_password/UpdatePasswordViewModel.kt @@ -1,19 +1,16 @@ package org.mifos.mobile.ui.update_password -import android.content.Context -import androidx.compose.ui.res.stringResource import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel -import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch import org.mifos.mobile.R -import org.mifos.mobile.repositories.ClientRepository -import org.mifos.mobile.repositories.UserAuthRepository -import org.mifos.mobile.utils.RegistrationUiState +import org.mifos.mobile.core.data.repositories.ClientRepository +import org.mifos.mobile.core.data.repositories.UserAuthRepository +import org.mifos.mobile.feature.registration.utils.RegistrationState import javax.inject.Inject @HiltViewModel @@ -22,17 +19,17 @@ class UpdatePasswordViewModel @Inject constructor( private val clientRepositoryImp: ClientRepository, ) : ViewModel() { - private val _updatePasswordUiState = MutableStateFlow(RegistrationUiState.Initial) - val updatePasswordUiState: StateFlow get() = _updatePasswordUiState + private val _updatePasswordUiState = MutableStateFlow(RegistrationState.Initial) + val updatePasswordUiState: StateFlow get() = _updatePasswordUiState fun updateAccountPassword(newPassword: String, confirmPassword: String) { viewModelScope.launch { - _updatePasswordUiState.value = RegistrationUiState.Loading + _updatePasswordUiState.value = RegistrationState.Loading userAuthRepositoryImp.updateAccountPassword(newPassword, confirmPassword).catch { _updatePasswordUiState.value = - RegistrationUiState.Error(R.string.could_not_update_password_error) + RegistrationState.Error(R.string.could_not_update_password_error) }.collect { - _updatePasswordUiState.value = RegistrationUiState.Success + _updatePasswordUiState.value = RegistrationState.Success clientRepositoryImp.updateAuthenticationToken(newPassword) } } diff --git a/app/src/main/java/org/mifos/mobile/ui/user_profile/UserDetailViewModel.kt b/app/src/main/java/org/mifos/mobile/ui/user_profile/UserDetailViewModel.kt index 59a43340d..114a581dd 100644 --- a/app/src/main/java/org/mifos/mobile/ui/user_profile/UserDetailViewModel.kt +++ b/app/src/main/java/org/mifos/mobile/ui/user_profile/UserDetailViewModel.kt @@ -10,10 +10,10 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.launch import org.mifos.mobile.R -import org.mifos.mobile.api.local.PreferencesHelper -import org.mifos.mobile.models.notification.NotificationRegisterPayload -import org.mifos.mobile.repositories.HomeRepository -import org.mifos.mobile.repositories.UserDetailRepository +import org.mifos.mobile.core.data.repositories.HomeRepository +import org.mifos.mobile.core.data.repositories.UserDetailRepository +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.model.entity.notification.NotificationRegisterPayload import org.mifos.mobile.utils.ImageUtil import org.mifos.mobile.utils.UserDetailUiState import retrofit2.HttpException diff --git a/app/src/main/java/org/mifos/mobile/ui/user_profile/UserProfileActivity.kt b/app/src/main/java/org/mifos/mobile/ui/user_profile/UserProfileActivity.kt index 529f25508..1faad1061 100644 --- a/app/src/main/java/org/mifos/mobile/ui/user_profile/UserProfileActivity.kt +++ b/app/src/main/java/org/mifos/mobile/ui/user_profile/UserProfileActivity.kt @@ -4,7 +4,6 @@ import android.os.Bundle import org.mifos.mobile.R import org.mifos.mobile.databinding.ActivityUserProfileBinding import org.mifos.mobile.ui.activities.base.BaseActivity -import org.mifos.mobile.ui.user_profile.UserProfileFragment class UserProfileActivity : BaseActivity() { 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 5e40993af..4d5a971dd 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 @@ -15,18 +15,17 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.lifecycleScope 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.client.Client -import org.mifos.mobile.models.client.Group import org.mifos.mobile.ui.activities.base.BaseActivity import org.mifos.mobile.ui.fragments.base.BaseFragment import org.mifos.mobile.ui.getThemeAttributeColor import org.mifos.mobile.ui.update_password.UpdatePasswordFragment -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.core.common.utils.DateHelper +import org.mifos.mobile.core.common.Network +import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.model.entity.client.Client +import org.mifos.mobile.core.model.entity.client.Group +import org.mifos.mobile.core.ui.theme.MifosMobileTheme +import org.mifos.mobile.core.common.utils.ParcelableAndSerializableUtils.getCheckedParcelable import org.mifos.mobile.utils.TextDrawable import org.mifos.mobile.utils.Toaster import org.mifos.mobile.utils.UserDetailUiState @@ -110,7 +109,7 @@ class UserProfileFragment : BaseFragment() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - outState.putParcelable(Constants.USER_DETAILS, client) + outState.putParcelable(org.mifos.mobile.core.common.Constants.USER_DETAILS, client) } override fun onActivityCreated(savedInstanceState: Bundle?) { @@ -118,7 +117,7 @@ class UserProfileFragment : BaseFragment() { if (savedInstanceState != null) { client = savedInstanceState.getCheckedParcelable( Client::class.java, - Constants.USER_DETAILS + org.mifos.mobile.core.common.Constants.USER_DETAILS ) viewModel.setUserProfile(preferencesHelper?.userProfileImage) showUserDetails(client) diff --git a/app/src/main/java/org/mifos/mobile/ui/widgets/ChargeWidgetDataProvider.kt b/app/src/main/java/org/mifos/mobile/ui/widgets/ChargeWidgetDataProvider.kt index 195d3c663..ee67b59a4 100644 --- a/app/src/main/java/org/mifos/mobile/ui/widgets/ChargeWidgetDataProvider.kt +++ b/app/src/main/java/org/mifos/mobile/ui/widgets/ChargeWidgetDataProvider.kt @@ -6,8 +6,8 @@ import android.widget.RemoteViewsService.RemoteViewsFactory import android.widget.Toast import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.mobile.R -import org.mifos.mobile.models.Charge -import org.mifos.mobile.repositories.ClientChargeRepository +import org.mifos.mobile.core.data.repositories.ClientChargeRepository +import org.mifos.mobile.core.datastore.model.Charge import org.mifos.mobile.ui.client_charge.ClientChargeViewModel import java.util.concurrent.locks.ReentrantLock import javax.inject.Inject diff --git a/app/src/main/java/org/mifos/mobile/utils/AccountTypeItemIndicator.kt b/app/src/main/java/org/mifos/mobile/utils/AccountTypeItemIndicator.kt new file mode 100644 index 000000000..a457b1cf5 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/utils/AccountTypeItemIndicator.kt @@ -0,0 +1,57 @@ +package org.mifos.mobile.utils + +import androidx.compose.foundation.Canvas +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp + +@Composable +fun AccountTypeItemIndicator(color: Color) { + Box( + modifier = Modifier.background(Color.Transparent) + ) { + Canvas( + modifier = Modifier + .height(60.dp) + .width(5.dp) + ) { + val radius = 10.dp.toPx() + val path = androidx.compose.ui.graphics.Path().apply { + moveTo(0f, 0f) + lineTo(size.width - radius, 0f) + arcTo( + rect = androidx.compose.ui.geometry.Rect( + offset = Offset(size.width - radius, 0f), + size = Size(radius, radius) + ), + startAngleDegrees = -90f, + sweepAngleDegrees = 90f, + forceMoveTo = false + ) + lineTo(size.width, size.height - radius) + arcTo( + rect = androidx.compose.ui.geometry.Rect( + offset = Offset(size.width - radius, size.height - radius), + size = Size(radius, radius) + ), + startAngleDegrees = 0f, + sweepAngleDegrees = 90f, + forceMoveTo = false + ) + lineTo(0f, size.height) + close() + } + drawPath( + path = path, + color = color + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/utils/AccountsFilterUtil.kt b/app/src/main/java/org/mifos/mobile/utils/AccountsFilterUtil.kt index 230ff13c9..2a88c6617 100644 --- a/app/src/main/java/org/mifos/mobile/utils/AccountsFilterUtil.kt +++ b/app/src/main/java/org/mifos/mobile/utils/AccountsFilterUtil.kt @@ -1,5 +1,8 @@ package org.mifos.mobile.utils +import android.content.Context +import org.mifos.mobile.R + data class AccountsFilterUtil( var activeString: String? = null, var approvedString: String? = null, @@ -10,4 +13,20 @@ data class AccountsFilterUtil( var closedString : String? = null, var withdrawnString : String? = null, var inArrearsString : String? = null -) \ No newline at end of file +) { + companion object { + fun getFilterStrings(context: Context): AccountsFilterUtil { + return AccountsFilterUtil( + activeString = context.getString(R.string.active), + approvedString = context.getString(R.string.approved), + approvalPendingString = context.getString(R.string.approval_pending), + maturedString = context.getString(R.string.matured), + waitingForDisburseString = context.getString(R.string.waiting_for_disburse), + overpaidString = context.getString(R.string.overpaid), + closedString = context.getString(R.string.closed), + withdrawnString = context.getString(R.string.withdrawn), + inArrearsString = context.getString(R.string.in_arrears), + ) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/utils/AccountsUiState.kt b/app/src/main/java/org/mifos/mobile/utils/AccountsUiState.kt deleted file mode 100644 index 386b8c43a..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/AccountsUiState.kt +++ /dev/null @@ -1,13 +0,0 @@ -package org.mifos.mobile.utils - -import org.mifos.mobile.models.accounts.loan.LoanAccount -import org.mifos.mobile.models.accounts.savings.SavingAccount -import org.mifos.mobile.models.accounts.share.ShareAccount - -sealed class AccountsUiState { - object Error : AccountsUiState() - object Loading : AccountsUiState() - data class ShowSavingsAccounts(val savingAccounts: List?) : AccountsUiState() - data class ShowLoanAccounts(val loanAccounts: List?) : AccountsUiState() - data class ShowShareAccounts(val shareAccounts: List?) : AccountsUiState() -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/utils/BeneficiaryUiState.kt b/app/src/main/java/org/mifos/mobile/utils/BeneficiaryUiState.kt deleted file mode 100644 index fbf4439a5..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/BeneficiaryUiState.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.mifos.mobile.utils - -import org.mifos.mobile.models.beneficiary.Beneficiary -import org.mifos.mobile.models.templates.beneficiary.BeneficiaryTemplate - -sealed class BeneficiaryUiState { - object Initial : BeneficiaryUiState() - object Loading : BeneficiaryUiState() - object CreatedSuccessfully : BeneficiaryUiState() - object UpdatedSuccessfully : BeneficiaryUiState() - object DeletedSuccessfully : BeneficiaryUiState() - data class ShowError(val message: Int) : BeneficiaryUiState() - data class SetVisibility(val visibility: Int) : BeneficiaryUiState() - data class ShowBeneficiaryTemplate(val beneficiaryTemplate: BeneficiaryTemplate) : - BeneficiaryUiState() - - data class ShowBeneficiaryList(val beneficiaries: List) : BeneficiaryUiState() - -} diff --git a/app/src/main/java/org/mifos/mobile/utils/CheckSelfPermissionAndRequest.kt b/app/src/main/java/org/mifos/mobile/utils/CheckSelfPermissionAndRequest.kt index 4a1eece01..cad06575a 100644 --- a/app/src/main/java/org/mifos/mobile/utils/CheckSelfPermissionAndRequest.kt +++ b/app/src/main/java/org/mifos/mobile/utils/CheckSelfPermissionAndRequest.kt @@ -13,7 +13,7 @@ import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import org.mifos.mobile.R -import org.mifos.mobile.api.local.PreferencesHelper +import org.mifos.mobile.core.datastore.PreferencesHelper /** * Created by dilpreet on 14/7/17. @@ -131,7 +131,7 @@ object CheckSelfPermissionAndRequest { if (intent.resolveActivity(pm) != null) { activity.startActivityForResult( intent, - Constants.REQUEST_PERMISSION_SETTING, + org.mifos.mobile.core.common.Constants.REQUEST_PERMISSION_SETTING, ) } else { Toast.makeText( diff --git a/app/src/main/java/org/mifos/mobile/utils/ClientChargeUiState.kt b/app/src/main/java/org/mifos/mobile/utils/ClientChargeUiState.kt deleted file mode 100644 index c7fac97cb..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/ClientChargeUiState.kt +++ /dev/null @@ -1,4 +0,0 @@ -package org.mifos.mobile.utils - -import org.mifos.mobile.models.Charge - diff --git a/app/src/main/java/org/mifos/mobile/utils/ComparatorBasedOnId.kt b/app/src/main/java/org/mifos/mobile/utils/ComparatorBasedOnId.kt index c3ed374bd..4b84615d9 100644 --- a/app/src/main/java/org/mifos/mobile/utils/ComparatorBasedOnId.kt +++ b/app/src/main/java/org/mifos/mobile/utils/ComparatorBasedOnId.kt @@ -1,6 +1,6 @@ package org.mifos.mobile.utils -import org.mifos.mobile.models.accounts.Account +import org.mifos.mobile.core.model.entity.accounts.Account /** * Created by dilpreet on 14/6/17. diff --git a/app/src/main/java/org/mifos/mobile/utils/ConfigurationDialogFragmentCompat.kt b/app/src/main/java/org/mifos/mobile/utils/ConfigurationDialogFragmentCompat.kt index 0ad133e68..e1fca0215 100644 --- a/app/src/main/java/org/mifos/mobile/utils/ConfigurationDialogFragmentCompat.kt +++ b/app/src/main/java/org/mifos/mobile/utils/ConfigurationDialogFragmentCompat.kt @@ -14,7 +14,7 @@ import butterknife.BindView import butterknife.ButterKnife import com.google.android.material.textfield.TextInputLayout import org.mifos.mobile.R -import org.mifos.mobile.api.local.PreferencesHelper +import org.mifos.mobile.core.datastore.PreferencesHelper import org.mifos.mobile.ui.login.LoginActivity import java.net.MalformedURLException import java.net.URL diff --git a/app/src/main/java/org/mifos/mobile/utils/ConfigurationPreference.kt b/app/src/main/java/org/mifos/mobile/utils/ConfigurationPreference.kt index 7935db723..8430001bd 100644 --- a/app/src/main/java/org/mifos/mobile/utils/ConfigurationPreference.kt +++ b/app/src/main/java/org/mifos/mobile/utils/ConfigurationPreference.kt @@ -3,7 +3,7 @@ package org.mifos.mobile.utils import android.content.Context import android.util.AttributeSet import androidx.preference.DialogPreference -import org.mifos.mobile.api.local.PreferencesHelper +import org.mifos.mobile.core.datastore.PreferencesHelper /** * Created by dilpreet on 11/03/18. diff --git a/app/src/commonTest/java/org/mifos/mobile/FakeJsonName.kt b/app/src/main/java/org/mifos/mobile/utils/FakeJsonName.kt similarity index 98% rename from app/src/commonTest/java/org/mifos/mobile/FakeJsonName.kt rename to app/src/main/java/org/mifos/mobile/utils/FakeJsonName.kt index e0f95d567..2f12f6ab0 100644 --- a/app/src/commonTest/java/org/mifos/mobile/FakeJsonName.kt +++ b/app/src/main/java/org/mifos/mobile/utils/FakeJsonName.kt @@ -1,4 +1,4 @@ -package org.mifos.mobile +package org.mifos.mobile.utils /** * Created by dilpreet on 26/6/17. diff --git a/app/src/commonTest/java/org/mifos/mobile/FakeRemoteDataSource.kt b/app/src/main/java/org/mifos/mobile/utils/FakeRemoteDataSource.kt similarity index 77% rename from app/src/commonTest/java/org/mifos/mobile/FakeRemoteDataSource.kt rename to app/src/main/java/org/mifos/mobile/utils/FakeRemoteDataSource.kt index 7e93bb475..9082e0735 100644 --- a/app/src/commonTest/java/org/mifos/mobile/FakeRemoteDataSource.kt +++ b/app/src/main/java/org/mifos/mobile/utils/FakeRemoteDataSource.kt @@ -1,30 +1,23 @@ -package org.mifos.mobile +package org.mifos.mobile.utils import com.google.gson.reflect.TypeToken -import org.mifos.mobile.models.Charge -import org.mifos.mobile.models.Page -import org.mifos.mobile.models.Transaction -import org.mifos.mobile.models.UpdatePasswordPayload -import org.mifos.mobile.models.User -import org.mifos.mobile.models.accounts.loan.LoanAccount -import org.mifos.mobile.models.accounts.loan.LoanWithAssociations -import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations -import org.mifos.mobile.models.beneficiary.Beneficiary -import org.mifos.mobile.models.beneficiary.BeneficiaryPayload -import org.mifos.mobile.models.beneficiary.BeneficiaryUpdatePayload -import org.mifos.mobile.models.client.Client -import org.mifos.mobile.models.client.ClientAccounts -import org.mifos.mobile.models.guarantor.GuarantorPayload -import org.mifos.mobile.models.guarantor.GuarantorTemplatePayload -import org.mifos.mobile.models.payload.LoansPayload -import org.mifos.mobile.models.payload.LoginPayload -import org.mifos.mobile.models.payload.TransferPayload -import org.mifos.mobile.models.register.RegisterPayload -import org.mifos.mobile.models.register.UserVerify -import org.mifos.mobile.models.templates.account.AccountOptionsTemplate -import org.mifos.mobile.models.templates.beneficiary.BeneficiaryTemplate -import org.mifos.mobile.models.templates.loans.LoanTemplate -import org.mifos.mobile.models.templates.savings.SavingsAccountTemplate +import org.mifos.mobile.core.model.entity.* +import org.mifos.mobile.core.model.entity.accounts.loan.LoanAccount +import org.mifos.mobile.core.model.entity.accounts.loan.LoanWithAssociations +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.model.entity.client.* +import org.mifos.mobile.core.model.entity.beneficiary.* +import org.mifos.mobile.core.model.entity.guarantor.GuarantorPayload +import org.mifos.mobile.core.model.entity.guarantor.GuarantorTemplatePayload +import org.mifos.mobile.core.model.entity.payload.LoansPayload +import org.mifos.mobile.core.model.entity.payload.LoginPayload +import org.mifos.mobile.core.model.entity.payload.TransferPayload +import org.mifos.mobile.core.model.entity.register.RegisterPayload +import org.mifos.mobile.core.model.entity.register.UserVerify +import org.mifos.mobile.core.model.entity.templates.account.AccountOptionsTemplate +import org.mifos.mobile.core.model.entity.templates.beneficiary.BeneficiaryTemplate +import org.mifos.mobile.core.model.entity.templates.loans.LoanTemplate +import org.mifos.mobile.core.model.entity.templates.savings.SavingsAccountTemplate /** * Created by dilpreet on 26/6/17. @@ -171,22 +164,22 @@ object FakeRemoteDataSource { LoginPayload::class.java, FakeJsonName.LOGIN, ) - val charge: Page? - get() = mTestDataFactory.getListTypePojo?>( + val charge: Page? + get() = mTestDataFactory.getListTypePojo?>( object : - TypeToken?>() {}, + TypeToken?>() {}, FakeJsonName.CHARGE, ) - val savingsCharge: List - get() = mTestDataFactory.getListTypePojo>( + val savingsCharge: List + get() = mTestDataFactory.getListTypePojo>( object : - TypeToken?>() {}, + TypeToken?>() {}, FakeJsonName.SAVING_CHARGE, ) - val loanCharge: List - get() = mTestDataFactory.getListTypePojo>( + val loanCharge: List + get() = mTestDataFactory.getListTypePojo>( object : - TypeToken?>() {}, + TypeToken?>() {}, FakeJsonName.LOAN_CHARGE, ) val userVerify: UserVerify diff --git a/app/src/main/java/org/mifos/mobile/utils/GuarantorUiState.kt b/app/src/main/java/org/mifos/mobile/utils/GuarantorUiState.kt index 31e31a75d..b95f9aaa1 100644 --- a/app/src/main/java/org/mifos/mobile/utils/GuarantorUiState.kt +++ b/app/src/main/java/org/mifos/mobile/utils/GuarantorUiState.kt @@ -1,8 +1,8 @@ package org.mifos.mobile.utils -import org.mifos.mobile.models.guarantor.GuarantorApplicationPayload -import org.mifos.mobile.models.guarantor.GuarantorPayload -import org.mifos.mobile.models.guarantor.GuarantorTemplatePayload +import org.mifos.mobile.core.model.entity.guarantor.GuarantorApplicationPayload +import org.mifos.mobile.core.model.entity.guarantor.GuarantorPayload +import org.mifos.mobile.core.model.entity.guarantor.GuarantorTemplatePayload sealed class GuarantorUiState { object Loading : GuarantorUiState() diff --git a/app/src/main/java/org/mifos/mobile/utils/HelpUiState.kt b/app/src/main/java/org/mifos/mobile/utils/HelpUiState.kt index c89e4dd93..c2c2852b9 100644 --- a/app/src/main/java/org/mifos/mobile/utils/HelpUiState.kt +++ b/app/src/main/java/org/mifos/mobile/utils/HelpUiState.kt @@ -1,6 +1,6 @@ package org.mifos.mobile.utils -import org.mifos.mobile.models.FAQ +import org.mifos.mobile.core.model.entity.FAQ sealed class HelpUiState { object Initial : HelpUiState() diff --git a/app/src/main/java/org/mifos/mobile/utils/LoanUiState.kt b/app/src/main/java/org/mifos/mobile/utils/LoanUiState.kt deleted file mode 100644 index 76a672c71..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/LoanUiState.kt +++ /dev/null @@ -1,16 +0,0 @@ -package org.mifos.mobile.utils - -import org.mifos.mobile.models.accounts.loan.LoanWithAssociations -import org.mifos.mobile.models.templates.loans.LoanTemplate - -sealed class LoanUiState { - object Loading : LoanUiState() - object WithdrawSuccess : LoanUiState() - data class ShowError(val message: Int) : LoanUiState() - data class ShowLoan(val loanWithAssociations: LoanWithAssociations) : LoanUiState() - data class ShowEmpty(val loanWithAssociations: LoanWithAssociations) : LoanUiState() - data class ShowLoanTemplate(val template: LoanTemplate) : LoanUiState() - data class ShowUpdateLoanTemplate(val template: LoanTemplate) : LoanUiState() - data class ShowLoanTemplateByProduct(val template: LoanTemplate) : LoanUiState() - data class ShowUpdateLoanTemplateByProduct(val template: LoanTemplate) : LoanUiState() -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/utils/MFErrorParser.kt b/app/src/main/java/org/mifos/mobile/utils/MFErrorParser.kt index 4ca048a9f..01a2178e2 100644 --- a/app/src/main/java/org/mifos/mobile/utils/MFErrorParser.kt +++ b/app/src/main/java/org/mifos/mobile/utils/MFErrorParser.kt @@ -2,7 +2,7 @@ package org.mifos.mobile.utils import com.google.gson.Gson import io.reactivex.plugins.RxJavaPlugins -import org.mifos.mobile.models.mifoserror.MifosError +import org.mifos.mobile.core.model.entity.mifoserror.MifosError import retrofit2.HttpException object MFErrorParser { diff --git a/app/src/main/java/org/mifos/mobile/utils/NotificationUiState.kt b/app/src/main/java/org/mifos/mobile/utils/NotificationUiState.kt deleted file mode 100644 index 872b73fef..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/NotificationUiState.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.mifos.mobile.utils - -import org.mifos.mobile.models.notification.MifosNotification diff --git a/app/src/main/java/org/mifos/mobile/utils/QrCodeAnalyzer.kt b/app/src/main/java/org/mifos/mobile/utils/QrCodeAnalyzer.kt new file mode 100644 index 000000000..274d430b5 --- /dev/null +++ b/app/src/main/java/org/mifos/mobile/utils/QrCodeAnalyzer.kt @@ -0,0 +1,63 @@ +package org.mifos.mobile.utils + +import android.graphics.ImageFormat +import androidx.camera.core.ImageAnalysis +import androidx.camera.core.ImageProxy +import com.google.zxing.BarcodeFormat +import com.google.zxing.BinaryBitmap +import com.google.zxing.DecodeHintType +import com.google.zxing.MultiFormatReader +import com.google.zxing.PlanarYUVLuminanceSource +import com.google.zxing.common.HybridBinarizer +import java.nio.ByteBuffer + +class QrCodeAnalyzer( + private val onBarcodeScanned: (String) -> Unit +) : ImageAnalysis.Analyzer { + + private val supportedImageFormats = listOf( + ImageFormat.YUV_420_888, + ImageFormat.YUV_422_888, + ImageFormat.YUV_444_888, + ) + + override fun analyze(image: ImageProxy) { + if (image.format in supportedImageFormats) { + val bytes = image.planes.first().buffer.toByteArray() + val source = PlanarYUVLuminanceSource( + bytes, + image.width, + image.height, + 0, + 0, + image.width, + image.height, + false + ) + val binaryBmp = BinaryBitmap(HybridBinarizer(source)) + try { + val result = MultiFormatReader().apply { + setHints( + mapOf( + DecodeHintType.POSSIBLE_FORMATS to arrayListOf( + BarcodeFormat.QR_CODE + ) + ) + ) + }.decode(binaryBmp) + onBarcodeScanned(result.text) + } catch (e: Exception) { + e.printStackTrace() + } finally { + image.close() + } + } + } + + private fun ByteBuffer.toByteArray(): ByteArray { + rewind() + return ByteArray(remaining()).also { + get(it) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/utils/QrCodeGenerator.kt b/app/src/main/java/org/mifos/mobile/utils/QrCodeGenerator.kt index 696f762a2..1bd4c3c12 100644 --- a/app/src/main/java/org/mifos/mobile/utils/QrCodeGenerator.kt +++ b/app/src/main/java/org/mifos/mobile/utils/QrCodeGenerator.kt @@ -7,8 +7,9 @@ import com.google.zxing.BarcodeFormat import com.google.zxing.MultiFormatWriter import com.google.zxing.WriterException import com.google.zxing.common.BitMatrix -import org.mifos.mobile.models.beneficiary.Beneficiary -import org.mifos.mobile.ui.enums.AccountType +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary +import org.mifos.mobile.core.model.enums.AccountType + /** * Created by dilpreet on 6/7/17. @@ -60,7 +61,7 @@ object QrCodeGenerator { } else if (accountType === AccountType.LOAN) { accountId = 1 } - val type = org.mifos.mobile.models.templates.account.AccountType() + val type = org.mifos.mobile.core.model.entity.templates.account.AccountType() type.id = accountId val payload = Beneficiary() payload.accountNumber = accountNumber diff --git a/app/src/main/java/org/mifos/mobile/utils/QrCodeUiState.kt b/app/src/main/java/org/mifos/mobile/utils/QrCodeUiState.kt deleted file mode 100644 index 3740a9f44..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/QrCodeUiState.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.mifos.mobile.utils - -import com.google.zxing.Result - -sealed class QrCodeUiState { - object Initial : QrCodeUiState() - object Loading : QrCodeUiState() - data class ShowError(val message: Int) : QrCodeUiState() - data class HandleDecodedResult(val result: Result?) : QrCodeUiState() -} diff --git a/app/src/main/java/org/mifos/mobile/utils/RecentTransactionUiState.kt b/app/src/main/java/org/mifos/mobile/utils/RecentTransactionUiState.kt deleted file mode 100644 index ef256f710..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/RecentTransactionUiState.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.mifos.mobile.utils - -import org.mifos.mobile.models.Transaction diff --git a/app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt b/app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt deleted file mode 100644 index 85792c68d..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/RegistrationUiState.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.mifos.mobile.utils - -sealed class RegistrationUiState { - data class Error(val exception: Int) : RegistrationUiState() - object Success : RegistrationUiState() - object Loading : RegistrationUiState() - object Initial: RegistrationUiState() -} diff --git a/app/src/commonTest/java/org/mifos/mobile/RetrofitUtils.kt b/app/src/main/java/org/mifos/mobile/utils/RetrofitUtils.kt similarity index 96% rename from app/src/commonTest/java/org/mifos/mobile/RetrofitUtils.kt rename to app/src/main/java/org/mifos/mobile/utils/RetrofitUtils.kt index 9e8ed89e3..420ac7296 100644 --- a/app/src/commonTest/java/org/mifos/mobile/RetrofitUtils.kt +++ b/app/src/main/java/org/mifos/mobile/utils/RetrofitUtils.kt @@ -1,4 +1,4 @@ -package org.mifos.mobile +package org.mifos.mobile.utils import okhttp3.MediaType import okhttp3.Protocol diff --git a/app/src/main/java/org/mifos/mobile/utils/RxEvent.kt b/app/src/main/java/org/mifos/mobile/utils/RxEvent.kt index 7814aabd9..590edcaa9 100644 --- a/app/src/main/java/org/mifos/mobile/utils/RxEvent.kt +++ b/app/src/main/java/org/mifos/mobile/utils/RxEvent.kt @@ -1,6 +1,6 @@ package org.mifos.mobile.utils -import org.mifos.mobile.models.guarantor.GuarantorApplicationPayload +import org.mifos.mobile.core.model.entity.guarantor.GuarantorApplicationPayload /* * Created by saksham on 29/July/2018 diff --git a/app/src/main/java/org/mifos/mobile/utils/SavingsAccountUiState.kt b/app/src/main/java/org/mifos/mobile/utils/SavingsAccountUiState.kt index 7ba8c719a..615543926 100644 --- a/app/src/main/java/org/mifos/mobile/utils/SavingsAccountUiState.kt +++ b/app/src/main/java/org/mifos/mobile/utils/SavingsAccountUiState.kt @@ -1,9 +1,9 @@ package org.mifos.mobile.utils -import org.mifos.mobile.models.accounts.savings.SavingsWithAssociations -import org.mifos.mobile.models.accounts.savings.Transactions -import org.mifos.mobile.models.templates.account.AccountOptionsTemplate -import org.mifos.mobile.models.templates.savings.SavingsAccountTemplate +import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations +import org.mifos.mobile.core.model.entity.accounts.savings.Transactions +import org.mifos.mobile.core.model.entity.templates.account.AccountOptionsTemplate +import org.mifos.mobile.core.model.entity.templates.savings.SavingsAccountTemplate sealed class SavingsAccountUiState { object Initial : SavingsAccountUiState() diff --git a/app/src/main/java/org/mifos/mobile/utils/StatusUtils.kt b/app/src/main/java/org/mifos/mobile/utils/StatusUtils.kt index 8984e4163..355ea14e8 100644 --- a/app/src/main/java/org/mifos/mobile/utils/StatusUtils.kt +++ b/app/src/main/java/org/mifos/mobile/utils/StatusUtils.kt @@ -3,7 +3,7 @@ package org.mifos.mobile.utils import android.content.Context import androidx.core.content.ContextCompat import org.mifos.mobile.R -import org.mifos.mobile.models.CheckboxStatus +import org.mifos.mobile.core.model.entity.CheckboxStatus import org.mifos.mobile.ui.getThemeAttributeColor /** diff --git a/app/src/commonTest/java/org/mifos/mobile/TestDataFactory.kt b/app/src/main/java/org/mifos/mobile/utils/TestDataFactory.kt similarity index 98% rename from app/src/commonTest/java/org/mifos/mobile/TestDataFactory.kt rename to app/src/main/java/org/mifos/mobile/utils/TestDataFactory.kt index 688dcfd81..83c65278a 100644 --- a/app/src/commonTest/java/org/mifos/mobile/TestDataFactory.kt +++ b/app/src/main/java/org/mifos/mobile/utils/TestDataFactory.kt @@ -1,4 +1,4 @@ -package org.mifos.mobile +package org.mifos.mobile.utils import com.google.gson.Gson import com.google.gson.reflect.TypeToken diff --git a/app/src/main/java/org/mifos/mobile/utils/ThirdPartyTransferUiState.kt b/app/src/main/java/org/mifos/mobile/utils/ThirdPartyTransferUiState.kt index addfe310e..d56a1d2ed 100644 --- a/app/src/main/java/org/mifos/mobile/utils/ThirdPartyTransferUiState.kt +++ b/app/src/main/java/org/mifos/mobile/utils/ThirdPartyTransferUiState.kt @@ -1,7 +1,7 @@ package org.mifos.mobile.utils -import org.mifos.mobile.models.beneficiary.Beneficiary -import org.mifos.mobile.models.templates.account.AccountOptionsTemplate +import org.mifos.mobile.core.model.entity.beneficiary.Beneficiary +import org.mifos.mobile.core.model.entity.templates.account.AccountOptionsTemplate sealed class ThirdPartyTransferUiState { object Initial : ThirdPartyTransferUiState() diff --git a/app/src/main/java/org/mifos/mobile/utils/TransferUiState.kt b/app/src/main/java/org/mifos/mobile/utils/TransferUiState.kt deleted file mode 100644 index cc49abe2d..000000000 --- a/app/src/main/java/org/mifos/mobile/utils/TransferUiState.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.mifos.mobile.utils - -sealed class TransferUiState { - object Initial : TransferUiState() - object Loading : TransferUiState() - object TransferSuccess : TransferUiState() - data class Error(val errorMessage: Throwable) : TransferUiState() -} - diff --git a/app/src/main/java/org/mifos/mobile/utils/UserDetailUiState.kt b/app/src/main/java/org/mifos/mobile/utils/UserDetailUiState.kt index b884f9bfa..5375a6ca2 100644 --- a/app/src/main/java/org/mifos/mobile/utils/UserDetailUiState.kt +++ b/app/src/main/java/org/mifos/mobile/utils/UserDetailUiState.kt @@ -1,7 +1,7 @@ package org.mifos.mobile.utils import android.graphics.Bitmap -import org.mifos.mobile.models.client.Client +import org.mifos.mobile.core.model.entity.client.Client sealed class UserDetailUiState { diff --git a/app/src/main/java/org/mifos/mobile/utils/fcm/MifosFirebaseMessagingService.kt b/app/src/main/java/org/mifos/mobile/utils/fcm/MifosFirebaseMessagingService.kt index 9b46dbe38..a930eb218 100644 --- a/app/src/main/java/org/mifos/mobile/utils/fcm/MifosFirebaseMessagingService.kt +++ b/app/src/main/java/org/mifos/mobile/utils/fcm/MifosFirebaseMessagingService.kt @@ -26,9 +26,8 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.RemoteMessage import org.mifos.mobile.R -import org.mifos.mobile.models.notification.MifosNotification +import org.mifos.mobile.core.datastore.model.MifosNotification import org.mifos.mobile.ui.activities.HomeActivity -import org.mifos.mobile.utils.Constants class MifosFirebaseMessagingService : FirebaseMessagingService() { // [START receive_message] @@ -42,7 +41,7 @@ class MifosFirebaseMessagingService : FirebaseMessagingService() { // normal downstream message. } sendNotification(message) - val registrationComplete = Intent(Constants.NOTIFY_HOME_FRAGMENT) + val registrationComplete = Intent(org.mifos.mobile.core.common.Constants.NOTIFY_HOME_FRAGMENT) LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete) } // [END receive_message] @@ -71,11 +70,10 @@ class MifosFirebaseMessagingService : FirebaseMessagingService() { .setContentIntent(pendingIntent) val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager - val notification = MifosNotification() + val notification = org.mifos.mobile.core.datastore.model.MifosNotification() notification.msg = message notification.timeStamp = System.currentTimeMillis() notification.setRead(false) - notification.save() notificationManager.notify(0, notificationBuilder.build()) } diff --git a/app/src/main/java/org/mifos/mobile/utils/fcm/RegistrationIntentService.kt b/app/src/main/java/org/mifos/mobile/utils/fcm/RegistrationIntentService.kt index 31baa5157..2b8a689b2 100644 --- a/app/src/main/java/org/mifos/mobile/utils/fcm/RegistrationIntentService.kt +++ b/app/src/main/java/org/mifos/mobile/utils/fcm/RegistrationIntentService.kt @@ -21,7 +21,6 @@ import android.util.Log import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.google.android.gms.tasks.OnCompleteListener import com.google.firebase.messaging.FirebaseMessaging -import org.mifos.mobile.utils.Constants class RegistrationIntentService : IntentService(TAG) { override fun onHandleIntent(intent: Intent?) { @@ -41,8 +40,8 @@ class RegistrationIntentService : IntentService(TAG) { } private fun sendRegistrationToServer(token: String?) { - val registrationComplete = Intent(Constants.REGISTER_ON_SERVER) - registrationComplete.putExtra(Constants.TOKEN, token) + val registrationComplete = Intent(org.mifos.mobile.core.common.Constants.REGISTER_ON_SERVER) + registrationComplete.putExtra(org.mifos.mobile.core.common.Constants.TOKEN, token) LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete) } diff --git a/app/src/main/java/org/mifos/mobile/viewModels/BeneficiaryApplicationViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/BeneficiaryApplicationViewModel.kt deleted file mode 100644 index f20d22aa6..000000000 --- a/app/src/main/java/org/mifos/mobile/viewModels/BeneficiaryApplicationViewModel.kt +++ /dev/null @@ -1,66 +0,0 @@ -package org.mifos.mobile.viewModels - -import android.util.Log -import android.view.View -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.flow.onCompletion -import kotlinx.coroutines.launch -import org.mifos.mobile.R -import org.mifos.mobile.models.beneficiary.BeneficiaryPayload -import org.mifos.mobile.models.beneficiary.BeneficiaryUpdatePayload -import org.mifos.mobile.repositories.BeneficiaryRepository -import org.mifos.mobile.utils.BeneficiaryUiState -import javax.inject.Inject - -@HiltViewModel -class BeneficiaryApplicationViewModel @Inject constructor(private val beneficiaryRepositoryImp: BeneficiaryRepository) : - ViewModel() { - - private val _beneficiaryUiState = - MutableStateFlow(BeneficiaryUiState.Initial) - val beneficiaryUiState: StateFlow get() = _beneficiaryUiState - - fun loadBeneficiaryTemplate() { - viewModelScope.launch { - _beneficiaryUiState.value = BeneficiaryUiState.Loading - beneficiaryRepositoryImp.beneficiaryTemplate().catch { - _beneficiaryUiState.value = - BeneficiaryUiState.ShowError(R.string.error_fetching_beneficiary_template) - }.onCompletion { - _beneficiaryUiState.value = BeneficiaryUiState.SetVisibility(View.VISIBLE) - }.collect { - _beneficiaryUiState.value = BeneficiaryUiState.ShowBeneficiaryTemplate(it) - } - } - } - - fun createBeneficiary(payload: BeneficiaryPayload?) { - viewModelScope.launch { - _beneficiaryUiState.value = BeneficiaryUiState.Loading - beneficiaryRepositoryImp.createBeneficiary(payload).catch { - _beneficiaryUiState.value = - BeneficiaryUiState.ShowError(R.string.error_creating_beneficiary) - }.collect { - _beneficiaryUiState.value = BeneficiaryUiState.CreatedSuccessfully - } - } - } - - fun updateBeneficiary(beneficiaryId: Long?, payload: BeneficiaryUpdatePayload?) { - viewModelScope.launch { - _beneficiaryUiState.value = BeneficiaryUiState.Loading - beneficiaryRepositoryImp.updateBeneficiary(beneficiaryId, payload).catch { - _beneficiaryUiState.value = - BeneficiaryUiState.ShowError(R.string.error_updating_beneficiary) - }.collect { - _beneficiaryUiState.value = BeneficiaryUiState.UpdatedSuccessfully - } - - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/BeneficiaryListViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/BeneficiaryListViewModel.kt deleted file mode 100644 index b7350a732..000000000 --- a/app/src/main/java/org/mifos/mobile/viewModels/BeneficiaryListViewModel.kt +++ /dev/null @@ -1,33 +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.R -import org.mifos.mobile.repositories.BeneficiaryRepository -import org.mifos.mobile.utils.BeneficiaryUiState -import javax.inject.Inject - -@HiltViewModel -class BeneficiaryListViewModel @Inject constructor(private val beneficiaryRepositoryImp: BeneficiaryRepository) : - ViewModel() { - - private val _beneficiaryUiState = - MutableStateFlow(BeneficiaryUiState.Initial) - val beneficiaryUiState: StateFlow get() = _beneficiaryUiState - - fun loadBeneficiaries() { - viewModelScope.launch { - _beneficiaryUiState.value = BeneficiaryUiState.Loading - beneficiaryRepositoryImp.beneficiaryList().catch { - _beneficiaryUiState.value = BeneficiaryUiState.ShowError(R.string.beneficiaries) - }.collect { - _beneficiaryUiState.value = BeneficiaryUiState.ShowBeneficiaryList(it) - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/QrCodeImportViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/QrCodeImportViewModel.kt deleted file mode 100644 index ecbc09e22..000000000 --- a/app/src/main/java/org/mifos/mobile/viewModels/QrCodeImportViewModel.kt +++ /dev/null @@ -1,79 +0,0 @@ -package org.mifos.mobile.viewModels - -import android.net.Uri -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.google.zxing.* -import com.google.zxing.common.HybridBinarizer -import com.isseiaoki.simplecropview.CropImageView -import dagger.hilt.android.lifecycle.HiltViewModel -import io.reactivex.Single -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.CompositeDisposable -import io.reactivex.schedulers.Schedulers -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import org.mifos.mobile.R -import org.mifos.mobile.utils.QrCodeUiState -import java.util.* -import javax.inject.Inject - -@HiltViewModel -class QrCodeImportViewModel @Inject constructor() : ViewModel() { - - private val compositeDisposables: CompositeDisposable = CompositeDisposable() - - private var result: Result? = null - private var hasErrorOccurred = false - - private val _qrCodeUiState = MutableStateFlow(QrCodeUiState.Initial) - val qrCodeUiState: StateFlow = _qrCodeUiState - - fun getDecodedResult(sourceUri: Uri?, cropImageView: CropImageView?) { - _qrCodeUiState.value = QrCodeUiState.Loading - cropImageView?.crop(sourceUri) - ?.executeAsSingle() - ?.flatMap { bMap -> - val intArray = IntArray(bMap.width * bMap.height) - // copy pixel data from the Bitmap into the 'intArray' array - bMap.getPixels( - intArray, - 0, - bMap.width, - 0, - 0, - bMap.width, - bMap.height, - ) - val source: LuminanceSource = RGBLuminanceSource( - bMap.width, - bMap.height, - intArray, - ) - val bitmap = BinaryBitmap(HybridBinarizer(source)) - // flags for decoding since it is large file - val tmpHintsMap: MutableMap = - EnumMap(DecodeHintType::class.java) - tmpHintsMap[DecodeHintType.TRY_HARDER] = java.lang.Boolean.TRUE - tmpHintsMap[DecodeHintType.PURE_BARCODE] = java.lang.Boolean.TRUE - val reader: Reader = MultiFormatReader() - try { - result = reader.decode(bitmap, tmpHintsMap) - } catch (e: Exception) { - _qrCodeUiState.value = QrCodeUiState.ShowError(R.string.error_reading_qr) - } - Single.just(result) - } - ?.subscribeOn(Schedulers.newThread()) - ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribe({ result -> - _qrCodeUiState.value = QrCodeUiState.HandleDecodedResult(result) - }) { - if (!hasErrorOccurred) { - _qrCodeUiState.value = QrCodeUiState.ShowError(R.string.error_reading_qr) - } - hasErrorOccurred = false - }?.let { compositeDisposables.add(it) } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/SavingAccountsTransactionViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/SavingAccountsTransactionViewModel.kt deleted file mode 100644 index 58c6fb597..000000000 --- a/app/src/main/java/org/mifos/mobile/viewModels/SavingAccountsTransactionViewModel.kt +++ /dev/null @@ -1,152 +0,0 @@ -package org.mifos.mobile.viewModels - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import dagger.hilt.android.lifecycle.HiltViewModel -import io.reactivex.Observable -import io.reactivex.functions.Predicate -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.catch -import kotlinx.coroutines.launch -import org.mifos.mobile.models.CheckboxStatus -import org.mifos.mobile.models.accounts.savings.Transactions -import org.mifos.mobile.repositories.SavingsAccountRepository -import org.mifos.mobile.utils.CheckBoxStatusUtil -import org.mifos.mobile.utils.Constants -import org.mifos.mobile.utils.DateHelper -import org.mifos.mobile.utils.SavingsAccountUiState -import javax.inject.Inject - -@HiltViewModel -class SavingAccountsTransactionViewModel @Inject constructor(private val savingsAccountRepositoryImp: SavingsAccountRepository) : - ViewModel() { - - private val _savingAccountsTransactionUiState = - MutableStateFlow(SavingsAccountUiState.Initial) - val savingAccountsTransactionUiState: StateFlow get() = _savingAccountsTransactionUiState - - /** - * Filters [List] of [CheckboxStatus] - * @param statusModelList [List] of [CheckboxStatus] - * @return Returns [List] of [CheckboxStatus] which have - * `checkboxStatus.isChecked()` as true. - */ - fun getCheckedStatus(statusModelList: List?): List? { - return Observable.fromIterable(statusModelList) - .filter { (_, _, isChecked) -> isChecked }.toList().blockingGet() - } - - /** - * 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 { - _savingAccountsTransactionUiState.value = SavingsAccountUiState.Loading - savingsAccountRepositoryImp.getSavingsWithAssociations( - accountId, - Constants.TRANSACTIONS, - ).catch { - _savingAccountsTransactionUiState.value = SavingsAccountUiState.Error - }.collect { - _savingAccountsTransactionUiState.value = - SavingsAccountUiState.SuccessLoadingSavingsWithAssociations(it) - } - } - } - - /** - * Used for filtering [List] of [Transactions] according to `startDate` and - * `lastDate` - * - * @param savingAccountsTransactionList [List] of [Transactions] - * @param startDate Starting date for filtering - * @param lastDate Last date for filtering - */ - fun filterTransactionList( - savingAccountsTransactionList: List?, - startDate: Long?, - lastDate: Long?, - ) { - val list = when { - (startDate != null && lastDate != null) -> { - Observable.fromIterable(savingAccountsTransactionList) - .filter { (_, _, _, _, date) -> - (DateHelper.getDateAsLongFromList(date) in startDate..lastDate) - } - .toList().blockingGet() - } - - else -> null - } - _savingAccountsTransactionUiState.value = - SavingsAccountUiState.ShowFilteredTransactionsList(list) - } - - /** - * Filters [List] of [Transactions] according to [CheckboxStatus] - * @param savingAccountsTransactionList [List] of filtered [Transactions] - * @param status Used for filtering the [List] - * @return Returns [List] of filtered [Transactions] according to the - * `status` provided. - */ - fun filterTransactionListByType( - savingAccountsTransactionList: List?, - status: CheckboxStatus?, - checkBoxStatusUtil: CheckBoxStatusUtil - ): Collection? { - return Observable.fromIterable(savingAccountsTransactionList) - .filter( - Predicate { (_, transactionType) -> - - when { - ((checkBoxStatusUtil.depositString?.let { status?.status?.compareTo(it) } == 0) && (transactionType?.deposit!!)) -> - return@Predicate true - - ((checkBoxStatusUtil.dividendPayoutString?.let { - status?.status?.compareTo( - it - ) - } == 0) && (transactionType?.dividendPayout!!)) -> - return@Predicate true - - ((checkBoxStatusUtil.withdrawalString?.let { status?.status?.compareTo(it) } == 0) && (transactionType?.withdrawal!!)) -> - return@Predicate true - - ((checkBoxStatusUtil.interestPostingString?.let { - status?.status?.compareTo( - it - ) - } == 0) && (transactionType?.interestPosting!!)) -> - return@Predicate true - - ((checkBoxStatusUtil.feeDeductionString?.let { status?.status?.compareTo(it) } == 0) && (transactionType?.feeDeduction!!)) -> - return@Predicate true - - ((checkBoxStatusUtil.withdrawalTransferString?.let { - status?.status?.compareTo( - it - ) - } == 0) && (transactionType?.withdrawTransfer!!)) -> - return@Predicate true - - ((checkBoxStatusUtil.rejectedTransferString?.let { - status?.status?.compareTo( - it - ) - } == 0) && (transactionType?.rejectTransfer!!)) -> - return@Predicate true - - ((checkBoxStatusUtil.overdraftFeeString?.let { status?.status?.compareTo(it) } == 0) && (transactionType?.overdraftFee!!)) -> - return@Predicate true - - else -> false - } - }, - ).toList().blockingGet() - } -} \ No newline at end of file diff --git a/app/src/main/java/org/mifos/mobile/viewModels/TransferProcessViewModel.kt b/app/src/main/java/org/mifos/mobile/viewModels/TransferProcessViewModel.kt deleted file mode 100644 index 8bf0cdb94..000000000 --- a/app/src/main/java/org/mifos/mobile/viewModels/TransferProcessViewModel.kt +++ /dev/null @@ -1,66 +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.TransferRepository -import org.mifos.mobile.ui.enums.TransferType -import org.mifos.mobile.utils.TransferUiState -import javax.inject.Inject - -@HiltViewModel -class TransferProcessViewModel @Inject constructor(private val transferRepositoryImp: TransferRepository) : - ViewModel() { - - private val _transferUiState = MutableStateFlow(TransferUiState.Initial) - val transferUiState: StateFlow get() = _transferUiState - - fun makeTransfer( - fromOfficeId: Int?, - fromClientId: Long?, - fromAccountType: Int?, - fromAccountId: Int?, - toOfficeId: Int?, - toClientId: Long?, - toAccountType: Int?, - toAccountId: Int?, - transferDate: String?, - transferAmount: Double?, - transferDescription: String?, - dateFormat: String = "dd MMMM yyyy", - locale: String = "en", - fromAccountNumber: String?, - toAccountNumber: String?, - transferType: TransferType? - ) { - viewModelScope.launch { - _transferUiState.value = TransferUiState.Loading - transferRepositoryImp.makeTransfer( - fromOfficeId, - fromClientId, - fromAccountType, - fromAccountId, - toOfficeId, - toClientId, - toAccountType, - toAccountId, - transferDate, - transferAmount, - transferDescription, - dateFormat, - locale, - fromAccountNumber, - toAccountNumber, - transferType - ).catch { e -> - _transferUiState.value = TransferUiState.Error(e) - }.collect { - _transferUiState.value = TransferUiState.TransferSuccess - } - } - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_qr_code_import.xml b/app/src/main/res/layout/fragment_qr_code_import.xml index 6124c832a..f1e90076e 100644 --- a/app/src/main/res/layout/fragment_qr_code_import.xml +++ b/app/src/main/res/layout/fragment_qr_code_import.xml @@ -12,6 +12,7 @@ android:padding="@dimen/Mifos.DesignSystem.Spacing.CardInnerPaddingLarge" android:text="@string/select_region_qr" /> + -