From 348ec06ff7979ff7a7761109c746392a61497e25 Mon Sep 17 00:00:00 2001 From: Sk Niyaj Ali Date: Tue, 24 Sep 2024 21:03:23 +0530 Subject: [PATCH 01/31] Feat: KMP Library Setup (#1766) * Migrating from hilt to koin (This) (#1764) * Migrating from hilt to koin * Fixed Instance creation error * refactor: Removed Hilt and migrated to Koin This commit removes Hilt and migrates the project to Koin for dependency injection. The following changes were made: - Removed the `AndroidHiltConventionPlugin`. - Added the `AndroidKoinConventionPlugin`. - Updated dependencies to use Koin. - Updated KSP configuration for Koin. - Updated feature modules to use Koin. - Updated common modules to use Koin . - Removed Hilt annotations and replaced them with Koin annotations. - Updated ViewModels to use Koin for dependency injection. - Updated modules to use Koin for dependency injection. * Formatted Dependencies * migrating from hilt to koin clean up commit * Revert "migrating from hilt to koin clean up commit" This reverts commit bb63058e49299a23d4397ef8ed2ff6236418bd7e. --------- Co-authored-by: Sk Niyaj Ali * Feat: KMP Library Setup --------- Co-authored-by: Nagarjuna <99315689+Nagarjuna0033@users.noreply.github.com> --- .github/workflows/master_dev_ci.yml | 2 + .github/workflows/monthly.yaml | 6 +- .github/workflows/weekly.yaml | 6 +- build-logic/convention/build.gradle.kts | 24 +- .../kotlin/AndroidFeatureConventionPlugin.kt | 28 +- .../kotlin/AndroidHiltConventionPlugin.kt | 21 - .../kotlin/AndroidLibraryConventionPlugin.kt | 3 + .../main/kotlin/CMPFeatureConventionPlugin.kt | 54 + .../main/kotlin/KMPKoinConventionPlugin.kt | 40 + .../main/kotlin/KMPLibraryConventionPlugin.kt | 41 + .../src/main/kotlin/KoinConventionPlugin.kt | 36 + .../kotlin/KotlinInjectConventionPlugin.kt | 29 + .../kotlin/org/mifospay/AndroidCompose.kt | 2 - .../main/kotlin/org/mifospay/KotlinAndroid.kt | 42 +- .../org/mifospay/KotlinMultiplatform.kt | 33 + .../kotlin/org/mifospay/ProjectExtensions.kt | 3 + build.gradle.kts | 16 +- core/analytics/build.gradle.kts | 23 +- .../kotlin}/AndroidManifest.xml | 0 .../mifospay/core/analytics/AnalyticsEvent.kt | 0 .../core/analytics/AnalyticsHelper.kt | 0 .../core/analytics/NoOpAnalyticsHelper.kt | 0 .../core/analytics/StubAnalyticsHelper.kt | 5 +- .../org/mifospay/core/analytics/UiHelpers.kt | 0 .../core/analytics/di/AnalyticsModule.kt | 25 + .../analytics/di/FirebaseAnalyticsHelper.kt | 3 +- .../core/analytics/di/AnalyticsModule.kt | 36 - core/common/build.gradle.kts | 21 +- .../{main => androidMain}/AndroidManifest.xml | 0 .../kotlin/org/mifospay/common/Constants.kt | 0 .../org/mifospay/common/CreditCardUtils.kt | 0 .../kotlin/org/mifospay/common/DebugUtil.kt | 0 .../kotlin/org/mifospay/common/FileUtils.kt | 0 .../org/mifospay/common/NavArgsConstants.kt | 0 .../kotlin/org/mifospay/common/Utils.kt | 0 .../mifospay/core/network/MifosDispatchers.kt | 9 +- .../core/network/di/CoroutineScopesModule.kt | 23 + .../core/network/di/DispatchersModule.kt | 21 + .../core/network/di/CoroutineScopesModule.kt | 37 - .../core/network/di/DispatchersModule.kt | 32 - core/data/build.gradle.kts | 41 +- .../{main => androidMain}/AndroidManifest.xml | 0 .../{main => androidMain}/assets/banks.json | 0 .../{main => androidMain}/assets/cities.json | 0 .../assets/countriesToCities.json | 0 .../org/mifospay/core/data/base/TaskLooper.kt | 3 +- .../core/data/base/ThreadPoolQueue.kt | 0 .../org/mifospay/core/data/base/UseCase.kt | 0 .../mifospay/core/data/base/UseCaseFactory.kt | 3 +- .../mifospay/core/data/base/UseCaseHandler.kt | 0 .../core/data/base/UseCaseScheduler.kt | 0 .../data/base/UseCaseThreadPoolScheduler.kt | 0 .../org/mifospay/core/data/di/DataModule.kt | 214 ++ .../mifospay/core/data/di/LocalDataModule.kt | 19 + .../usecase/account/BlockUnblockCommand.kt | 3 +- .../account/DownloadTransactionReceipt.kt | 3 +- .../domain/usecase/account/FetchAccount.kt | 3 +- .../account/FetchAccountTransaction.kt | 3 +- .../account/FetchAccountTransactions.kt | 3 +- .../usecase/account/FetchAccountTransfer.kt | 3 +- .../domain/usecase/account/FetchAccounts.kt | 3 +- .../domain/usecase/account/FetchMerchants.kt | 3 +- .../domain/usecase/account/TransferFunds.kt | 3 +- .../domain/usecase/client/CreateClient.kt | 3 +- .../domain/usecase/client/FetchClientData.kt | 7 +- .../usecase/client/FetchClientDetails.kt | 3 +- .../domain/usecase/client/FetchClientImage.kt | 3 +- .../domain/usecase/client/SearchClient.kt | 7 +- .../domain/usecase/client/UpdateClient.kt | 3 +- .../domain/usecase/history/HistoryContract.kt | 0 .../usecase/history/TransactionsHistory.kt | 13 +- .../domain/usecase/invoice/FetchInvoice.kt | 3 +- .../domain/usecase/invoice/FetchInvoices.kt | 3 +- .../usecase/kyc/FetchKYCLevel1Details.kt | 3 +- .../usecase/kyc/UpdateKYCLevel1Details.kt | 3 +- .../data/domain/usecase/kyc/UploadKYCDocs.kt | 3 +- .../usecase/kyc/UploadKYCLevel1Details.kt | 3 +- .../notification/FetchNotifications.kt | 3 +- .../data/domain/usecase/savedcards/AddCard.kt | 3 +- .../domain/usecase/savedcards/DeleteCard.kt | 3 +- .../domain/usecase/savedcards/EditCard.kt | 3 +- .../usecase/savedcards/FetchSavedCards.kt | 3 +- .../CreateStandingTransaction.kt | 3 +- .../DeleteStandingInstruction.kt | 3 +- .../FetchStandingInstruction.kt | 3 +- .../GetAllStandingInstructions.kt | 3 +- .../UpdateStandingInstruction.kt | 3 +- .../usecase/twofactor/FetchDeliveryMethods.kt | 3 +- .../domain/usecase/twofactor/RequestOTP.kt | 3 +- .../domain/usecase/twofactor/ValidateOTP.kt | 3 +- .../domain/usecase/user/AuthenticateUser.kt | 3 +- .../data/domain/usecase/user/CreateUser.kt | 3 +- .../data/domain/usecase/user/DeleteUser.kt | 3 +- .../domain/usecase/user/FetchUserDetails.kt | 3 +- .../data/domain/usecase/user/FetchUsers.kt | 3 +- .../data/domain/usecase/user/RegisterUser.kt | 3 +- .../data/domain/usecase/user/UpdateUser.kt | 3 +- .../data/domain/usecase/user/VerifyUser.kt | 3 +- .../fineract/entity/mapper/AccountMapper.kt | 3 +- .../entity/mapper/ClientDetailsMapper.kt | 3 +- .../fineract/entity/mapper/CurrencyMapper.kt | 6 +- .../fineract/entity/mapper/FetchAccount.kt | 3 +- .../entity/mapper/SearchedEntitiesMapper.kt | 3 +- .../entity/mapper/TransactionMapper.kt | 3 +- .../fineract/repository/FineractRepository.kt | 7 +- .../auth/AuthenticationUserRepository.kt | 3 +- .../repository/auth/UserDataRepository.kt | 0 .../repository/local/LocalAssetRepository.kt | 0 .../data/repository/local/LocalRepository.kt | 5 +- .../local/MifosLocalAssetRepository.kt | 12 +- .../util/ConnectivityManagerNetworkMonitor.kt | 6 +- .../org/mifospay/core/data/util/Constants.kt | 0 .../core/data/util/ErrorJsonMessageHelper.kt | 0 .../mifospay/core/data/util/NetworkMonitor.kt | 0 .../core/data/util/TimeZoneMonitor.kt | 16 +- .../res/values/strings.xml | 0 .../org/mifospay/core/data/di/DataModule.kt | 48 - .../mifospay/core/data/di/LocalDataModule.kt | 46 - .../mobilewallet/core/ExampleUnitTest.kt | 26 - core/datastore-proto/build.gradle.kts | 23 +- .../{main => androidMain}/AndroidManifest.xml | 0 .../user_preferences.proto | 0 core/datastore/build.gradle.kts | 27 +- .../{main => androidMain}/AndroidManifest.xml | 0 .../core/datastore/PreferencesHelper.kt | 13 +- .../core/datastore/di/CoreDataStoreModule.kt | 21 + .../core/datastore/di/DataStoreModule.kt | 30 - core/designsystem/build.gradle.kts | 77 +- core/model/build.gradle.kts | 20 +- .../mobilewallet/model/ExampleUnitTest.kt | 25 - core/network/build.gradle.kts | 80 +- .../{main => androidMain}/AndroidManifest.xml | 0 .../{main => androidMain}/assets/banks.json | 0 .../{main => androidMain}/assets/cities.json | 0 .../assets/countries.json | 0 .../assets/countriesToCities.json | 0 .../{main => androidMain}/assets/states.json | 0 .../org/mifospay/core/network/ApiEndPoints.kt | 0 .../mifospay/core/network/ApiInterceptor.kt | 6 +- .../org/mifospay/core/network/BaseURL.kt | 0 .../core/network/FineractApiManager.kt | 3 +- .../mifospay/core/network/GenericResponse.kt | 0 .../core/network/JvmLocalAssetManager.kt | 24 +- .../mifospay/core/network/KtorInterceptor.kt | 0 .../core/network/MifosWalletOkHttpClient.kt | 2 +- .../core/network/SelfServiceApiManager.kt | 3 +- .../mifospay/core/network/di/LocalModule.kt | 20 + .../mifospay/core/network/di/NetworkModule.kt | 233 ++ .../org/mifospay/core/network/di/Qualifier.kt | 27 + .../localAssets/LocalAssetDataSource.kt | 0 .../network/localAssets/LocalAssetManager.kt | 0 .../localAssets/MifosLocalAssetDataSource.kt | 12 +- .../services/AccountTransfersService.kt | 0 .../network/services/AuthenticationService.kt | 0 .../network/services/BeneficiaryService.kt | 0 .../core/network/services/ClientService.kt | 0 .../core/network/services/DocumentService.kt | 0 .../core/network/services/InvoiceService.kt | 0 .../core/network/services/KYCLevel1Service.kt | 0 .../services/KtorAuthenticationService.kt | 3 +- .../services/KtorSavingsAccountService.kt | 3 +- .../network/services/NotificationService.kt | 0 .../network/services/RegistrationService.kt | 0 .../core/network/services/RunReportService.kt | 0 .../core/network/services/SavedCardService.kt | 0 .../services/SavingsAccountsService.kt | 0 .../core/network/services/SearchService.kt | 0 .../services/StandingInstructionService.kt | 0 .../services/ThirdPartyTransferService.kt | 0 .../network/services/TwoFactorAuthService.kt | 0 .../core/network/services/UserService.kt | 0 .../mifospay/core/network/di/LocalModule.kt | 25 - .../mifospay/core/network/di/NetworkModule.kt | 360 -- .../mifospay/network/ExampleUnitTest.kt | 25 - core/ui/build.gradle.kts | 48 +- feature/accounts/build.gradle.kts | 1 + .../feature/bank/accounts/AccountViewModel.kt | 5 +- .../feature/bank/accounts/AccountsScreen.kt | 4 +- .../bank/accounts/di/AccountsModule.kt | 26 + .../accounts/link/LinkBankAccountScreen.kt | 4 +- .../accounts/link/LinkBankAccountViewModel.kt | 9 +- feature/auth/build.gradle.kts | 2 - .../mifospay/feature/auth/di/AuthModule.kt | 49 + .../feature/auth/login/LoginScreen.kt | 4 +- .../feature/auth/login/LoginViewModel.kt | 5 +- .../mobileVerify/MobileVerificationScreen.kt | 4 +- .../MobileVerificationViewModel.kt | 5 +- .../feature/auth/signup/SignupScreen.kt | 4 +- .../feature/auth/signup/SignupViewModel.kt | 5 +- feature/editpassword/build.gradle.kts | 4 +- .../editpassword/EditPasswordScreen.kt | 4 +- .../editpassword/EditPasswordViewModel.kt | 5 +- .../editpassword/di/EditPasswordModule.kt | 25 + feature/faq/build.gradle.kts | 4 +- .../org/mifospay/feature/faq/FAQViewModel.kt | 5 +- .../org/mifospay/feature/faq/FaqScreen.kt | 4 +- .../org/mifospay/feature/faq/di/FaqModule.kt | 17 +- feature/history/build.gradle.kts | 3 +- .../org/mifospay/feature/di/HistoryModule.kt | 40 + .../mifospay/feature/history/HistoryScreen.kt | 4 +- .../feature/history/HistoryViewModel.kt | 5 +- .../SpecificTransactionsScreen.kt | 4 +- .../SpecificTransactionsViewModel.kt | 5 +- .../detail/TransactionDetailScreen.kt | 4 +- .../detail/TransactionDetailViewModel.kt | 5 +- feature/home/build.gradle.kts | 2 +- .../org/mifospay/feature/home/HomeScreen.kt | 4 +- .../mifospay/feature/home/HomeViewModel.kt | 5 +- .../mifospay/feature/home/di/HomeModule.kt | 26 + feature/invoices/build.gradle.kts | 4 +- .../feature/invoices/InvoiceDetailScreen.kt | 4 +- .../invoices/InvoiceDetailViewModel.kt | 5 +- .../feature/invoices/InvoiceScreen.kt | 4 +- .../feature/invoices/InvoicesViewModel.kt | 5 +- .../feature/invoices/di/InvoicesModule.kt | 35 + feature/kyc/build.gradle.kts | 2 - .../feature/kyc/KYCDescriptionScreen.kt | 4 +- .../feature/kyc/KYCDescriptionViewModel.kt | 5 +- .../mifospay/feature/kyc/KYCLevel1Screen.kt | 4 +- .../feature/kyc/KYCLevel1ViewModel.kt | 5 +- .../mifospay/feature/kyc/KYCLevel2Screen.kt | 4 +- .../feature/kyc/KYCLevel2ViewModel.kt | 5 +- .../mifospay/feature/kyc/KYCLevel3Screen.kt | 4 +- .../feature/kyc/KYCLevel3ViewModel.kt | 5 +- .../org/mifospay/feature/kyc/di/KYCModule.kt | 50 + feature/make-transfer/build.gradle.kts | 4 +- .../make/transfer/MakeTransferScreen.kt | 4 +- .../make/transfer/MakeTransferViewModel.kt | 5 +- .../make/transfer/di/MakeTransferModule.kt | 26 + feature/merchants/build.gradle.kts | 1 - .../merchants/MerchantTransferViewModel.kt | 5 +- .../feature/merchants/MerchantViewModel.kt | 10 +- .../feature/merchants/di/MerchantsModule.kt | 38 + .../feature/merchants/ui/MerchantScreen.kt | 4 +- .../merchants/ui/MerchantTransferScreen.kt | 4 +- feature/notification/build.gradle.kts | 1 - .../notification/NotificationScreen.kt | 4 +- .../notification/NotificationViewModel.kt | 5 +- .../notification/di/NotificationModule.kt | 24 + feature/payments/build.gradle.kts | 1 - .../feature/payments/RequestScreen.kt | 4 +- .../feature/payments/TransferViewModel.kt | 5 +- .../feature/payments/di/PaymentsModule.kt | 24 + feature/profile/build.gradle.kts | 4 +- .../mifospay/feature/profile/ProfileScreen.kt | 4 +- .../feature/profile/ProfileViewModel.kt | 5 +- .../feature/profile/di/ProfileModule.kt | 35 + .../feature/profile/edit/EditProfileScreen.kt | 4 +- .../profile/edit/EditProfileViewModel.kt | 5 +- feature/qr/build.gradle.kts | 1 - .../mifospay/feature/read/qr/ReadQrScreen.kt | 4 +- .../feature/read/qr/ReadQrViewModel.kt | 5 +- .../mifospay/feature/read/qr/di/QrModule.kt | 24 + .../mifospay/feature/read/qr/utils/ScanQr.kt | 3 +- feature/receipt/build.gradle.kts | 1 - .../mifospay/feature/receipt/ReceiptScreen.kt | 6 +- .../feature/receipt/ReceiptViewModel.kt | 5 +- .../feature/receipt/di/ReceiptModule.kt | 27 + feature/request-money/build.gradle.kts | 2 - .../feature/request/money/GenerateQr.kt | 3 +- .../request/money/ShowQrScreenRoute.kt | 4 +- .../feature/request/money/ShowQrViewModel.kt | 5 +- .../request/money/di/RequestMoneyModule.kt | 30 + feature/savedcards/build.gradle.kts | 4 +- .../feature/savedcards/CardsScreen.kt | 4 +- .../savedcards/CardsScreenViewModel.kt | 5 +- .../feature/savedcards/di/SavedCardsModule.kt | 27 + feature/search/build.gradle.kts | 4 +- .../mifospay/feature/search/SearchScreen.kt | 4 +- .../feature/search/SearchViewModel.kt | 5 +- .../feature/search/di/SearchModule.kt | 24 + feature/send-money/build.gradle.kts | 2 - .../send/money/SendPaymentViewModel.kt | 5 +- .../feature/send/money/SendScreenRoute.kt | 4 +- .../feature/send/money/di/SendMoneyModule.kt | 24 + feature/settings/build.gradle.kts | 4 +- .../feature/settings/SettingsScreen.kt | 6 +- .../feature/settings/SettingsViewModel.kt | 5 +- .../feature/settings/di/SettingsModule.kt | 24 + feature/standing-instruction/build.gradle.kts | 2 - .../standing/instruction/NewSIScreenRoute.kt | 4 +- .../standing/instruction/NewSIViewModel.kt | 5 +- .../standing/instruction/SIDetailsScreen.kt | 4 +- .../StandingInstructionDetailsViewModel.kt | 5 +- .../instruction/StandingInstructionScreen.kt | 4 +- .../StandingInstructionViewModel.kt | 5 +- .../di/StandingInstructionModule.kt | 45 + feature/upi-setup/build.gradle.kts | 4 +- .../feature/upiSetup/di/UpiSetupModule.kt | 26 + .../upiSetup/screens/DebitCardScreen.kt | 4 +- .../upiSetup/screens/SetUpUPiPinScreen.kt | 4 +- .../upiSetup/viewmodel/DebitCardViewModal.kt | 5 +- .../upiSetup/viewmodel/SetUpUpiViewModal.kt | 5 +- gradle.properties | 1 + gradle/libs.versions.toml | 105 +- .../countrycodepicker/CountryCodePicker.kt | 1 - .../material3/navigation/BottomSheet.kt | 2 + libs/mifos-passcode/build.gradle.kts | 15 +- .../mifos/library/passcode/PassCodeScreen.kt | 4 +- .../library/passcode/data/PasscodeManager.kt | 9 +- .../passcode/data/PasscodeRepositoryImpl.kt | 3 +- .../library/passcode/di/ApplicationModule.kt | 34 +- .../passcode/viewmodels/PasscodeViewModel.kt | 5 +- mifospay/build.gradle.kts | 19 +- .../prodReleaseRuntimeClasspath.tree.txt | 3164 +++++++++-------- .../prodReleaseRuntimeClasspath.txt | 393 +- mifospay/prodRelease-badging.txt | 2 +- .../main/java/org/mifospay/MainActivity.kt | 29 +- .../org/mifospay/MainActivityViewModel.kt | 5 +- .../src/main/java/org/mifospay/MifosPayApp.kt | 26 +- .../java/org/mifospay/di/JankStatsModule.kt | 38 +- .../main/java/org/mifospay/di/KoinModules.kt | 76 + .../test/java/org/mifospay/ExampleUnitTest.kt | 26 - .../java/org/mifospay/KoinModulesCheck.kt | 76 + settings.gradle.kts | 2 +- shared/build.gradle.kts | 1 - 316 files changed, 4280 insertions(+), 3170 deletions(-) delete mode 100644 build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt create mode 100644 build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt create mode 100644 build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt create mode 100644 build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt create mode 100644 build-logic/convention/src/main/kotlin/KoinConventionPlugin.kt create mode 100644 build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt create mode 100644 build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt rename core/analytics/src/{main => androidMain/kotlin}/AndroidManifest.xml (100%) rename core/analytics/src/{main => androidMain}/kotlin/org/mifospay/core/analytics/AnalyticsEvent.kt (100%) rename core/analytics/src/{main => androidMain}/kotlin/org/mifospay/core/analytics/AnalyticsHelper.kt (100%) rename core/analytics/src/{main => androidMain}/kotlin/org/mifospay/core/analytics/NoOpAnalyticsHelper.kt (100%) rename core/analytics/src/{main => androidMain}/kotlin/org/mifospay/core/analytics/StubAnalyticsHelper.kt (82%) rename core/analytics/src/{main => androidMain}/kotlin/org/mifospay/core/analytics/UiHelpers.kt (100%) create mode 100644 core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/di/AnalyticsModule.kt rename core/analytics/src/{main => androidMain}/kotlin/org/mifospay/core/analytics/di/FirebaseAnalyticsHelper.kt (92%) delete mode 100644 core/analytics/src/main/kotlin/org/mifospay/core/analytics/di/AnalyticsModule.kt rename core/common/src/{main => androidMain}/AndroidManifest.xml (100%) rename core/common/src/{main => androidMain}/kotlin/org/mifospay/common/Constants.kt (100%) rename core/common/src/{main => androidMain}/kotlin/org/mifospay/common/CreditCardUtils.kt (100%) rename core/common/src/{main => androidMain}/kotlin/org/mifospay/common/DebugUtil.kt (100%) rename core/common/src/{main => androidMain}/kotlin/org/mifospay/common/FileUtils.kt (100%) rename core/common/src/{main => androidMain}/kotlin/org/mifospay/common/NavArgsConstants.kt (100%) rename core/common/src/{main => androidMain}/kotlin/org/mifospay/common/Utils.kt (100%) rename core/common/src/{main => androidMain}/kotlin/org/mifospay/core/network/MifosDispatchers.kt (74%) create mode 100644 core/common/src/androidMain/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt create mode 100644 core/common/src/androidMain/kotlin/org/mifospay/core/network/di/DispatchersModule.kt delete mode 100644 core/common/src/main/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt delete mode 100644 core/common/src/main/kotlin/org/mifospay/core/network/di/DispatchersModule.kt rename core/data/src/{main => androidMain}/AndroidManifest.xml (100%) rename core/data/src/{main => androidMain}/assets/banks.json (100%) rename core/data/src/{main => androidMain}/assets/cities.json (100%) rename core/data/src/{main => androidMain}/assets/countriesToCities.json (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/base/TaskLooper.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/base/ThreadPoolQueue.kt (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/base/UseCase.kt (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/base/UseCaseFactory.kt (93%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/base/UseCaseHandler.kt (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/base/UseCaseScheduler.kt (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/base/UseCaseThreadPoolScheduler.kt (100%) create mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/di/DataModule.kt create mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/di/LocalDataModule.kt rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt (97%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt (99%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt (93%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt (97%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/history/HistoryContract.kt (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt (83%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt (97%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt (98%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt (97%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt (94%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt (95%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt (97%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt (94%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt (93%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt (83%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt (97%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt (92%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt (96%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt (98%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt (92%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/repository/auth/UserDataRepository.kt (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/repository/local/LocalAssetRepository.kt (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/repository/local/LocalRepository.kt (90%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt (77%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt (92%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/util/Constants.kt (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/util/NetworkMonitor.kt (100%) rename core/data/src/{main => androidMain}/java/org/mifospay/core/data/util/TimeZoneMonitor.kt (87%) rename core/data/src/{main => androidMain}/res/values/strings.xml (100%) delete mode 100644 core/data/src/main/java/org/mifospay/core/data/di/DataModule.kt delete mode 100644 core/data/src/main/java/org/mifospay/core/data/di/LocalDataModule.kt delete mode 100644 core/data/src/test/java/org/mifospay/mobilewallet/core/ExampleUnitTest.kt rename core/datastore-proto/src/{main => androidMain}/AndroidManifest.xml (100%) rename core/datastore-proto/src/{main => androidMain}/proto/org.mifospay.core.data/user_preferences.proto (100%) rename core/datastore/src/{main => androidMain}/AndroidManifest.xml (100%) rename core/datastore/src/{main => androidMain}/java/org/mifospay/core/datastore/PreferencesHelper.kt (92%) create mode 100644 core/datastore/src/androidMain/java/org/mifospay/core/datastore/di/CoreDataStoreModule.kt delete mode 100644 core/datastore/src/main/java/org/mifospay/core/datastore/di/DataStoreModule.kt delete mode 100644 core/model/src/test/java/com/mifos/mobilewallet/model/ExampleUnitTest.kt rename core/network/src/{main => androidMain}/AndroidManifest.xml (100%) rename core/network/src/{main => androidMain}/assets/banks.json (100%) rename core/network/src/{main => androidMain}/assets/cities.json (100%) rename core/network/src/{main => androidMain}/assets/countries.json (100%) rename core/network/src/{main => androidMain}/assets/countriesToCities.json (100%) rename core/network/src/{main => androidMain}/assets/states.json (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/ApiEndPoints.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/ApiInterceptor.kt (81%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/BaseURL.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/FineractApiManager.kt (98%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/GenericResponse.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt (57%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/KtorInterceptor.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt (97%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt (96%) create mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/di/LocalModule.kt create mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt create mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/di/Qualifier.kt rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt (82%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/AuthenticationService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/ClientService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/DocumentService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/InvoiceService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt (92%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt (97%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/NotificationService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/RegistrationService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/RunReportService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/SavedCardService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/SearchService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt (100%) rename core/network/src/{main => androidMain}/kotlin/org/mifospay/core/network/services/UserService.kt (100%) delete mode 100644 core/network/src/main/kotlin/org/mifospay/core/network/di/LocalModule.kt delete mode 100644 core/network/src/main/kotlin/org/mifospay/core/network/di/NetworkModule.kt delete mode 100644 core/network/src/test/java/org/mifospay/mobilewallet/mifospay/network/ExampleUnitTest.kt create mode 100644 feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/di/AccountsModule.kt create mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt create mode 100644 feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/di/EditPasswordModule.kt rename core/network/src/main/kotlin/org/mifospay/core/network/di/Qualifier.kt => feature/faq/src/main/kotlin/org/mifospay/feature/faq/di/FaqModule.kt (58%) create mode 100644 feature/history/src/main/kotlin/org/mifospay/feature/di/HistoryModule.kt create mode 100644 feature/home/src/main/kotlin/org/mifospay/feature/home/di/HomeModule.kt create mode 100644 feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/di/InvoicesModule.kt create mode 100644 feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/di/KYCModule.kt create mode 100644 feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/di/MakeTransferModule.kt create mode 100644 feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/di/MerchantsModule.kt create mode 100644 feature/notification/src/main/kotlin/org/mifospay/feature/notification/di/NotificationModule.kt create mode 100644 feature/payments/src/main/kotlin/org/mifospay/feature/payments/di/PaymentsModule.kt create mode 100644 feature/profile/src/main/kotlin/org/mifospay/feature/profile/di/ProfileModule.kt create mode 100644 feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/di/QrModule.kt create mode 100644 feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/di/ReceiptModule.kt create mode 100644 feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/di/RequestMoneyModule.kt create mode 100644 feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/di/SavedCardsModule.kt create mode 100644 feature/search/src/main/kotlin/org/mifospay/feature/search/di/SearchModule.kt create mode 100644 feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/di/SendMoneyModule.kt create mode 100644 feature/settings/src/main/kotlin/org/mifospay/feature/settings/di/SettingsModule.kt create mode 100644 feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/di/StandingInstructionModule.kt create mode 100644 feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/di/UpiSetupModule.kt create mode 100644 mifospay/src/main/java/org/mifospay/di/KoinModules.kt delete mode 100644 mifospay/src/test/java/org/mifospay/ExampleUnitTest.kt create mode 100644 mifospay/src/test/java/org/mifospay/KoinModulesCheck.kt diff --git a/.github/workflows/master_dev_ci.yml b/.github/workflows/master_dev_ci.yml index 27bb7a38d..88fe178ef 100644 --- a/.github/workflows/master_dev_ci.yml +++ b/.github/workflows/master_dev_ci.yml @@ -133,6 +133,8 @@ jobs: run: ./gradlew :mifospay:assembleDemoDebug - name: Check badging + # This step is allowed to fail, as it's not critical for the build + continue-on-error: true run: ./gradlew :mifospay:checkProdReleaseBadging - name: Upload APKs diff --git a/.github/workflows/monthly.yaml b/.github/workflows/monthly.yaml index 9f173e9ed..557c0b26d 100644 --- a/.github/workflows/monthly.yaml +++ b/.github/workflows/monthly.yaml @@ -2,8 +2,10 @@ name: Bump our Calendar Version on: workflow_dispatch: - schedule: - - cron: '30 3 1 * *' +# This is a monthly cron job that runs on the first of the month at 3:30 AM UTC +# Turning off for now +# schedule: +# - cron: '30 3 1 * *' jobs: tag: name: Tag Monthly Release diff --git a/.github/workflows/weekly.yaml b/.github/workflows/weekly.yaml index 2e5281576..9b8285c07 100644 --- a/.github/workflows/weekly.yaml +++ b/.github/workflows/weekly.yaml @@ -2,8 +2,10 @@ name: Tag Weekly Release on: workflow_dispatch: - schedule: - - cron: '0 4 * * 0' +# This is a weekly cron job that runs every Sunday at 4:00 AM UTC +# Turning off for now +# schedule: +# - cron: '0 4 * * 0' jobs: tag: name: Tag Weekly Release diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts index 6a0f9ea3b..57703e6e1 100644 --- a/build-logic/convention/build.gradle.kts +++ b/build-logic/convention/build.gradle.kts @@ -51,10 +51,6 @@ gradlePlugin { id = "mifospay.android.application" implementationClass = "AndroidApplicationConventionPlugin" } - register("androidHilt") { - id = "mifospay.android.hilt" - implementationClass = "AndroidHiltConventionPlugin" - } register("androidLibraryCompose") { id = "mifospay.android.library.compose" implementationClass = "AndroidLibraryComposeConventionPlugin" @@ -64,6 +60,10 @@ gradlePlugin { implementationClass = "AndroidLibraryConventionPlugin" } register("androidFeature") { + id = "mifospay.cmp.feature" + implementationClass = "CMPFeatureConventionPlugin" + } + register("cmpFeature") { id = "mifospay.android.feature" implementationClass = "AndroidFeatureConventionPlugin" } @@ -87,10 +87,26 @@ gradlePlugin { id = "mifospay.jvm.library" implementationClass = "JvmLibraryConventionPlugin" } + register("kmpLibrary") { + id = "mifospay.kmp.library" + implementationClass = "KMPLibraryConventionPlugin" + } + register("kotlinInject") { + id = "mifospay.kmp.inject" + implementationClass = "KotlinInjectConventionPlugin" + } register("androidFlavors") { id = "mifospay.android.application.flavors" implementationClass = "AndroidApplicationFlavorsConventionPlugin" } + register("androidKoin") { + id = "mifospay.android.koin" + implementationClass = "KoinConventionPlugin" + } + register("kmpKoin") { + id = "mifospay.kmp.koin" + implementationClass = "KMPKoinConventionPlugin" + } register("detekt") { id = "mifos.detekt.plugin" implementationClass = "MifosDetektConventionPlugin" diff --git a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt index 6ef667136..52e08e684 100644 --- a/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidFeatureConventionPlugin.kt @@ -1,5 +1,6 @@ + import com.android.build.gradle.LibraryExtension -import com.android.build.gradle.internal.scope.ProjectInfo.Companion.getBaseName +import com.google.devtools.ksp.gradle.KspExtension import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.configure @@ -12,8 +13,9 @@ class AndroidFeatureConventionPlugin : Plugin { with(target) { pluginManager.apply { apply("mifospay.android.library") - apply("mifospay.android.hilt") + apply("mifospay.android.koin") } + extensions.configure { defaultConfig { // set custom test runner @@ -22,28 +24,42 @@ class AndroidFeatureConventionPlugin : Plugin { testOptions.animationsDisabled = true } + extensions.configure { + arg("KOIN_USE_COMPOSE_VIEWMODEL","true") + } + dependencies { add("implementation", project(":core:ui")) add("implementation", project(":core:designsystem")) + add("implementation", project(":core:data")) add("implementation", project(":libs:material3-navigation")) + add("implementation", libs.findLibrary("androidx.navigation.compose").get()) add("implementation", libs.findLibrary("kotlinx.collections.immutable").get()) - add("implementation", libs.findLibrary("androidx.hilt.navigation.compose").get()) add("implementation", libs.findLibrary("androidx.lifecycle.runtimeCompose").get()) add("implementation", libs.findLibrary("androidx.lifecycle.viewModelCompose").get()) add("implementation", libs.findLibrary("androidx.tracing.ktx").get()) + add("implementation", platform(libs.findLibrary("koin-bom").get())) + add("implementation", libs.findLibrary("koin-android").get()) + add("implementation", libs.findLibrary("koin.androidx.compose").get()) + + add("implementation", libs.findLibrary("koin.android").get()) + add("implementation", libs.findLibrary("koin.androidx.navigation").get()) + add("implementation", libs.findLibrary("koin.androidx.compose").get()) + add("implementation", libs.findLibrary("koin.core.viewmodel").get()) + add("androidTestImplementation", libs.findLibrary("androidx.lifecycle.runtimeTesting").get()) add("testImplementation", kotlin("test")) - add("testImplementation", libs.findLibrary("hilt.android.testing").get()) + + add("testImplementation", libs.findLibrary("koin.test").get()) + add("testImplementation", libs.findLibrary("koin.test.junit4").get()) add("debugImplementation", libs.findLibrary("androidx.compose.ui.test.manifest").get()) add("androidTestImplementation", libs.findLibrary("androidx.navigation.testing").get()) add("androidTestImplementation", libs.findLibrary("androidx.compose.ui.test").get()) - add("androidTestImplementation", libs.findLibrary("hilt.android.testing").get()) - add("androidTestImplementation", libs.findLibrary("androidx.lifecycle.runtimeTesting").get()) } } } diff --git a/build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt deleted file mode 100644 index c93d1abf8..000000000 --- a/build-logic/convention/src/main/kotlin/AndroidHiltConventionPlugin.kt +++ /dev/null @@ -1,21 +0,0 @@ - -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.kotlin.dsl.dependencies -import org.mifospay.libs - -class AndroidHiltConventionPlugin : Plugin { - override fun apply(target: Project) { - with(target) { - with(pluginManager) { - apply("com.google.devtools.ksp") - apply("dagger.hilt.android.plugin") - } - - dependencies { - "implementation"(libs.findLibrary("hilt.android").get()) - "ksp"(libs.findLibrary("hilt.compiler").get()) - } - } - } -} diff --git a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt index e3967793e..edea58609 100644 --- a/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/AndroidLibraryConventionPlugin.kt @@ -21,6 +21,7 @@ class AndroidLibraryConventionPlugin : Plugin { apply("mifos.detekt.plugin") apply("mifos.spotless.plugin") apply("mifos.ktlint.plugin") + apply("mifospay.android.koin") } extensions.configure { @@ -32,10 +33,12 @@ class AndroidLibraryConventionPlugin : Plugin { // so resources inside ":core:module1" must be prefixed with "core_module1_" resourcePrefix = path.split("""\W""".toRegex()).drop(1).distinct().joinToString(separator = "_").lowercase() + "_" } + extensions.configure { configurePrintApksTask(this) disableUnnecessaryAndroidTests(target) } + dependencies { add("testImplementation", kotlin("test")) add("implementation", libs.findLibrary("androidx.tracing.ktx").get()) diff --git a/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt new file mode 100644 index 000000000..c57ee23b3 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt @@ -0,0 +1,54 @@ + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.dependencies +import org.mifospay.libs + +class CMPFeatureConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + pluginManager.apply { + apply("mifospay.kmp.library") + apply("mifospay.kmp.inject") + apply("org.jetbrains.kotlin.plugin.compose") + apply("org.jetbrains.compose") + } + + dependencies { + add("commonMainImplementation", project(":core:ui")) + add("commonMainImplementation", project(":core:designsystem")) + add("commonMainImplementation", project(":core:data")) + add("commonMainImplementation", libs.findLibrary("jetbrains.compose.viewmodel").get()) + add("commonMainImplementation", libs.findLibrary("jetbrains.compose.navigation").get()) + add("commonMainImplementation", libs.findLibrary("kotlinx.collections.immutable").get()) + + add("androidMainImplementation", project(":libs:material3-navigation")) + + add("androidMainImplementation", libs.findLibrary("androidx.lifecycle.runtimeCompose").get()) + add("androidMainImplementation", libs.findLibrary("androidx.lifecycle.viewModelCompose").get()) + add("androidMainImplementation", libs.findLibrary("androidx.tracing.ktx").get()) + + add("androidMainImplementation", platform(libs.findLibrary("koin-bom").get())) + add("androidMainImplementation", libs.findLibrary("koin-android").get()) + add("androidMainImplementation", libs.findLibrary("koin.androidx.compose").get()) + + add("androidMainImplementation", libs.findLibrary("koin.android").get()) + add("androidMainImplementation", libs.findLibrary("koin.androidx.navigation").get()) + add("androidMainImplementation", libs.findLibrary("koin.androidx.compose").get()) + add("androidMainImplementation", libs.findLibrary("koin.core.viewmodel").get()) + + add("androidTestImplementation", libs.findLibrary("koin.test.junit4").get()) + + add("androidDebugImplementation", libs.findLibrary("androidx.compose.ui.test.manifest").get()) + add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.navigation.testing").get()) + add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.compose.ui.test").get()) + add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.lifecycle.runtimeTesting").get()) + add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.core").get()) + add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.ext").get()) + add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.junit").get()) + add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.runner").get()) + add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.espresso.core").get()) + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt new file mode 100644 index 000000000..ca6cf9a78 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt @@ -0,0 +1,40 @@ +import com.google.devtools.ksp.gradle.KspExtension +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.dependencies +import org.mifospay.libs + + +class KMPKoinConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply("com.google.devtools.ksp") + } + + dependencies { + val bom = libs.findLibrary("koin-bom").get() + add("commonMainImplementation", platform(bom)) + add("commonMainImplementation", libs.findLibrary("koin.core").get()) + + add("commonMainImplementation", libs.findLibrary("koin.annotations").get()) + add("kspCommonMainMetadata", libs.findLibrary("koin.ksp.compiler").get()) + add("ksp", libs.findLibrary("koin.ksp.compiler").get()) +// add("kspWasmJs", libs.findLibrary("koin.ksp.compiler").get()) +// add("kspJvm", libs.findLibrary("koin.ksp.compiler").get()) +// add("kspIosX64", libs.findLibrary("koin.ksp.compiler").get()) +// add("kspIosArm64", libs.findLibrary("koin.ksp.compiler").get()) +// add("kspIosSimulatorArm64", libs.findLibrary("koin.ksp.compiler").get()) + + add("commonTestImplementation", libs.findLibrary("koin.test").get()) + } + + extensions.configure { + arg("KOIN_CONFIG_CHECK","true") + arg("USE_COMPOSE_VIEWMODEL", "false") + arg("KOIN_USE_COMPOSE_VIEWMODEL", "true") + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt new file mode 100644 index 000000000..678e698f2 --- /dev/null +++ b/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt @@ -0,0 +1,41 @@ + +import com.android.build.gradle.LibraryExtension +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.dependencies +import org.mifospay.configureFlavors +import org.mifospay.configureKotlinAndroid +import org.mifospay.configureKotlinMultiplatform +import org.mifospay.libs + +class KMPLibraryConventionPlugin: Plugin { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply("com.android.library") + apply("org.jetbrains.kotlin.multiplatform") + apply("mifospay.kmp.koin") + apply("mifos.detekt.plugin") + apply("mifos.spotless.plugin") + apply("mifos.ktlint.plugin") + } + + configureKotlinMultiplatform() + + extensions.configure { + configureKotlinAndroid(this) + defaultConfig.targetSdk = 34 + configureFlavors(this) + // The resource prefix is derived from the module name, + // so resources inside ":core:module1" must be prefixed with "core_module1_" + resourcePrefix = path.split("""\W""".toRegex()).drop(1).distinct().joinToString(separator = "_").lowercase() + "_" + } + + dependencies { + add("commonTestImplementation", libs.findLibrary("kotlin.test").get()) + add("commonTestImplementation", libs.findLibrary("kotlinx.coroutines.test").get()) + } + } + } +} \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/KoinConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KoinConventionPlugin.kt new file mode 100644 index 000000000..0b20f8b4c --- /dev/null +++ b/build-logic/convention/src/main/kotlin/KoinConventionPlugin.kt @@ -0,0 +1,36 @@ +import com.google.devtools.ksp.gradle.KspExtension +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.dependencies +import org.mifospay.libs + + +class KoinConventionPlugin : Plugin { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply("com.google.devtools.ksp") + } + + dependencies { + val bom = libs.findLibrary("koin-bom").get() + add("implementation", platform(bom)) + add("implementation", libs.findLibrary("koin.core").get()) + + add("implementation", libs.findLibrary("koin.annotations").get()) + add("ksp", libs.findLibrary("koin.ksp.compiler").get()) + + + add("testImplementation", libs.findLibrary("koin.test").get()) + add("testImplementation", libs.findLibrary("koin.test.junit4").get()) + } + + extensions.configure { + arg("KOIN_CONFIG_CHECK","true") + arg("USE_COMPOSE_VIEWMODEL", "false") + arg("KOIN_USE_COMPOSE_VIEWMODEL", "true") + } + } + } +} diff --git a/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt new file mode 100644 index 000000000..977f01b2d --- /dev/null +++ b/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt @@ -0,0 +1,29 @@ +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.dependencies +import org.mifospay.libs + +class KotlinInjectConventionPlugin: Plugin { + override fun apply(target: Project) { + with(target) { + with(pluginManager) { + apply("com.google.devtools.ksp") + } + dependencies { + add("kspCommonMainMetadata", libs.findLibrary("kotlin.inject.compiler.ksp").get()) + add("commonMainImplementation", libs.findLibrary("kotlin.inject.runtime.kmp").get()) + // KSP will eventually have better multiplatform support and we'll be able to simply have + // `ksp libs.kotlinInject.compiler` in the dependencies block of each source set + // https://github.com/google/ksp/pull/1021 + add("kspIosX64", libs.findLibrary("kotlin.inject.compiler.ksp").get()) + add("kspIosArm64", libs.findLibrary("kotlin.inject.compiler.ksp").get()) + add("kspIosSimulatorArm64", libs.findLibrary("kotlin.inject.compiler.ksp").get()) +// add("kspWasmJs", libs.findLibrary("kotlin.inject.compiler.ksp").get()) + add("kspAndroid", libs.findLibrary("kotlin.inject.compiler.ksp").get()) + add("kspJvm", libs.findLibrary("kotlin.inject.compiler.ksp").get()) + add("kspMacosX64", libs.findLibrary("kotlin.inject.compiler.ksp").get()) + add("kspMacosArm64", libs.findLibrary("kotlin.inject.compiler.ksp").get()) + } + } + } +} \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/org/mifospay/AndroidCompose.kt b/build-logic/convention/src/main/kotlin/org/mifospay/AndroidCompose.kt index 888bb2c43..8b48e4b77 100644 --- a/build-logic/convention/src/main/kotlin/org/mifospay/AndroidCompose.kt +++ b/build-logic/convention/src/main/kotlin/org/mifospay/AndroidCompose.kt @@ -58,7 +58,5 @@ internal fun Project.configureAndroidCompose( .let(reportsDestination::set) stabilityConfigurationFile = rootProject.layout.projectDirectory.file("compose_compiler_config.conf") - - enableStrongSkippingMode = true } } \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/org/mifospay/KotlinAndroid.kt b/build-logic/convention/src/main/kotlin/org/mifospay/KotlinAndroid.kt index bd39d9387..d05ebad92 100644 --- a/build-logic/convention/src/main/kotlin/org/mifospay/KotlinAndroid.kt +++ b/build-logic/convention/src/main/kotlin/org/mifospay/KotlinAndroid.kt @@ -10,9 +10,6 @@ import org.gradle.kotlin.dsl.dependencies import org.gradle.kotlin.dsl.provideDelegate import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension -import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension -import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension import org.jetbrains.kotlin.gradle.tasks.KotlinCompile /** @@ -37,7 +34,7 @@ internal fun Project.configureKotlinAndroid( } } - configureKotlin() + configureKotlin() dependencies { add("coreLibraryDesugaring", libs.findLibrary("android.desugarJdkLibs").get()) @@ -55,29 +52,26 @@ internal fun Project.configureKotlinJvm() { targetCompatibility = JavaVersion.VERSION_17 } - configureKotlin() + configureKotlin() } /** * Configure base Kotlin options */ -private inline fun Project.configureKotlin() = configure { - // Treat all Kotlin warnings as errors (disabled by default) - // Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties - val warningsAsErrors: String? by project - when (this) { - is KotlinAndroidProjectExtension -> compilerOptions - is KotlinJvmProjectExtension -> compilerOptions - else -> TODO("Unsupported project extension $this ${T::class}") - }.apply { - jvmTarget = JvmTarget.JVM_17 - allWarningsAsErrors = warningsAsErrors.toBoolean() - freeCompilerArgs.add( - // Enable experimental coroutines APIs, including Flow - "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", - ) - freeCompilerArgs.add( - "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api" - ) +private fun Project.configureKotlin() { + // Use withType to workaround https://youtrack.jetbrains.com/issue/KT-55947 + tasks.withType().configureEach { + compilerOptions { + // Set JVM target to 17 + jvmTarget = JvmTarget.JVM_17 + // Treat all Kotlin warnings as errors (disabled by default) + // Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties + val warningsAsErrors: String? by project + allWarningsAsErrors = warningsAsErrors.toBoolean() + freeCompilerArgs.add( + // Enable experimental coroutines APIs, including Flow + "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi", + ) + } } -} +} \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt b/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt new file mode 100644 index 000000000..9d6ee74bf --- /dev/null +++ b/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt @@ -0,0 +1,33 @@ +package org.mifospay + +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension + +@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class) +internal fun Project.configureKotlinMultiplatform() { + extensions.configure { + applyDefaultHierarchyTemplate() + + jvm() + androidTarget() + iosSimulatorArm64() + iosX64() + iosArm64() + + // Suppress 'expect'/'actual' classes are in Beta. + targets.configureEach { + compilations.configureEach { + compilerOptions.configure { + freeCompilerArgs.addAll("-Xexpect-actual-classes") + } + } + } + + // Fixes Cannot locate tasks that match ':core:model:testClasses' as task 'testClasses' + // not found in project ':core:model'. Some candidates are: 'jsTestClasses', 'jvmTestClasses'. + project.tasks.create("testClasses") { + dependsOn("allTests") + } + } +} \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/org/mifospay/ProjectExtensions.kt b/build-logic/convention/src/main/kotlin/org/mifospay/ProjectExtensions.kt index 28fd88c0c..7bb67b857 100644 --- a/build-logic/convention/src/main/kotlin/org/mifospay/ProjectExtensions.kt +++ b/build-logic/convention/src/main/kotlin/org/mifospay/ProjectExtensions.kt @@ -11,6 +11,9 @@ import org.gradle.kotlin.dsl.getByType val Project.libs get(): VersionCatalog = extensions.getByType().named("libs") +val Project.dynamicVersion + get() = project.version.toString().split('+')[0] + inline fun Project.detektGradle(crossinline configure: DetektExtension.() -> Unit) = extensions.configure { configure() diff --git a/build.gradle.kts b/build.gradle.kts index 455b4e37b..77c7dd5ed 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -18,7 +18,6 @@ plugins { alias(libs.plugins.firebase.crashlytics) apply false alias(libs.plugins.firebase.perf) apply false alias(libs.plugins.gms) apply false - alias(libs.plugins.hilt) apply false alias(libs.plugins.ksp) apply false alias(libs.plugins.roborazzi) apply false alias(libs.plugins.secrets) apply false @@ -34,11 +33,18 @@ plugins { alias(libs.plugins.compose.compiler) apply false alias(libs.plugins.kotlinMultiplatform) apply false alias(libs.plugins.wire) apply false + alias(libs.plugins.ktrofit) apply false } -tasks.register("versionFile").configure { - group = "publishing" - doLast { - File(projectDir, "version.txt").writeText(project.version.toString()) +object DynamicVersion { + fun setDynamicVersion(file: File, version: String) { + val cleanedVersion = version.split('+')[0] + file.writeText(cleanedVersion) } +} + +tasks.register("versionFile") { + val file = File(projectDir, "version.txt") + + DynamicVersion.setDynamicVersion(file, project.version.toString()) } \ No newline at end of file diff --git a/core/analytics/build.gradle.kts b/core/analytics/build.gradle.kts index 31c708758..0059b3e4d 100644 --- a/core/analytics/build.gradle.kts +++ b/core/analytics/build.gradle.kts @@ -8,18 +8,23 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.library) - alias(libs.plugins.mifospay.android.library.compose) - alias(libs.plugins.mifospay.android.hilt) + alias(libs.plugins.mifospay.kmp.library) + alias(libs.plugins.jetbrainsCompose) + alias(libs.plugins.compose.compiler) } android { namespace = "org.mifospay.core.analytics" } -dependencies { - implementation(libs.androidx.compose.runtime) - - implementation(platform(libs.firebase.bom)) - implementation(libs.firebase.analytics) -} +kotlin { + sourceSets { + commonMain.dependencies { + implementation(compose.runtime) + } + androidMain.dependencies { + implementation(project.dependencies.platform(libs.firebase.bom)) + implementation(libs.firebase.analytics) + } + } +} \ No newline at end of file diff --git a/core/analytics/src/main/AndroidManifest.xml b/core/analytics/src/androidMain/kotlin/AndroidManifest.xml similarity index 100% rename from core/analytics/src/main/AndroidManifest.xml rename to core/analytics/src/androidMain/kotlin/AndroidManifest.xml diff --git a/core/analytics/src/main/kotlin/org/mifospay/core/analytics/AnalyticsEvent.kt b/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/AnalyticsEvent.kt similarity index 100% rename from core/analytics/src/main/kotlin/org/mifospay/core/analytics/AnalyticsEvent.kt rename to core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/AnalyticsEvent.kt diff --git a/core/analytics/src/main/kotlin/org/mifospay/core/analytics/AnalyticsHelper.kt b/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/AnalyticsHelper.kt similarity index 100% rename from core/analytics/src/main/kotlin/org/mifospay/core/analytics/AnalyticsHelper.kt rename to core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/AnalyticsHelper.kt diff --git a/core/analytics/src/main/kotlin/org/mifospay/core/analytics/NoOpAnalyticsHelper.kt b/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/NoOpAnalyticsHelper.kt similarity index 100% rename from core/analytics/src/main/kotlin/org/mifospay/core/analytics/NoOpAnalyticsHelper.kt rename to core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/NoOpAnalyticsHelper.kt diff --git a/core/analytics/src/main/kotlin/org/mifospay/core/analytics/StubAnalyticsHelper.kt b/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/StubAnalyticsHelper.kt similarity index 82% rename from core/analytics/src/main/kotlin/org/mifospay/core/analytics/StubAnalyticsHelper.kt rename to core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/StubAnalyticsHelper.kt index 6cbc75920..d3afcd9e0 100644 --- a/core/analytics/src/main/kotlin/org/mifospay/core/analytics/StubAnalyticsHelper.kt +++ b/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/StubAnalyticsHelper.kt @@ -10,8 +10,6 @@ package org.mifospay.core.analytics import android.util.Log -import javax.inject.Inject -import javax.inject.Singleton private const val TAG = "StubAnalyticsHelper" @@ -19,8 +17,7 @@ private const val TAG = "StubAnalyticsHelper" * An implementation of AnalyticsHelper just writes the events to logcat. Used in builds where no * analytics events should be sent to a backend. */ -@Singleton -internal class StubAnalyticsHelper @Inject constructor() : AnalyticsHelper { +internal class StubAnalyticsHelper : AnalyticsHelper { override fun logEvent(event: AnalyticsEvent) { Log.d(TAG, "Received analytics event: $event") } diff --git a/core/analytics/src/main/kotlin/org/mifospay/core/analytics/UiHelpers.kt b/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/UiHelpers.kt similarity index 100% rename from core/analytics/src/main/kotlin/org/mifospay/core/analytics/UiHelpers.kt rename to core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/UiHelpers.kt diff --git a/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/di/AnalyticsModule.kt b/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/di/AnalyticsModule.kt new file mode 100644 index 000000000..472f15c95 --- /dev/null +++ b/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/di/AnalyticsModule.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.analytics.di + +import com.google.firebase.analytics.ktx.analytics +import com.google.firebase.ktx.Firebase +import org.koin.dsl.module +import org.mifospay.core.analytics.AnalyticsHelper + +val AnalyticsModule = module { + + single { + Firebase.analytics + } + single { + FirebaseAnalyticsHelper(firebaseAnalytics = get()) + } +} diff --git a/core/analytics/src/main/kotlin/org/mifospay/core/analytics/di/FirebaseAnalyticsHelper.kt b/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/di/FirebaseAnalyticsHelper.kt similarity index 92% rename from core/analytics/src/main/kotlin/org/mifospay/core/analytics/di/FirebaseAnalyticsHelper.kt rename to core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/di/FirebaseAnalyticsHelper.kt index f3e5aae63..326f296fa 100644 --- a/core/analytics/src/main/kotlin/org/mifospay/core/analytics/di/FirebaseAnalyticsHelper.kt +++ b/core/analytics/src/androidMain/kotlin/org/mifospay/core/analytics/di/FirebaseAnalyticsHelper.kt @@ -13,12 +13,11 @@ import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.analytics.logEvent import org.mifospay.core.analytics.AnalyticsEvent import org.mifospay.core.analytics.AnalyticsHelper -import javax.inject.Inject /** * Implementation of `AnalyticsHelper` which logs events to a Firebase backend. */ -internal class FirebaseAnalyticsHelper @Inject constructor( +internal class FirebaseAnalyticsHelper( private val firebaseAnalytics: FirebaseAnalytics, ) : AnalyticsHelper { diff --git a/core/analytics/src/main/kotlin/org/mifospay/core/analytics/di/AnalyticsModule.kt b/core/analytics/src/main/kotlin/org/mifospay/core/analytics/di/AnalyticsModule.kt deleted file mode 100644 index dcd9ece82..000000000 --- a/core/analytics/src/main/kotlin/org/mifospay/core/analytics/di/AnalyticsModule.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.analytics.di - -import com.google.firebase.analytics.FirebaseAnalytics -import com.google.firebase.analytics.ktx.analytics -import com.google.firebase.ktx.Firebase -import dagger.Binds -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import org.mifospay.core.analytics.AnalyticsHelper -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -internal abstract class AnalyticsModule { - @Binds - abstract fun bindsAnalyticsHelper(analyticsHelperImpl: FirebaseAnalyticsHelper): AnalyticsHelper - - companion object { - @Provides - @Singleton - fun provideFirebaseAnalytics(): FirebaseAnalytics { - return Firebase.analytics - } - } -} diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index 5e84d21ee..20720cc5f 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -8,12 +8,27 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.library) - alias(libs.plugins.mifospay.android.hilt) + alias(libs.plugins.mifospay.kmp.library) } android { namespace = "org.mifospay.common" } -dependencies {} +kotlin { + sourceSets { + commonMain.dependencies { + implementation(libs.kotlinx.coroutines.core) + api(libs.coil.kt) + api(libs.coil.core) + api(libs.coil.svg) + api(libs.coil.network.ktor) + } + androidMain.dependencies { + implementation(libs.kotlinx.coroutines.android) + } + commonTest.dependencies { + implementation(libs.kotlinx.coroutines.test) + } + } +} \ No newline at end of file diff --git a/core/common/src/main/AndroidManifest.xml b/core/common/src/androidMain/AndroidManifest.xml similarity index 100% rename from core/common/src/main/AndroidManifest.xml rename to core/common/src/androidMain/AndroidManifest.xml diff --git a/core/common/src/main/kotlin/org/mifospay/common/Constants.kt b/core/common/src/androidMain/kotlin/org/mifospay/common/Constants.kt similarity index 100% rename from core/common/src/main/kotlin/org/mifospay/common/Constants.kt rename to core/common/src/androidMain/kotlin/org/mifospay/common/Constants.kt diff --git a/core/common/src/main/kotlin/org/mifospay/common/CreditCardUtils.kt b/core/common/src/androidMain/kotlin/org/mifospay/common/CreditCardUtils.kt similarity index 100% rename from core/common/src/main/kotlin/org/mifospay/common/CreditCardUtils.kt rename to core/common/src/androidMain/kotlin/org/mifospay/common/CreditCardUtils.kt diff --git a/core/common/src/main/kotlin/org/mifospay/common/DebugUtil.kt b/core/common/src/androidMain/kotlin/org/mifospay/common/DebugUtil.kt similarity index 100% rename from core/common/src/main/kotlin/org/mifospay/common/DebugUtil.kt rename to core/common/src/androidMain/kotlin/org/mifospay/common/DebugUtil.kt diff --git a/core/common/src/main/kotlin/org/mifospay/common/FileUtils.kt b/core/common/src/androidMain/kotlin/org/mifospay/common/FileUtils.kt similarity index 100% rename from core/common/src/main/kotlin/org/mifospay/common/FileUtils.kt rename to core/common/src/androidMain/kotlin/org/mifospay/common/FileUtils.kt diff --git a/core/common/src/main/kotlin/org/mifospay/common/NavArgsConstants.kt b/core/common/src/androidMain/kotlin/org/mifospay/common/NavArgsConstants.kt similarity index 100% rename from core/common/src/main/kotlin/org/mifospay/common/NavArgsConstants.kt rename to core/common/src/androidMain/kotlin/org/mifospay/common/NavArgsConstants.kt diff --git a/core/common/src/main/kotlin/org/mifospay/common/Utils.kt b/core/common/src/androidMain/kotlin/org/mifospay/common/Utils.kt similarity index 100% rename from core/common/src/main/kotlin/org/mifospay/common/Utils.kt rename to core/common/src/androidMain/kotlin/org/mifospay/common/Utils.kt diff --git a/core/common/src/main/kotlin/org/mifospay/core/network/MifosDispatchers.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/network/MifosDispatchers.kt similarity index 74% rename from core/common/src/main/kotlin/org/mifospay/core/network/MifosDispatchers.kt rename to core/common/src/androidMain/kotlin/org/mifospay/core/network/MifosDispatchers.kt index 234708415..3122bf45b 100644 --- a/core/common/src/main/kotlin/org/mifospay/core/network/MifosDispatchers.kt +++ b/core/common/src/androidMain/kotlin/org/mifospay/core/network/MifosDispatchers.kt @@ -9,14 +9,17 @@ */ package org.mifospay.core.network -import javax.inject.Qualifier -import kotlin.annotation.AnnotationRetention.RUNTIME +import org.koin.core.annotation.Qualifier @Qualifier -@Retention(RUNTIME) +@Retention(AnnotationRetention.RUNTIME) annotation class Dispatcher(val mifosDispatcher: MifosDispatchers) enum class MifosDispatchers { Default, IO, } + +@Qualifier +@Retention(AnnotationRetention.RUNTIME) +annotation class ApplicationScope diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt new file mode 100644 index 000000000..501cf3b80 --- /dev/null +++ b/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.di + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import org.koin.core.qualifier.named +import org.koin.dsl.module + +val CoroutineScopesModule = module { + + single(named("ApplicationScope")) { + CoroutineScope(SupervisorJob() + Dispatchers.Default) + } +} diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/DispatchersModule.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/DispatchersModule.kt new file mode 100644 index 000000000..9ad058f96 --- /dev/null +++ b/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/DispatchersModule.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.di + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.network.MifosDispatchers + +val DispatchersModule = module { + single(named(MifosDispatchers.IO.name)) { Dispatchers.IO } + single(named(MifosDispatchers.Default.name)) { Dispatchers.Default } +} diff --git a/core/common/src/main/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt b/core/common/src/main/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt deleted file mode 100644 index 025c12a65..000000000 --- a/core/common/src/main/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.di - -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import org.mifospay.core.network.Dispatcher -import org.mifospay.core.network.MifosDispatchers.Default -import javax.inject.Qualifier -import javax.inject.Singleton - -@Retention(AnnotationRetention.RUNTIME) -@Qualifier -annotation class ApplicationScope - -@Module -@InstallIn(SingletonComponent::class) -internal object CoroutineScopesModule { - @Provides - @Singleton - @ApplicationScope - fun providesCoroutineScope( - @Dispatcher(Default) dispatcher: CoroutineDispatcher, - ): CoroutineScope = CoroutineScope(SupervisorJob() + dispatcher) -} diff --git a/core/common/src/main/kotlin/org/mifospay/core/network/di/DispatchersModule.kt b/core/common/src/main/kotlin/org/mifospay/core/network/di/DispatchersModule.kt deleted file mode 100644 index 98b34f703..000000000 --- a/core/common/src/main/kotlin/org/mifospay/core/network/di/DispatchersModule.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.di - -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.Dispatchers -import org.mifospay.core.network.Dispatcher -import org.mifospay.core.network.MifosDispatchers.Default -import org.mifospay.core.network.MifosDispatchers.IO - -@Module -@InstallIn(SingletonComponent::class) -object DispatchersModule { - @Provides - @Dispatcher(IO) - fun providesIODispatcher(): CoroutineDispatcher = Dispatchers.IO - - @Provides - @Dispatcher(Default) - fun providesDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default -} diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts index 41831e43d..36ec8ba1f 100644 --- a/core/data/build.gradle.kts +++ b/core/data/build.gradle.kts @@ -8,8 +8,7 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.library) - alias(libs.plugins.mifospay.android.hilt) + alias(libs.plugins.mifospay.kmp.library) alias(libs.plugins.kotlin.parcelize) id("kotlinx-serialization") } @@ -24,23 +23,27 @@ android { } } -dependencies { - api(projects.core.common) - api(projects.core.model) - api(projects.core.network) +kotlin { + sourceSets { + commonMain.dependencies { + api(projects.core.common) + api(projects.core.datastore) + api(projects.core.network) + api(projects.core.model) - implementation(libs.squareup.retrofit2) { - // exclude Retrofit’s OkHttp peer-dependency module and define your own module import - exclude(module = "okhttp") - } - implementation(libs.squareup.retrofit.adapter.rxjava) - implementation(libs.squareup.retrofit.converter.gson) - implementation(libs.squareup.okhttp) - implementation(libs.squareup.logging.interceptor) + implementation(projects.core.analytics) + } - implementation(libs.reactivex.rxjava.android) - implementation(libs.reactivex.rxjava) + commonTest.dependencies { + implementation(libs.multiplatform.settings) + implementation(libs.multiplatform.settings.test) + implementation(libs.kotlinx.serialization.json) + } - testImplementation(libs.junit) - androidTestImplementation(libs.espresso.core) -} + androidMain.dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.tracing.ktx) + implementation(libs.koin.android) + } + } +} \ No newline at end of file diff --git a/core/data/src/main/AndroidManifest.xml b/core/data/src/androidMain/AndroidManifest.xml similarity index 100% rename from core/data/src/main/AndroidManifest.xml rename to core/data/src/androidMain/AndroidManifest.xml diff --git a/core/data/src/main/assets/banks.json b/core/data/src/androidMain/assets/banks.json similarity index 100% rename from core/data/src/main/assets/banks.json rename to core/data/src/androidMain/assets/banks.json diff --git a/core/data/src/main/assets/cities.json b/core/data/src/androidMain/assets/cities.json similarity index 100% rename from core/data/src/main/assets/cities.json rename to core/data/src/androidMain/assets/cities.json diff --git a/core/data/src/main/assets/countriesToCities.json b/core/data/src/androidMain/assets/countriesToCities.json similarity index 100% rename from core/data/src/main/assets/countriesToCities.json rename to core/data/src/androidMain/assets/countriesToCities.json diff --git a/core/data/src/main/java/org/mifospay/core/data/base/TaskLooper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/TaskLooper.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/base/TaskLooper.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/base/TaskLooper.kt index 175b2da3a..6fa7abbf7 100644 --- a/core/data/src/main/java/org/mifospay/core/data/base/TaskLooper.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/base/TaskLooper.kt @@ -10,9 +10,8 @@ package org.mifospay.core.data.base import org.mifospay.core.data.base.UseCase.UseCaseCallback -import javax.inject.Inject -class TaskLooper @Inject constructor( +class TaskLooper( private val mUseCaseHandler: UseCaseHandler, ) { var isFailed = false diff --git a/core/data/src/main/java/org/mifospay/core/data/base/ThreadPoolQueue.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/ThreadPoolQueue.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/base/ThreadPoolQueue.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/base/ThreadPoolQueue.kt diff --git a/core/data/src/main/java/org/mifospay/core/data/base/UseCase.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCase.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/base/UseCase.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/base/UseCase.kt diff --git a/core/data/src/main/java/org/mifospay/core/data/base/UseCaseFactory.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseFactory.kt similarity index 93% rename from core/data/src/main/java/org/mifospay/core/data/base/UseCaseFactory.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseFactory.kt index ea1eb6bb7..d7f6b510b 100644 --- a/core/data/src/main/java/org/mifospay/core/data/base/UseCaseFactory.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseFactory.kt @@ -13,9 +13,8 @@ import org.mifospay.core.data.domain.usecase.account.FetchAccountTransfer import org.mifospay.core.data.domain.usecase.client.FetchClientDetails import org.mifospay.core.data.fineract.repository.FineractRepository import org.mifospay.core.data.util.Constants -import javax.inject.Inject -class UseCaseFactory @Inject constructor( +class UseCaseFactory( private val mFineractRepository: FineractRepository, ) { fun getUseCase(useCase: String): UseCase<*, *>? { diff --git a/core/data/src/main/java/org/mifospay/core/data/base/UseCaseHandler.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseHandler.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/base/UseCaseHandler.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseHandler.kt diff --git a/core/data/src/main/java/org/mifospay/core/data/base/UseCaseScheduler.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseScheduler.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/base/UseCaseScheduler.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseScheduler.kt diff --git a/core/data/src/main/java/org/mifospay/core/data/base/UseCaseThreadPoolScheduler.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseThreadPoolScheduler.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/base/UseCaseThreadPoolScheduler.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseThreadPoolScheduler.kt diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/di/DataModule.kt b/core/data/src/androidMain/java/org/mifospay/core/data/di/DataModule.kt new file mode 100644 index 000000000..e498908c9 --- /dev/null +++ b/core/data/src/androidMain/java/org/mifospay/core/data/di/DataModule.kt @@ -0,0 +1,214 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.di + +import org.koin.android.ext.koin.androidContext +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifos.core.network.localAssets.LocalAssetDataSource +import org.mifospay.core.data.base.TaskLooper +import org.mifospay.core.data.base.UseCaseFactory +import org.mifospay.core.data.base.UseCaseHandler +import org.mifospay.core.data.base.UseCaseScheduler +import org.mifospay.core.data.base.UseCaseThreadPoolScheduler +import org.mifospay.core.data.domain.usecase.account.BlockUnblockCommand +import org.mifospay.core.data.domain.usecase.account.DownloadTransactionReceipt +import org.mifospay.core.data.domain.usecase.account.FetchAccount +import org.mifospay.core.data.domain.usecase.account.FetchAccountTransaction +import org.mifospay.core.data.domain.usecase.account.FetchAccountTransactions +import org.mifospay.core.data.domain.usecase.account.FetchAccountTransfer +import org.mifospay.core.data.domain.usecase.account.FetchAccounts +import org.mifospay.core.data.domain.usecase.account.FetchMerchants +import org.mifospay.core.data.domain.usecase.account.TransferFunds +import org.mifospay.core.data.domain.usecase.client.CreateClient +import org.mifospay.core.data.domain.usecase.client.FetchClientData +import org.mifospay.core.data.domain.usecase.client.FetchClientDetails +import org.mifospay.core.data.domain.usecase.client.FetchClientImage +import org.mifospay.core.data.domain.usecase.client.SearchClient +import org.mifospay.core.data.domain.usecase.client.UpdateClient +import org.mifospay.core.data.domain.usecase.history.TransactionsHistory +import org.mifospay.core.data.domain.usecase.invoice.FetchInvoice +import org.mifospay.core.data.domain.usecase.invoice.FetchInvoices +import org.mifospay.core.data.domain.usecase.kyc.FetchKYCLevel1Details +import org.mifospay.core.data.domain.usecase.kyc.UpdateKYCLevel1Details +import org.mifospay.core.data.domain.usecase.kyc.UploadKYCDocs +import org.mifospay.core.data.domain.usecase.kyc.UploadKYCLevel1Details +import org.mifospay.core.data.domain.usecase.notification.FetchNotifications +import org.mifospay.core.data.domain.usecase.savedcards.AddCard +import org.mifospay.core.data.domain.usecase.savedcards.DeleteCard +import org.mifospay.core.data.domain.usecase.savedcards.EditCard +import org.mifospay.core.data.domain.usecase.savedcards.FetchSavedCards +import org.mifospay.core.data.domain.usecase.standinginstruction.CreateStandingTransaction +import org.mifospay.core.data.domain.usecase.standinginstruction.DeleteStandingInstruction +import org.mifospay.core.data.domain.usecase.standinginstruction.FetchStandingInstruction +import org.mifospay.core.data.domain.usecase.standinginstruction.GetAllStandingInstructions +import org.mifospay.core.data.domain.usecase.standinginstruction.UpdateStandingInstruction +import org.mifospay.core.data.domain.usecase.twofactor.FetchDeliveryMethods +import org.mifospay.core.data.domain.usecase.twofactor.RequestOTP +import org.mifospay.core.data.domain.usecase.twofactor.ValidateOTP +import org.mifospay.core.data.domain.usecase.user.AuthenticateUser +import org.mifospay.core.data.domain.usecase.user.CreateUser +import org.mifospay.core.data.domain.usecase.user.DeleteUser +import org.mifospay.core.data.domain.usecase.user.FetchUserDetails +import org.mifospay.core.data.domain.usecase.user.FetchUsers +import org.mifospay.core.data.domain.usecase.user.RegisterUser +import org.mifospay.core.data.domain.usecase.user.UpdateUser +import org.mifospay.core.data.domain.usecase.user.VerifyUser +import org.mifospay.core.data.fineract.entity.mapper.AccountMapper +import org.mifospay.core.data.fineract.entity.mapper.ClientDetailsMapper +import org.mifospay.core.data.fineract.entity.mapper.CurrencyMapper +import org.mifospay.core.data.fineract.entity.mapper.SearchedEntitiesMapper +import org.mifospay.core.data.fineract.entity.mapper.TransactionMapper +import org.mifospay.core.data.fineract.repository.FineractRepository +import org.mifospay.core.data.repository.auth.AuthenticationUserRepository +import org.mifospay.core.data.repository.auth.UserDataRepository +import org.mifospay.core.data.repository.local.LocalAssetRepository +import org.mifospay.core.data.repository.local.LocalRepository +import org.mifospay.core.data.repository.local.MifosLocalAssetRepository +import org.mifospay.core.data.util.ConnectivityManagerNetworkMonitor +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneBroadcastMonitor +import org.mifospay.core.data.util.TimeZoneMonitor +import org.mifospay.core.datastore.PreferencesHelper +import org.mifospay.core.network.MifosDispatchers +import org.mifospay.core.network.di.LocalModule +import org.mifospay.core.network.localAssets.MifosLocalAssetDataSource + +val DataModule = module { + includes(LocalModule) + + single { UseCaseThreadPoolScheduler() } + single { UseCaseHandler(get()) } + single { TaskLooper(get()) } + single { UseCaseFactory(get()) } + single { FetchClientData(get(), get()) } + single { ClientDetailsMapper() } + single { SearchClient(get(), get()) } + single { UpdateClient(get()) } + single { CreateClient(get()) } + single { FetchClientDetails(get()) } + single { FetchClientImage(get()) } + single { BlockUnblockCommand(get()) } + single { DownloadTransactionReceipt(get()) } + single { AccountMapper(get()) } + single { FetchAccount(get(), get()) } + single { FetchAccounts(get(), get()) } + single { FetchAccountTransaction(get(), get()) } + single { FetchAccountTransactions(get(), get()) } + single { FetchAccountTransfer(get()) } + single { FetchMerchants(get()) } + single { TransferFunds(get()) } + single { + TransactionsHistory( + mUseCaseHandler = get(), + fetchAccountTransactionsUseCase = get(), + ) + } + + // Invoice UseCase + single { FetchInvoice(get()) } + single { FetchInvoices(get()) } + + // KYC UseCase + single { FetchKYCLevel1Details(get()) } + single { UpdateKYCLevel1Details(get()) } + single { UploadKYCDocs(get()) } + single { UploadKYCLevel1Details(get()) } + + // Notifications + single { FetchNotifications(get()) } + + // Saved Cards + single { AddCard(get()) } + single { DeleteCard(get()) } + single { EditCard(get()) } + single { FetchSavedCards(get()) } + + // Standing Instructions + single { CreateStandingTransaction(get()) } + single { DeleteStandingInstruction(get()) } + single { FetchStandingInstruction(get()) } + single { GetAllStandingInstructions(get()) } + single { UpdateStandingInstruction(get()) } + + // Two-Factor + single { FetchDeliveryMethods(get()) } + single { RequestOTP(get()) } + single { ValidateOTP(get()) } + + // User + single { AuthenticateUser(get()) } + single { CreateUser(get()) } + single { DeleteUser(get()) } + single { FetchUserDetails(get()) } + single { FetchUsers(get()) } + single { RegisterUser(get()) } + single { UpdateUser(get()) } + single { VerifyUser(get()) } + + // Fineract Entity Mappers + single { CurrencyMapper() } + single { SearchedEntitiesMapper() } + single { TransactionMapper(get()) } + single { AccountMapper(get()) } + single { ClientDetailsMapper() } + + // Fineract Repository + + single { + FineractRepository( + fineractApiManager = get(), + selfApiManager = get(), + ktorAuthenticationService = get(), + ) + } + + // Fineract Repository Auth + + single { AuthenticationUserRepository(get()) } + + // Fineract Repository Local + + single { + val preferencesHelper: PreferencesHelper = get() + LocalRepository(preferencesHelper) + } + + factory { + MifosLocalAssetDataSource( + ioDispatcher = get( + named(MifosDispatchers.IO.name), + ), + networkJson = get(), + assets = get(), + ) + } + + factory { + MifosLocalAssetRepository( + ioDispatcher = get( + named(MifosDispatchers.IO.name), + ), + datasource = get(), + ) + } + + // Util + + single { ConnectivityManagerNetworkMonitor(context = androidContext()) } + + single { + TimeZoneBroadcastMonitor( + context = androidContext(), + appScope = get(named("ApplicationScope")), + ioDispatcher = get(named(MifosDispatchers.IO.name)), + ) + } +} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/di/LocalDataModule.kt b/core/data/src/androidMain/java/org/mifospay/core/data/di/LocalDataModule.kt new file mode 100644 index 000000000..87be810d2 --- /dev/null +++ b/core/data/src/androidMain/java/org/mifospay/core/data/di/LocalDataModule.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.di + +import androidx.lifecycle.SavedStateHandle +import org.koin.dsl.module + +val LocalDataModule = module { + factory { + SavedStateHandle() + } +} diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt index 1185fba19..45075fd22 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt @@ -16,9 +16,8 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.fineract.repository.FineractRepository -import javax.inject.Inject -class BlockUnblockCommand @Inject constructor( +class BlockUnblockCommand( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt index f6bc1058f..36d955040 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt @@ -16,9 +16,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class DownloadTransactionReceipt @Inject constructor( +class DownloadTransactionReceipt( private val mFineractRepository: FineractRepository, ) : UseCase() { override fun executeUseCase(requestValues: RequestValues) { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt similarity index 97% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt index 314e4deff..4bc88a5e1 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt @@ -18,9 +18,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchAccount @Inject constructor( +class FetchAccount( private val fineractRepository: FineractRepository, private val accountMapper: AccountMapper, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt index 52c917278..6ad743a05 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt @@ -19,9 +19,8 @@ import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.fineract.entity.mapper.TransactionMapper import org.mifospay.core.data.fineract.repository.FineractRepository import org.mifospay.core.data.util.Constants -import javax.inject.Inject -class FetchAccountTransaction @Inject constructor( +class FetchAccountTransaction( private val fineractRepository: FineractRepository, private val transactionMapper: TransactionMapper, ) : diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt index 9504ee9ee..7ab0830d4 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt @@ -19,9 +19,8 @@ import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.fineract.entity.mapper.TransactionMapper import org.mifospay.core.data.fineract.repository.FineractRepository import org.mifospay.core.data.util.Constants -import javax.inject.Inject -class FetchAccountTransactions @Inject constructor( +class FetchAccountTransactions( private val fineractRepository: FineractRepository, private val transactionMapper: TransactionMapper, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt index 05890a5b3..78cc231a7 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt @@ -15,9 +15,8 @@ import org.mifospay.core.data.fineract.repository.FineractRepository import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchAccountTransfer @Inject constructor( +class FetchAccountTransfer( private val mFineractRepository: FineractRepository, ) : UseCase() { override fun executeUseCase(requestValues: RequestValues) { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt index 60895b71d..9b3b4732f 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt @@ -18,9 +18,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchAccounts @Inject constructor( +class FetchAccounts( private val fineractRepository: FineractRepository, private val accountMapper: AccountMapper, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt index 2d255f28f..57bdbba0a 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt @@ -18,9 +18,8 @@ import kotlinx.coroutines.withContext import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.fineract.repository.FineractRepository import org.mifospay.core.data.util.Constants -import javax.inject.Inject -class FetchMerchants @Inject constructor( +class FetchMerchants( private val mFineractRepository: FineractRepository, ) : UseCase() { override fun executeUseCase(requestValues: RequestValues) { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt similarity index 99% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt index fdb32c9b2..ec3efb669 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt @@ -25,10 +25,9 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject @Suppress("UnusedPrivateMember") -class TransferFunds @Inject constructor( +class TransferFunds( private val apiRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt index 64246586f..fd84e1477 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt @@ -17,9 +17,8 @@ import retrofit2.HttpException import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class CreateClient @Inject constructor( +class CreateClient( private val apiRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt index 2d74601ce..ad588cd33 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt @@ -18,15 +18,12 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchClientData @Inject constructor( +class FetchClientData( private val fineractRepository: FineractRepository, + private val clientDetailsMapper: ClientDetailsMapper, ) : UseCase() { - @Inject - lateinit var clientDetailsMapper: ClientDetailsMapper - override fun executeUseCase(requestValues: RequestValues) { requestValues.clientId?.let { clientId -> fineractRepository.getSelfClientDetails(clientId) diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt index 7728aeee4..3ab9b074f 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt @@ -16,9 +16,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchClientDetails @Inject constructor( +class FetchClientDetails( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt index db51bf3fe..90bd05665 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt @@ -16,9 +16,8 @@ import org.mifospay.core.data.util.ErrorJsonMessageHelper.getUserMessage import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchClientImage @Inject constructor( +class FetchClientImage( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt similarity index 93% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt index 4cf55ef81..05b882da0 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt @@ -18,15 +18,12 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class SearchClient @Inject constructor( +class SearchClient( private val apiRepository: FineractRepository, + private val searchedEntitiesMapper: SearchedEntitiesMapper, ) : UseCase() { - @Inject - lateinit var searchedEntitiesMapper: SearchedEntitiesMapper - data class RequestValues(val externalId: String) : UseCase.RequestValues data class ResponseValue(val results: List) : UseCase.ResponseValue diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt similarity index 97% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt index c6d533071..6badef3e6 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt @@ -17,9 +17,8 @@ import retrofit2.HttpException import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class UpdateClient @Inject constructor( +class UpdateClient( private val fineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/history/HistoryContract.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/HistoryContract.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/history/HistoryContract.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/HistoryContract.kt diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt similarity index 83% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt index 5253742b2..10e105b76 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt @@ -10,26 +10,15 @@ package org.mifospay.core.data.domain.usecase.history import com.mifospay.core.model.domain.Transaction -import org.mifospay.core.data.base.TaskLooper import org.mifospay.core.data.base.UseCase.UseCaseCallback -import org.mifospay.core.data.base.UseCaseFactory import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.account.FetchAccountTransactions -import javax.inject.Inject -class TransactionsHistory @Inject constructor( +class TransactionsHistory( private val mUseCaseHandler: UseCaseHandler, private val fetchAccountTransactionsUseCase: FetchAccountTransactions, ) { var delegate: HistoryContract.TransactionsHistoryAsync? = null - - @JvmField - @Inject - var mTaskLooper: TaskLooper? = null - - @JvmField - @Inject - var mUseCaseFactory: UseCaseFactory? = null private var transactions: List? init { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt similarity index 97% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt index bfdcfb24e..4a6cf57ea 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt @@ -18,9 +18,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchInvoice @Inject constructor( +class FetchInvoice( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt index 50caac4f2..e9a4b5b2a 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt @@ -16,9 +16,8 @@ import org.mifospay.core.data.fineract.repository.FineractRepository import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchInvoices @Inject constructor( +class FetchInvoices( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt index 2cf235a3d..42e9d19c9 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt @@ -15,9 +15,8 @@ import org.mifospay.core.data.fineract.repository.FineractRepository import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchKYCLevel1Details @Inject constructor( +class FetchKYCLevel1Details( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt index 90b1c0d4a..6f232ca29 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt @@ -16,9 +16,8 @@ import org.mifospay.core.network.GenericResponse import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class UpdateKYCLevel1Details @Inject constructor( +class UpdateKYCLevel1Details( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt index c62971778..6eb539c1f 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt @@ -16,9 +16,8 @@ import org.mifospay.core.network.GenericResponse import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class UploadKYCDocs @Inject constructor( +class UploadKYCDocs( private val apiRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt index cf8627e6b..74ace32cb 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt @@ -16,9 +16,8 @@ import org.mifospay.core.network.GenericResponse import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class UploadKYCLevel1Details @Inject constructor( +class UploadKYCLevel1Details( var mFineractRepository: FineractRepository, ) : UseCase() { class RequestValues( diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt index 7aef23b3b..4237dc12a 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt @@ -16,9 +16,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchNotifications @Inject constructor( +class FetchNotifications( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt index 85b01ae6e..73bb2bbcc 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt @@ -16,9 +16,8 @@ import org.mifospay.core.network.GenericResponse import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class AddCard @Inject constructor( +class AddCard( private val mFineractRepository: FineractRepository, ) : UseCase() { class RequestValues(val clientId: Long, val card: Card) : UseCase.RequestValues diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt index d143d1ea4..c11cb90f0 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt @@ -15,9 +15,8 @@ import org.mifospay.core.network.GenericResponse import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class DeleteCard @Inject constructor( +class DeleteCard( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt index b27627897..7f0440b18 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt @@ -16,9 +16,8 @@ import org.mifospay.core.network.GenericResponse import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class EditCard @Inject constructor( +class EditCard( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt index 6400ae78d..8750008de 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt @@ -16,9 +16,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchSavedCards @Inject constructor( +class FetchSavedCards( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt similarity index 98% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt index 690651c9a..5e4dfd300 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt @@ -20,9 +20,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class CreateStandingTransaction @Inject constructor( +class CreateStandingTransaction( private val apiRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt index dea053f75..569a9149b 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt @@ -15,9 +15,8 @@ import org.mifospay.core.network.GenericResponse import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class DeleteStandingInstruction @Inject constructor( +class DeleteStandingInstruction( private val apiRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt index c14f2815d..8e165f333 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt @@ -15,9 +15,8 @@ import org.mifospay.core.data.fineract.repository.FineractRepository import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchStandingInstruction @Inject constructor( +class FetchStandingInstruction( private val apiRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt index cd715c479..1e4338704 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt @@ -16,9 +16,8 @@ import org.mifospay.core.data.fineract.repository.FineractRepository import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class GetAllStandingInstructions @Inject constructor( +class GetAllStandingInstructions( private val apiRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt similarity index 97% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt index 81bfc27e2..8eef580b2 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt @@ -17,9 +17,8 @@ import org.mifospay.core.network.GenericResponse import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class UpdateStandingInstruction @Inject constructor( +class UpdateStandingInstruction( private val apiRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt index 4698b3934..29cf2bb7c 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt @@ -15,9 +15,8 @@ import org.mifospay.core.data.fineract.repository.FineractRepository import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchDeliveryMethods @Inject constructor( +class FetchDeliveryMethods( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt index d2f9dc829..004806f96 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt @@ -14,9 +14,8 @@ import org.mifospay.core.data.fineract.repository.FineractRepository import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class RequestOTP @Inject constructor( +class RequestOTP( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt index 76ddc75ba..1249e58be 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt @@ -15,9 +15,8 @@ import org.mifospay.core.data.fineract.repository.FineractRepository import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class ValidateOTP @Inject constructor( +class ValidateOTP( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt index b87fb4736..c849b1261 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt @@ -18,9 +18,8 @@ import kotlinx.coroutines.withContext import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.fineract.repository.FineractRepository import org.mifospay.core.data.util.Constants -import javax.inject.Inject -class AuthenticateUser @Inject constructor( +class AuthenticateUser( private val apiRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt similarity index 94% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt index 7cbfc079b..79f056b70 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt @@ -17,9 +17,8 @@ import retrofit2.HttpException import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class CreateUser @Inject constructor(private val apiRepository: FineractRepository) : +class CreateUser(private val apiRepository: FineractRepository) : UseCase() { override fun executeUseCase(requestValues: RequestValues) { apiRepository.createUser(requestValues.user) diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt index 8bf1177c8..2a537345f 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt @@ -15,9 +15,8 @@ import org.mifospay.core.network.GenericResponse import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class DeleteUser @Inject constructor( +class DeleteUser( private val mFineractRepository: FineractRepository, ) : UseCase() { override fun executeUseCase(requestValues: RequestValues) { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt similarity index 95% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt index c019540f5..153e46ee0 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt @@ -15,9 +15,8 @@ import org.mifospay.core.data.fineract.repository.FineractRepository import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchUserDetails @Inject constructor( +class FetchUserDetails( private val mFineractRepository: FineractRepository, ) : UseCase() { override fun executeUseCase(requestValues: RequestValues) { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt index b2813e61e..61340673a 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt @@ -16,9 +16,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchUsers @Inject constructor( +class FetchUsers( private val mFineractRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt index 3eaed68e2..f37d1df98 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt @@ -17,9 +17,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class RegisterUser @Inject constructor( +class RegisterUser( private val apiRepository: FineractRepository, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt similarity index 97% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt index a53f16fda..9fac23150 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt @@ -17,9 +17,8 @@ import retrofit2.HttpException import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class UpdateUser @Inject constructor( +class UpdateUser( private val mFineractRepository: FineractRepository, ) : UseCase() { override fun executeUseCase(requestValues: RequestValues) { diff --git a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt index cd68fbb97..d946eff90 100644 --- a/core/data/src/main/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt @@ -17,9 +17,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class VerifyUser @Inject constructor( +class VerifyUser( private val apiRepository: FineractRepository, ) : UseCase() { override fun executeUseCase(requestValues: RequestValues) { diff --git a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt similarity index 94% rename from core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt index 64f21ba33..672f1a393 100644 --- a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt @@ -11,9 +11,8 @@ package org.mifospay.core.data.fineract.entity.mapper import com.mifospay.core.model.domain.Account import com.mifospay.core.model.entity.client.ClientAccounts -import javax.inject.Inject -class AccountMapper @Inject constructor( +class AccountMapper( private val currencyMapper: CurrencyMapper, ) { diff --git a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt similarity index 93% rename from core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt index 8c96d6542..eccd4a613 100644 --- a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt @@ -10,10 +10,9 @@ package org.mifospay.core.data.fineract.entity.mapper import com.mifospay.core.model.entity.client.Client -import javax.inject.Inject import com.mifospay.core.model.domain.client.Client as DomainClient -class ClientDetailsMapper @Inject constructor() { +class ClientDetailsMapper { fun transformList(clients: List?): List { val clientList: MutableList = ArrayList() clients?.forEach { client -> diff --git a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt similarity index 83% rename from core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt index a96dc6802..21270ee2d 100644 --- a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt @@ -10,13 +10,11 @@ package org.mifospay.core.data.fineract.entity.mapper import com.mifospay.core.model.entity.accounts.savings.Currency -import javax.inject.Inject import com.mifospay.core.model.domain.Currency as DomainCurrency -class CurrencyMapper @Inject internal constructor() { +class CurrencyMapper { fun transform(savingsCurrency: Currency): DomainCurrency { - val currency: DomainCurrency = - DomainCurrency() + val currency = DomainCurrency() currency.code = savingsCurrency.code currency.displayLabel = savingsCurrency.displayLabel currency.displaySymbol = savingsCurrency.displaySymbol diff --git a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt similarity index 97% rename from core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt index 4073c72ef..d21aa0b8e 100644 --- a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt @@ -17,9 +17,8 @@ import org.mifospay.core.data.util.Constants import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers -import javax.inject.Inject -class FetchAccount @Inject constructor( +class FetchAccount( private val fineractRepository: FineractRepository, private val accountMapper: AccountMapper, ) : UseCase() { diff --git a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt similarity index 92% rename from core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt index 4f9b58ea1..affc21632 100644 --- a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt @@ -11,9 +11,8 @@ package org.mifospay.core.data.fineract.entity.mapper import com.mifospay.core.model.domain.SearchResult import com.mifospay.core.model.entity.SearchedEntity -import javax.inject.Inject -class SearchedEntitiesMapper @Inject internal constructor() { +class SearchedEntitiesMapper { fun transformList(searchedEntities: List?): List { val searchResults: MutableList = ArrayList() diff --git a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt similarity index 96% rename from core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt index 9f2c09513..340298508 100644 --- a/core/data/src/main/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt @@ -14,9 +14,8 @@ import com.mifospay.core.model.domain.TransactionType import com.mifospay.core.model.entity.accounts.savings.SavingsWithAssociations import com.mifospay.core.model.entity.accounts.savings.Transactions import com.mifospay.core.model.utils.DateHelper -import javax.inject.Inject -class TransactionMapper @Inject constructor( +class TransactionMapper( private val currencyMapper: CurrencyMapper, ) { diff --git a/core/data/src/main/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt similarity index 98% rename from core/data/src/main/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt index 054b9a6d3..80e0be3ea 100644 --- a/core/data/src/main/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt @@ -40,20 +40,17 @@ import com.mifospay.core.model.entity.standinginstruction.SDIResponse import com.mifospay.core.model.entity.standinginstruction.StandingInstruction import okhttp3.MultipartBody import okhttp3.ResponseBody +import org.mifos.core.network.services.KtorAuthenticationService import org.mifospay.core.data.domain.usecase.client.CreateClient import org.mifospay.core.data.domain.usecase.user.CreateUser import org.mifospay.core.data.util.Constants import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.GenericResponse import org.mifospay.core.network.SelfServiceApiManager -import org.mifospay.core.network.services.KtorAuthenticationService import rx.Observable -import javax.inject.Inject -import javax.inject.Singleton -@Singleton @Suppress("TooManyFunctions") -class FineractRepository @Inject constructor( +class FineractRepository( private val fineractApiManager: FineractApiManager, private val selfApiManager: SelfServiceApiManager, private val ktorAuthenticationService: KtorAuthenticationService, diff --git a/core/data/src/main/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt b/core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt similarity index 92% rename from core/data/src/main/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt index 266f7f9c4..70cc1a2c3 100644 --- a/core/data/src/main/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt @@ -13,9 +13,8 @@ import com.mifospay.core.model.UserData import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import org.mifospay.core.datastore.PreferencesHelper -import javax.inject.Inject -class AuthenticationUserRepository @Inject constructor( +class AuthenticationUserRepository( private val preferencesHelper: PreferencesHelper, ) : UserDataRepository { diff --git a/core/data/src/main/java/org/mifospay/core/data/repository/auth/UserDataRepository.kt b/core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/UserDataRepository.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/repository/auth/UserDataRepository.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/UserDataRepository.kt diff --git a/core/data/src/main/java/org/mifospay/core/data/repository/local/LocalAssetRepository.kt b/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalAssetRepository.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/repository/local/LocalAssetRepository.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalAssetRepository.kt diff --git a/core/data/src/main/java/org/mifospay/core/data/repository/local/LocalRepository.kt b/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalRepository.kt similarity index 90% rename from core/data/src/main/java/org/mifospay/core/data/repository/local/LocalRepository.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalRepository.kt index d6554c5e4..de55915ed 100644 --- a/core/data/src/main/java/org/mifospay/core/data/repository/local/LocalRepository.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalRepository.kt @@ -11,11 +11,8 @@ package org.mifospay.core.data.repository.local import com.mifospay.core.model.domain.client.Client import org.mifospay.core.datastore.PreferencesHelper -import javax.inject.Inject -import javax.inject.Singleton -@Singleton -class LocalRepository @Inject constructor( +class LocalRepository( val preferencesHelper: PreferencesHelper, ) { diff --git a/core/data/src/main/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt b/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt similarity index 77% rename from core/data/src/main/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt index d2d5062b5..c93b060fa 100644 --- a/core/data/src/main/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt @@ -16,19 +16,17 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn -import org.mifospay.core.network.Dispatcher -import org.mifospay.core.network.MifosDispatchers -import org.mifospay.core.network.localAssets.MifosLocalAssetDataSource -import javax.inject.Inject +import org.mifos.core.network.localAssets.LocalAssetDataSource /** * Local implementation of the [LocalAssetRepository] that retrieves the countries, banks, cities * and state list from a JSON String. * */ -class MifosLocalAssetRepository @Inject constructor( - @Dispatcher(MifosDispatchers.IO) private val ioDispatcher: CoroutineDispatcher, - private val datasource: MifosLocalAssetDataSource, + +class MifosLocalAssetRepository( + private val ioDispatcher: CoroutineDispatcher, + private val datasource: LocalAssetDataSource, ) : LocalAssetRepository { override fun getCountries(): Flow> = flow { diff --git a/core/data/src/main/java/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt b/core/data/src/androidMain/java/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt similarity index 92% rename from core/data/src/main/java/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt index 1f7f15bd4..8e0986c79 100644 --- a/core/data/src/main/java/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt @@ -19,15 +19,13 @@ import android.net.NetworkRequest.Builder import android.os.Build.VERSION import android.os.Build.VERSION_CODES import androidx.core.content.getSystemService -import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.conflate -import javax.inject.Inject -internal class ConnectivityManagerNetworkMonitor @Inject constructor( - @ApplicationContext private val context: Context, +internal class ConnectivityManagerNetworkMonitor( + private val context: Context, ) : NetworkMonitor { override val isOnline: Flow = callbackFlow { val connectivityManager = context.getSystemService() diff --git a/core/data/src/main/java/org/mifospay/core/data/util/Constants.kt b/core/data/src/androidMain/java/org/mifospay/core/data/util/Constants.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/util/Constants.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/util/Constants.kt diff --git a/core/data/src/main/java/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt diff --git a/core/data/src/main/java/org/mifospay/core/data/util/NetworkMonitor.kt b/core/data/src/androidMain/java/org/mifospay/core/data/util/NetworkMonitor.kt similarity index 100% rename from core/data/src/main/java/org/mifospay/core/data/util/NetworkMonitor.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/util/NetworkMonitor.kt diff --git a/core/data/src/main/java/org/mifospay/core/data/util/TimeZoneMonitor.kt b/core/data/src/androidMain/java/org/mifospay/core/data/util/TimeZoneMonitor.kt similarity index 87% rename from core/data/src/main/java/org/mifospay/core/data/util/TimeZoneMonitor.kt rename to core/data/src/androidMain/java/org/mifospay/core/data/util/TimeZoneMonitor.kt index c32ef6808..bd92230cd 100644 --- a/core/data/src/main/java/org/mifospay/core/data/util/TimeZoneMonitor.kt +++ b/core/data/src/androidMain/java/org/mifospay/core/data/util/TimeZoneMonitor.kt @@ -16,7 +16,6 @@ import android.content.IntentFilter import android.os.Build.VERSION import android.os.Build.VERSION_CODES import androidx.tracing.trace -import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose @@ -30,26 +29,21 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.shareIn import kotlinx.datetime.TimeZone import kotlinx.datetime.toKotlinTimeZone -import org.mifospay.core.network.Dispatcher -import org.mifospay.core.network.MifosDispatchers -import org.mifospay.core.network.di.ApplicationScope import java.time.ZoneId -import javax.inject.Inject -import javax.inject.Singleton /** * Utility for reporting current timezone the device has set. * It always emits at least once with default setting and then for each TZ change. */ + interface TimeZoneMonitor { val currentTimeZone: Flow } -@Singleton -internal class TimeZoneBroadcastMonitor @Inject constructor( - @ApplicationContext private val context: Context, - @ApplicationScope appScope: CoroutineScope, - @Dispatcher(MifosDispatchers.IO) private val ioDispatcher: CoroutineDispatcher, +internal class TimeZoneBroadcastMonitor( + private val context: Context, + appScope: CoroutineScope, + private val ioDispatcher: CoroutineDispatcher, ) : TimeZoneMonitor { override val currentTimeZone: SharedFlow = diff --git a/core/data/src/main/res/values/strings.xml b/core/data/src/androidMain/res/values/strings.xml similarity index 100% rename from core/data/src/main/res/values/strings.xml rename to core/data/src/androidMain/res/values/strings.xml diff --git a/core/data/src/main/java/org/mifospay/core/data/di/DataModule.kt b/core/data/src/main/java/org/mifospay/core/data/di/DataModule.kt deleted file mode 100644 index 6317d5f41..000000000 --- a/core/data/src/main/java/org/mifospay/core/data/di/DataModule.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.di - -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import org.mifospay.core.data.base.UseCaseHandler -import org.mifospay.core.data.base.UseCaseThreadPoolScheduler -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.network.FineractApiManager -import org.mifospay.core.network.SelfServiceApiManager -import org.mifospay.core.network.services.KtorAuthenticationService - -@Module -@InstallIn(SingletonComponent::class) -class DataModule { - - @Provides - fun provideUseCaseThreadPoolScheduler(): UseCaseThreadPoolScheduler = - UseCaseThreadPoolScheduler() - - @Provides - fun providesUseCaseHandler(useCaseThreadPoolScheduler: UseCaseThreadPoolScheduler): UseCaseHandler { - return UseCaseHandler(useCaseThreadPoolScheduler) - } - - @Provides - fun providesFineractRepository( - fineractApiManager: FineractApiManager, - selfServiceApiManager: SelfServiceApiManager, - ktorAuthenticationService: KtorAuthenticationService, - ): FineractRepository { - return FineractRepository( - fineractApiManager, - selfServiceApiManager, - ktorAuthenticationService, - ) - } -} diff --git a/core/data/src/main/java/org/mifospay/core/data/di/LocalDataModule.kt b/core/data/src/main/java/org/mifospay/core/data/di/LocalDataModule.kt deleted file mode 100644 index 9b477903d..000000000 --- a/core/data/src/main/java/org/mifospay/core/data/di/LocalDataModule.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.di - -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import org.mifospay.core.data.repository.auth.AuthenticationUserRepository -import org.mifospay.core.data.repository.auth.UserDataRepository -import org.mifospay.core.data.repository.local.LocalAssetRepository -import org.mifospay.core.data.repository.local.MifosLocalAssetRepository -import org.mifospay.core.data.util.ConnectivityManagerNetworkMonitor -import org.mifospay.core.data.util.NetworkMonitor -import org.mifospay.core.data.util.TimeZoneBroadcastMonitor -import org.mifospay.core.data.util.TimeZoneMonitor - -@Module -@InstallIn(SingletonComponent::class) -abstract class LocalDataModule { - - @Binds - internal abstract fun bindsUserDataRepository( - authenticationUserRepository: AuthenticationUserRepository, - ): UserDataRepository - - @Binds - internal abstract fun bindsLocalAssetRepository( - repository: MifosLocalAssetRepository, - ): LocalAssetRepository - - @Binds - internal abstract fun bindsNetworkMonitor( - networkMonitor: ConnectivityManagerNetworkMonitor, - ): NetworkMonitor - - @Binds - internal abstract fun binds(impl: TimeZoneBroadcastMonitor): TimeZoneMonitor -} diff --git a/core/data/src/test/java/org/mifospay/mobilewallet/core/ExampleUnitTest.kt b/core/data/src/test/java/org/mifospay/mobilewallet/core/ExampleUnitTest.kt deleted file mode 100644 index abad7a3e6..000000000 --- a/core/data/src/test/java/org/mifospay/mobilewallet/core/ExampleUnitTest.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.mobilewallet.core - -import org.junit.Assert -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see [Testing documentation](http://d.android.com/tools/testing) - */ -class ExampleUnitTest { - @Test - @Throws(Exception::class) - fun additionIsCorrect() { - Assert.assertEquals(4, (2 + 2).toLong()) - } -} diff --git a/core/datastore-proto/build.gradle.kts b/core/datastore-proto/build.gradle.kts index b579ecfba..51683868e 100644 --- a/core/datastore-proto/build.gradle.kts +++ b/core/datastore-proto/build.gradle.kts @@ -8,8 +8,9 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.library) + alias(libs.plugins.mifospay.kmp.library) alias(libs.plugins.protobuf) + id("kotlinx-serialization") } android { @@ -24,9 +25,6 @@ protobuf { generateProtoTasks { all().forEach { task -> task.builtins { - register("java") { - option("lite") - } register("kotlin") { option("lite") } @@ -35,14 +33,11 @@ protobuf { } } -/*androidComponents.beforeVariants { - android.sourceSets.register(it.name) { - val buildDir = layout.buildDirectory.get().asFile - java.srcDir(buildDir.resolve("generated/source/proto/${it.name}/java")) - kotlin.srcDir(buildDir.resolve("generated/source/proto/${it.name}/kotlin")) +kotlin { + sourceSets { + commonMain.dependencies { + api(libs.protobuf.kotlin.lite) + implementation(libs.kotlinx.serialization.core) + } } -}*/ - -dependencies { - api(libs.protobuf.kotlin.lite) -} +} \ No newline at end of file diff --git a/core/datastore-proto/src/main/AndroidManifest.xml b/core/datastore-proto/src/androidMain/AndroidManifest.xml similarity index 100% rename from core/datastore-proto/src/main/AndroidManifest.xml rename to core/datastore-proto/src/androidMain/AndroidManifest.xml diff --git a/core/datastore-proto/src/main/proto/org.mifospay.core.data/user_preferences.proto b/core/datastore-proto/src/androidMain/proto/org.mifospay.core.data/user_preferences.proto similarity index 100% rename from core/datastore-proto/src/main/proto/org.mifospay.core.data/user_preferences.proto rename to core/datastore-proto/src/androidMain/proto/org.mifospay.core.data/user_preferences.proto diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index d11f08063..f447d6a0d 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -8,11 +8,9 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.library) - alias(libs.plugins.mifospay.android.hilt) + alias(libs.plugins.mifospay.kmp.library) } - android { namespace = "org.mifospay.core.datastore" defaultConfig { @@ -25,11 +23,20 @@ android { } } -dependencies { - api(libs.kotlinx.datetime) - api(libs.androidx.dataStore.core) - api(projects.core.datastoreProto) - api(projects.core.common) - api(projects.core.model) - implementation(libs.squareup.retrofit.converter.gson) +kotlin { + sourceSets { + commonMain.dependencies { + implementation(libs.multiplatform.settings) + implementation(libs.multiplatform.settings.serialization) + implementation(libs.multiplatform.settings.coroutines) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.serialization.core) + implementation(projects.core.model) + implementation(projects.core.common) + implementation(projects.core.datastoreProto) + } + commonTest.dependencies { + implementation(libs.multiplatform.settings.test) + } + } } \ No newline at end of file diff --git a/core/datastore/src/main/AndroidManifest.xml b/core/datastore/src/androidMain/AndroidManifest.xml similarity index 100% rename from core/datastore/src/main/AndroidManifest.xml rename to core/datastore/src/androidMain/AndroidManifest.xml diff --git a/core/datastore/src/main/java/org/mifospay/core/datastore/PreferencesHelper.kt b/core/datastore/src/androidMain/java/org/mifospay/core/datastore/PreferencesHelper.kt similarity index 92% rename from core/datastore/src/main/java/org/mifospay/core/datastore/PreferencesHelper.kt rename to core/datastore/src/androidMain/java/org/mifospay/core/datastore/PreferencesHelper.kt index b3fba0ce4..ac1ba99b3 100644 --- a/core/datastore/src/main/java/org/mifospay/core/datastore/PreferencesHelper.kt +++ b/core/datastore/src/androidMain/java/org/mifospay/core/datastore/PreferencesHelper.kt @@ -15,17 +15,10 @@ import android.preference.PreferenceManager import com.google.gson.Gson import com.mifospay.core.model.domain.client.Client import com.mifospay.core.model.domain.user.User -import dagger.hilt.android.qualifiers.ApplicationContext -import javax.inject.Inject -import javax.inject.Singleton -@Singleton -class PreferencesHelper @Inject constructor(@ApplicationContext context: Context?) { - private val sharedPreferences: SharedPreferences - - init { - sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - } +class PreferencesHelper(private val context: Context?) { + private val sharedPreferences: SharedPreferences = + PreferenceManager.getDefaultSharedPreferences(context) fun clear() { sharedPreferences.edit().clear().apply() diff --git a/core/datastore/src/androidMain/java/org/mifospay/core/datastore/di/CoreDataStoreModule.kt b/core/datastore/src/androidMain/java/org/mifospay/core/datastore/di/CoreDataStoreModule.kt new file mode 100644 index 000000000..a38fb6ff2 --- /dev/null +++ b/core/datastore/src/androidMain/java/org/mifospay/core/datastore/di/CoreDataStoreModule.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.datastore.di + +import org.koin.android.ext.koin.androidContext +import org.koin.dsl.module +import org.mifospay.core.datastore.PreferencesHelper + +val CoreDataStoreModule = module { + + factory { + PreferencesHelper(context = androidContext()) + } +} diff --git a/core/datastore/src/main/java/org/mifospay/core/datastore/di/DataStoreModule.kt b/core/datastore/src/main/java/org/mifospay/core/datastore/di/DataStoreModule.kt deleted file mode 100644 index 986a08b89..000000000 --- a/core/datastore/src/main/java/org/mifospay/core/datastore/di/DataStoreModule.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.datastore.di - -import android.content.Context -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import org.mifospay.core.datastore.PreferencesHelper -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -object DataStoreModule { - - @Provides - @Singleton - fun prefManager(@ApplicationContext context: Context): PreferencesHelper { - return PreferencesHelper(context) - } -} diff --git a/core/designsystem/build.gradle.kts b/core/designsystem/build.gradle.kts index f08a5aea8..d776a2ebe 100644 --- a/core/designsystem/build.gradle.kts +++ b/core/designsystem/build.gradle.kts @@ -1,3 +1,15 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig + /* * Copyright 2024 Mifos Initiative * @@ -8,8 +20,10 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.library) - alias(libs.plugins.mifospay.android.library.compose) + alias(libs.plugins.mifospay.kmp.library) + alias(libs.plugins.jetbrainsCompose) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.roborazzi) } android { @@ -19,20 +33,51 @@ android { namespace = "org.mifospay.core.designsystem" } -dependencies { - lintPublish(projects.lint) - - implementation(projects.core.model) +kotlin { + @OptIn(ExperimentalWasmDsl::class) + wasmJs { + moduleName = "composeApp" + browser { + commonWebpackConfig { + outputFileName = "composeApp.js" + devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply { + static = (static ?: mutableListOf()).apply { + // Serve sources to debug inside browser + add(project.projectDir.path) + } + } + } + } + binaries.executable() + } - api(libs.androidx.compose.ui) - api(libs.androidx.compose.foundation) - api(libs.androidx.compose.foundation.layout) - api(libs.androidx.compose.material.iconsExtended) - api(libs.androidx.compose.material3) - api(libs.androidx.compose.runtime) - api(libs.androidx.compose.ui.util) - api(libs.androidx.activity.compose) + sourceSets { + androidMain.dependencies { + implementation(libs.androidx.compose.ui.tooling.preview) + implementation(libs.androidx.activity.compose) + implementation(projects.core.model) + } + androidInstrumentedTest.dependencies { + implementation(libs.androidx.compose.ui.test) + } + androidUnitTest.dependencies { + implementation(libs.androidx.compose.ui.test) + } + commonMain.dependencies { + implementation(libs.coil.kt.compose) + implementation(compose.runtime) + implementation(compose.foundation) + implementation(compose.material) + implementation(compose.material3) + implementation(compose.materialIconsExtended) + implementation(compose.ui) + implementation(compose.uiUtil) + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) + } + } +} - testImplementation(libs.androidx.compose.ui.test) - androidTestImplementation(libs.androidx.compose.ui.test) +dependencies { + lintPublish(projects.lint) } \ No newline at end of file diff --git a/core/model/build.gradle.kts b/core/model/build.gradle.kts index fb199f33d..8cadff653 100644 --- a/core/model/build.gradle.kts +++ b/core/model/build.gradle.kts @@ -8,7 +8,7 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.library) + alias(libs.plugins.mifospay.kmp.library) alias(libs.plugins.kotlin.parcelize) id("kotlinx-serialization") } @@ -17,10 +17,14 @@ android { namespace = "org.mifospay.core.model" } -dependencies { - api(libs.kotlinx.datetime) - - // For Serialized name - implementation(libs.squareup.retrofit.converter.gson) - implementation(libs.kotlinx.serialization.json) -} +kotlin { + sourceSets { + commonMain.dependencies { + api(libs.kotlinx.datetime) + implementation(libs.kotlinx.serialization.json) + } + androidMain.dependencies { + implementation(libs.squareup.retrofit.converter.gson) + } + } +} \ No newline at end of file diff --git a/core/model/src/test/java/com/mifos/mobilewallet/model/ExampleUnitTest.kt b/core/model/src/test/java/com/mifos/mobilewallet/model/ExampleUnitTest.kt deleted file mode 100644 index 1915be841..000000000 --- a/core/model/src/test/java/com/mifos/mobilewallet/model/ExampleUnitTest.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifos.mobilewallet.model - -import org.junit.Assert.assertEquals -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index 5b13992d6..f4f2243dd 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -7,7 +7,6 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -import com.android.build.api.dsl.Packaging /* * Copyright 2024 Mifos Initiative @@ -19,9 +18,10 @@ import com.android.build.api.dsl.Packaging * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.library) - alias(libs.plugins.mifospay.android.hilt) + alias(libs.plugins.mifospay.kmp.library) + alias(libs.plugins.ktrofit) id("kotlinx-serialization") + id("com.google.devtools.ksp") } android { @@ -32,37 +32,53 @@ android { testOptions { unitTests { isReturnDefaultValues = true + isIncludeAndroidResources = true } } } -dependencies { - api(libs.kotlinx.datetime) - api(projects.core.common) - api(projects.core.model) - api(projects.core.datastore) - - implementation(libs.squareup.okhttp) - implementation(libs.squareup.logging.interceptor) - - implementation(libs.squareup.retrofit2) - implementation(libs.retrofit.kotlin.serialization) - implementation(libs.squareup.retrofit.adapter.rxjava) - implementation(libs.squareup.retrofit.converter.gson) - - implementation(libs.reactivex.rxjava.android) - implementation(libs.reactivex.rxjava) - - implementation(libs.jetbrains.kotlin.stdlib) - implementation(libs.ktor.client.core) - implementation(libs.ktor.client.android) - implementation(libs.ktor.client.serialization) - implementation(libs.ktor.client.logging) - implementation(libs.ktor.client.content.negotiation) - implementation(libs.ktor.client.json) - implementation(libs.ktor.client.websockets) - implementation(libs.ktor.serialization.kotlinx.json) - implementation(libs.logback.classic) - - testImplementation(libs.kotlinx.coroutines.test) +kotlin { + sourceSets { + commonMain.dependencies { + api(libs.kotlinx.datetime) + api(projects.core.common) + api(projects.core.model) + implementation(libs.kotlinx.serialization.json) + implementation(libs.ktor.client.core) + implementation(libs.ktor.client.json) + implementation(libs.ktor.client.logging) + implementation(libs.ktor.client.serialization) + implementation(libs.ktor.client.content.negotiation) + implementation(libs.ktor.serialization.kotlinx.json) + implementation(libs.ktorfit.lib) + implementation(libs.ktorfit.converters.call) + implementation(libs.ktorfit.converters.flow) + } + androidMain.dependencies { + implementation(libs.ktor.client.android) + implementation(libs.koin.android) + } + appleMain.dependencies { + implementation(libs.ktor.client.darwin) + } +// wasmJsMain.dependencies { +// implementation(libs.ktor.client.js) +// } + jvmMain.dependencies { + implementation(libs.ktor.client.java) + } + mingwMain.dependencies { + implementation(libs.ktor.client.winhttp) + } + } } + +dependencies { + add("kspCommonMainMetadata", libs.ktorfit.ksp) + add("kspAndroid", libs.ktorfit.ksp) +// add("kspWasmJs", libs.ktorfit.ksp) + add("kspJvm", libs.ktorfit.ksp) + add("kspIosX64", libs.ktorfit.ksp) + add("kspIosArm64", libs.ktorfit.ksp) + add("kspIosSimulatorArm64", libs.ktorfit.ksp) +} \ No newline at end of file diff --git a/core/network/src/main/AndroidManifest.xml b/core/network/src/androidMain/AndroidManifest.xml similarity index 100% rename from core/network/src/main/AndroidManifest.xml rename to core/network/src/androidMain/AndroidManifest.xml diff --git a/core/network/src/main/assets/banks.json b/core/network/src/androidMain/assets/banks.json similarity index 100% rename from core/network/src/main/assets/banks.json rename to core/network/src/androidMain/assets/banks.json diff --git a/core/network/src/main/assets/cities.json b/core/network/src/androidMain/assets/cities.json similarity index 100% rename from core/network/src/main/assets/cities.json rename to core/network/src/androidMain/assets/cities.json diff --git a/core/network/src/main/assets/countries.json b/core/network/src/androidMain/assets/countries.json similarity index 100% rename from core/network/src/main/assets/countries.json rename to core/network/src/androidMain/assets/countries.json diff --git a/core/network/src/main/assets/countriesToCities.json b/core/network/src/androidMain/assets/countriesToCities.json similarity index 100% rename from core/network/src/main/assets/countriesToCities.json rename to core/network/src/androidMain/assets/countriesToCities.json diff --git a/core/network/src/main/assets/states.json b/core/network/src/androidMain/assets/states.json similarity index 100% rename from core/network/src/main/assets/states.json rename to core/network/src/androidMain/assets/states.json diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/ApiEndPoints.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/ApiEndPoints.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/ApiInterceptor.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiInterceptor.kt similarity index 81% rename from core/network/src/main/kotlin/org/mifospay/core/network/ApiInterceptor.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiInterceptor.kt index a006691cd..26d2511d6 100644 --- a/core/network/src/main/kotlin/org/mifospay/core/network/ApiInterceptor.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiInterceptor.kt @@ -20,12 +20,12 @@ class ApiInterceptor(private val preferencesHelper: PreferencesHelper) : Interce override fun intercept(chain: Interceptor.Chain): Response { val chainRequest = chain.request() val builder = chainRequest.newBuilder().header( - org.mifospay.core.network.ApiInterceptor.Companion.HEADER_TENANT, - org.mifospay.core.network.ApiInterceptor.Companion.DEFAULT, + HEADER_TENANT, + DEFAULT, ) val authToken = preferencesHelper.token if (!authToken.isNullOrEmpty()) { - builder.header(org.mifospay.core.network.ApiInterceptor.Companion.HEADER_AUTH, authToken) + builder.header(HEADER_AUTH, authToken) } val request = builder.build() return chain.proceed(request) diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/BaseURL.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/BaseURL.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/BaseURL.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/BaseURL.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/FineractApiManager.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/FineractApiManager.kt similarity index 98% rename from core/network/src/main/kotlin/org/mifospay/core/network/FineractApiManager.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/FineractApiManager.kt index a424d3d92..b42a185f4 100644 --- a/core/network/src/main/kotlin/org/mifospay/core/network/FineractApiManager.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/FineractApiManager.kt @@ -26,9 +26,8 @@ import org.mifospay.core.network.services.StandingInstructionService import org.mifospay.core.network.services.ThirdPartyTransferService import org.mifospay.core.network.services.TwoFactorAuthService import org.mifospay.core.network.services.UserService -import javax.inject.Inject -class FineractApiManager @Inject constructor( +class FineractApiManager( private val authenticationService: AuthenticationService, private val clientService: ClientService, private val savingsAccountsService: SavingsAccountsService, diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/GenericResponse.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/GenericResponse.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/GenericResponse.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/GenericResponse.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt similarity index 57% rename from core/network/src/main/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt index a2e332838..37cc92891 100644 --- a/core/network/src/main/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt @@ -13,25 +13,25 @@ import androidx.annotation.VisibleForTesting import org.mifospay.core.network.localAssets.LocalAssetManager import java.io.File import java.io.InputStream -import java.util.Properties /** * This class helps with loading Android `/assets` files, especially when running JVM unit tests. * It must remain on the root package for an easier [Class.getResource] with relative paths. * @see https://developer.android.com/reference/tools/gradle-api/7.3/com/android/build/api/dsl/UnitTestOptions */ + @VisibleForTesting internal object JvmLocalAssetManager : LocalAssetManager { - private val config = - requireNotNull(javaClass.getResource("com/android/tools/test_config.properties")) { - """ - Missing Android resources properties file. - Did you forget to enable the feature in the gradle build file? - android.testOptions.unitTests.isIncludeAndroidResources = true - """.trimIndent() - } - private val properties = Properties().apply { config.openStream().use(::load) } - private val assets = File(properties["android_merged_assets"].toString()) +// private val config = +// requireNotNull(javaClass.getResource("com/android/tools/test_config.properties")) { +// """ +// Missing Android resources properties file. +// Did you forget to enable the feature in the gradle build file? +// android.testOptions.unitTests.isIncludeAndroidResources = true +// """.trimIndent() +// } +// private val properties = Properties().apply { config.openStream().use(::load) } +// private val assets = File(properties["android_merged_assets"].toString()) - override fun open(fileName: String): InputStream = File(assets, fileName).inputStream() + override fun open(fileName: String): InputStream = File(fileName).inputStream() } diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/KtorInterceptor.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorInterceptor.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/KtorInterceptor.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorInterceptor.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt similarity index 97% rename from core/network/src/main/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt index c58705e70..b2fd7bafd 100644 --- a/core/network/src/main/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt @@ -78,7 +78,7 @@ class MifosWalletOkHttpClient(private val preferences: PreferencesHelper) { // Interceptor :> Full Body Logger and ApiRequest Header builder.addInterceptor(logger) - builder.addInterceptor(org.mifospay.core.network.ApiInterceptor(preferences)) + builder.addInterceptor(ApiInterceptor(preferences)) return builder.build() } } diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt similarity index 96% rename from core/network/src/main/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt index 059594223..54ea9d17d 100644 --- a/core/network/src/main/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt @@ -16,9 +16,8 @@ import org.mifospay.core.network.services.KtorSavingsAccountService import org.mifospay.core.network.services.RegistrationService import org.mifospay.core.network.services.SavingsAccountsService import org.mifospay.core.network.services.ThirdPartyTransferService -import javax.inject.Inject -class SelfServiceApiManager @Inject constructor( +class SelfServiceApiManager( private val authenticationService: AuthenticationService, private val clientService: ClientService, private val savingsAccountsService: SavingsAccountsService, diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/LocalModule.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/LocalModule.kt new file mode 100644 index 000000000..484d2effe --- /dev/null +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/LocalModule.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.di + +import org.koin.android.ext.koin.androidContext +import org.koin.dsl.module +import org.mifospay.core.network.localAssets.LocalAssetManager + +val LocalModule = module { + single { + LocalAssetManager { fileName -> androidContext().assets.open(fileName) } + } +} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt new file mode 100644 index 000000000..639d5623c --- /dev/null +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt @@ -0,0 +1,233 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.di + +import io.ktor.client.HttpClient +import io.ktor.client.engine.android.Android +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logging +import io.ktor.client.plugins.websocket.WebSockets +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json +import org.koin.dsl.module +import org.mifospay.core.datastore.PreferencesHelper +import org.mifospay.core.network.BaseURL +import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.KtorInterceptor +import org.mifospay.core.network.MifosWalletOkHttpClient +import org.mifospay.core.network.SelfServiceApiManager +import org.mifospay.core.network.services.AccountTransfersService +import org.mifospay.core.network.services.AuthenticationService +import org.mifospay.core.network.services.BeneficiaryService +import org.mifospay.core.network.services.ClientService +import org.mifospay.core.network.services.DocumentService +import org.mifospay.core.network.services.InvoiceService +import org.mifospay.core.network.services.KYCLevel1Service +import org.mifospay.core.network.services.KtorAuthenticationService +import org.mifospay.core.network.services.KtorSavingsAccountService +import org.mifospay.core.network.services.NotificationService +import org.mifospay.core.network.services.RegistrationService +import org.mifospay.core.network.services.RunReportService +import org.mifospay.core.network.services.SavedCardService +import org.mifospay.core.network.services.SavingsAccountsService +import org.mifospay.core.network.services.SearchService +import org.mifospay.core.network.services.StandingInstructionService +import org.mifospay.core.network.services.ThirdPartyTransferService +import org.mifospay.core.network.services.TwoFactorAuthService +import org.mifospay.core.network.services.UserService +import retrofit2.Retrofit +import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory +import retrofit2.converter.gson.GsonConverterFactory + +@Suppress("TooManyFunctions") +val NetworkModule = module { + + single { + Json { + ignoreUnknownKeys = true + } + } + + single(SelfServiceApi) { + val preferencesHelper: PreferencesHelper = get() + Retrofit.Builder() + .baseUrl(BaseURL().selfServiceUrl) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) + .client(MifosWalletOkHttpClient(preferencesHelper).mifosOkHttpClient) + .build() + } + + single(FineractApi) { + val preferencesHelper: PreferencesHelper = get() + Retrofit.Builder() + .baseUrl(BaseURL().url) + .addConverterFactory(GsonConverterFactory.create()) + .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) + .client(MifosWalletOkHttpClient(preferencesHelper).mifosOkHttpClient) + .build() + } + + single { + FineractApiManager( + authenticationService = get(FineractAuthenticationService), + clientService = get(FineractClientService), + savingsAccountsService = get(FineractSavingsAccountsService), + registrationService = get(FineractRegistrationService), + searchService = get(), + documentService = get(), + runReportService = get(), + twoFactorAuthService = get(), + accountTransfersService = get(), + savedCardService = get(), + kYCLevel1Service = get(), + invoiceService = get(), + userService = get(), + thirdPartyTransferService = get(FineractThirdPartyTransferService), + standingInstructionService = get(), + notificationService = get(), + ktorSavingsAccountService = get(), + ) + } + + single { + SelfServiceApiManager( + authenticationService = get(SelfServiceAuthenticationService), + clientService = get(SelfServiceClientService), + savingsAccountsService = get(SelfServiceSavingsAccountsService), + registrationService = get(SelfServiceRegistrationService), + beneficiaryService = get(), + thirdPartyTransferService = get(SelfServiceThirdPartyTransferService), + ktorSavingsAccountService = get(), + ) + } + +// Http client for Ktor + + single { + HttpClient(Android) { + install(WebSockets) + install(KtorInterceptor) { + this.preferencesHelper = get() + } + install(ContentNegotiation) { + json( + Json { + ignoreUnknownKeys = true + isLenient = true + }, + ) + } + install(HttpTimeout) { + requestTimeoutMillis = 15000 + } + install(Logging) { + level = LogLevel.ALL + } + } + } + + single { KtorAuthenticationService(client = get()) } + single { KtorSavingsAccountService(client = get()) } + + // -----Fineract API Service---------// + + single(FineractAuthenticationService) { + get(FineractApi).create(AuthenticationService::class.java) + } + + single(FineractClientService) { + get(FineractApi).create(ClientService::class.java) + } + + single(FineractSavingsAccountsService) { + get(FineractApi).create(SavingsAccountsService::class.java) + } + + single(FineractRegistrationService) { + get(FineractApi).create(RegistrationService::class.java) + } + + single { + get(FineractApi).create(SearchService::class.java) + } + + single { + get(FineractApi).create(SavedCardService::class.java) + } + + single { + get(FineractApi).create(DocumentService::class.java) + } + + single { + get(FineractApi).create(TwoFactorAuthService::class.java) + } + + single { + get(FineractApi).create(AccountTransfersService::class.java) + } + + single { + get(FineractApi).create(RunReportService::class.java) + } + + single { + get(FineractApi).create(KYCLevel1Service::class.java) + } + + single { + get(FineractApi).create(InvoiceService::class.java) + } + + single { + get(FineractApi).create(UserService::class.java) + } + + single(FineractThirdPartyTransferService) { + get(FineractApi).create(ThirdPartyTransferService::class.java) + } + + single { + get(FineractApi).create(NotificationService::class.java) + } + + single { + get(FineractApi).create(StandingInstructionService::class.java) + } + + // -------SelfService API Service-------// + + single(SelfServiceAuthenticationService) { + get(SelfServiceApi).create(AuthenticationService::class.java) + } + + single(SelfServiceClientService) { + get(SelfServiceApi).create(ClientService::class.java) + } + + single(SelfServiceSavingsAccountsService) { + get(SelfServiceApi).create(SavingsAccountsService::class.java) + } + + single(SelfServiceRegistrationService) { + get(SelfServiceApi).create(RegistrationService::class.java) + } + + single { + get(SelfServiceApi).create(BeneficiaryService::class.java) + } + + single(SelfServiceThirdPartyTransferService) { + get(SelfServiceApi).create(ThirdPartyTransferService::class.java) + } +} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/Qualifier.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/Qualifier.kt new file mode 100644 index 000000000..ae0471f29 --- /dev/null +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/Qualifier.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.di + +import org.koin.core.qualifier.named + +val SelfServiceApi = named("SelfServiceApi") +val FineractApi = named("FineractApi") + +val FineractAuthenticationService = named("FineractAuthenticationService") +val FineractClientService = named("FineractClientService") +val FineractSavingsAccountsService = named("FineractSavingsAccountsService") +val FineractRegistrationService = named("FineractRegistrationService") +val FineractThirdPartyTransferService = named("FineractThirdPartyTransferService") + +val SelfServiceAuthenticationService = named("SelfServiceAuthenticationService") +val SelfServiceClientService = named("SelfServiceClientService") +val SelfServiceSavingsAccountsService = named("SelfServiceSavingsAccountsService") +val SelfServiceRegistrationService = named("SelfServiceRegistrationService") +val SelfServiceThirdPartyTransferService = named("SelfServiceThirdPartyTransferService") diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt similarity index 82% rename from core/network/src/main/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt index 4b85dc667..1bb530e4d 100644 --- a/core/network/src/main/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt @@ -9,7 +9,6 @@ */ package org.mifospay.core.network.localAssets -import android.annotation.SuppressLint import com.mifospay.core.model.City import com.mifospay.core.model.Country import com.mifospay.core.model.State @@ -18,16 +17,11 @@ import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.decodeFromStream -import org.mifospay.core.network.Dispatcher -import org.mifospay.core.network.JvmLocalAssetManager -import org.mifospay.core.network.MifosDispatchers -import javax.inject.Inject -class MifosLocalAssetDataSource @Inject constructor( - @Dispatcher(MifosDispatchers.IO) private val ioDispatcher: CoroutineDispatcher, +class MifosLocalAssetDataSource( + private val ioDispatcher: CoroutineDispatcher, private val networkJson: Json, - @SuppressLint("VisibleForTests") - private val assets: LocalAssetManager = JvmLocalAssetManager, + private val assets: LocalAssetManager, ) : LocalAssetDataSource { @OptIn(ExperimentalSerializationApi::class) diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/AuthenticationService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/AuthenticationService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/ClientService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ClientService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/ClientService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ClientService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/DocumentService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/DocumentService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/DocumentService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/DocumentService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/InvoiceService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/InvoiceService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt similarity index 92% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt index 47a93bf53..4df4b550c 100644 --- a/core/network/src/main/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt @@ -18,9 +18,8 @@ import io.ktor.client.request.setBody import io.ktor.http.ContentType import io.ktor.http.contentType import org.mifospay.core.network.BaseURL -import javax.inject.Inject -class KtorAuthenticationService @Inject constructor( +class KtorAuthenticationService( private val client: HttpClient, ) { diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt similarity index 97% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt index b0fc43c16..141088cd7 100644 --- a/core/network/src/main/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt @@ -20,13 +20,12 @@ import io.ktor.client.request.post import io.ktor.client.request.setBody import io.ktor.http.ContentType import io.ktor.http.contentType -import jakarta.inject.Inject import org.mifospay.core.network.ApiEndPoints.SAVINGS_ACCOUNTS import org.mifospay.core.network.ApiEndPoints.TRANSACTIONS import org.mifospay.core.network.BaseURL import org.mifospay.core.network.GenericResponse -class KtorSavingsAccountService @Inject constructor( +class KtorSavingsAccountService( private val client: HttpClient, ) { suspend fun getSavingsWithAssociations( diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/NotificationService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/NotificationService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/NotificationService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/NotificationService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/RegistrationService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/RegistrationService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/RunReportService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/RunReportService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/RunReportService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/RunReportService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/SavedCardService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/SavedCardService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/SearchService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SearchService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/SearchService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SearchService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/services/UserService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/UserService.kt similarity index 100% rename from core/network/src/main/kotlin/org/mifospay/core/network/services/UserService.kt rename to core/network/src/androidMain/kotlin/org/mifospay/core/network/services/UserService.kt diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/di/LocalModule.kt b/core/network/src/main/kotlin/org/mifospay/core/network/di/LocalModule.kt deleted file mode 100644 index c6217e930..000000000 --- a/core/network/src/main/kotlin/org/mifospay/core/network/di/LocalModule.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.di - -import dagger.Binds -import dagger.Module -import dagger.hilt.InstallIn -import dagger.hilt.components.SingletonComponent -import org.mifospay.core.network.localAssets.LocalAssetDataSource -import org.mifospay.core.network.localAssets.MifosLocalAssetDataSource - -@Module -@InstallIn(SingletonComponent::class) -internal interface LocalModule { - - @Binds - fun binds(impl: MifosLocalAssetDataSource): LocalAssetDataSource -} diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/di/NetworkModule.kt b/core/network/src/main/kotlin/org/mifospay/core/network/di/NetworkModule.kt deleted file mode 100644 index a58ba87a5..000000000 --- a/core/network/src/main/kotlin/org/mifospay/core/network/di/NetworkModule.kt +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.di - -import android.content.Context -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent -import io.ktor.client.HttpClient -import io.ktor.client.engine.android.Android -import io.ktor.client.plugins.HttpTimeout -import io.ktor.client.plugins.contentnegotiation.ContentNegotiation -import io.ktor.client.plugins.logging.LogLevel -import io.ktor.client.plugins.logging.Logging -import io.ktor.client.plugins.websocket.WebSockets -import io.ktor.serialization.kotlinx.json.json -import kotlinx.serialization.json.Json -import org.mifospay.core.datastore.PreferencesHelper -import org.mifospay.core.network.BaseURL -import org.mifospay.core.network.FineractApiManager -import org.mifospay.core.network.KtorInterceptor -import org.mifospay.core.network.MifosWalletOkHttpClient -import org.mifospay.core.network.SelfServiceApiManager -import org.mifospay.core.network.localAssets.LocalAssetManager -import org.mifospay.core.network.services.AccountTransfersService -import org.mifospay.core.network.services.AuthenticationService -import org.mifospay.core.network.services.BeneficiaryService -import org.mifospay.core.network.services.ClientService -import org.mifospay.core.network.services.DocumentService -import org.mifospay.core.network.services.InvoiceService -import org.mifospay.core.network.services.KYCLevel1Service -import org.mifospay.core.network.services.KtorAuthenticationService -import org.mifospay.core.network.services.KtorSavingsAccountService -import org.mifospay.core.network.services.NotificationService -import org.mifospay.core.network.services.RegistrationService -import org.mifospay.core.network.services.RunReportService -import org.mifospay.core.network.services.SavedCardService -import org.mifospay.core.network.services.SavingsAccountsService -import org.mifospay.core.network.services.SearchService -import org.mifospay.core.network.services.StandingInstructionService -import org.mifospay.core.network.services.ThirdPartyTransferService -import org.mifospay.core.network.services.TwoFactorAuthService -import org.mifospay.core.network.services.UserService -import retrofit2.Retrofit -import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory -import retrofit2.converter.gson.GsonConverterFactory -import javax.inject.Named -import javax.inject.Singleton - -@Module -@InstallIn(SingletonComponent::class) -@Suppress("TooManyFunctions") -class NetworkModule { - - @Provides - @Singleton - fun providesNetworkJson(): Json = Json { - ignoreUnknownKeys = true - } - - @Provides - @Singleton - fun providesFakeAssetManager( - @ApplicationContext context: Context, - ): LocalAssetManager = LocalAssetManager(context.assets::open) - - @Provides - @Singleton - @SelfServiceApi - fun providesRetrofitSelfService(preferencesHelper: PreferencesHelper): Retrofit { - return Retrofit.Builder() - .baseUrl(BaseURL().selfServiceUrl) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - .client(MifosWalletOkHttpClient(preferencesHelper).mifosOkHttpClient) - .build() - } - - @Provides - @Singleton - @FineractApi - fun providesRetrofitFineract(preferencesHelper: PreferencesHelper): Retrofit { - return Retrofit.Builder() - .baseUrl(BaseURL().url) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - .client(MifosWalletOkHttpClient(preferencesHelper).mifosOkHttpClient) - .build() - } - - @Provides - @Singleton - fun providesFineractApiManager( - @Named("FineractAuthenticationService") authenticationService: AuthenticationService, - @Named("FineractClientService") clientService: ClientService, - @Named("FineractSavingsAccountsService") savingsAccountsService: SavingsAccountsService, - @Named("FineractRegistrationService") registrationService: RegistrationService, - searchService: SearchService, - documentService: DocumentService, - runReportService: RunReportService, - twoFactorAuthService: TwoFactorAuthService, - accountTransfersService: AccountTransfersService, - savedCardService: SavedCardService, - kYCLevel1Service: KYCLevel1Service, - invoiceService: InvoiceService, - userService: UserService, - @Named("FineractThirdPartyTransferService") thirdPartyTransferService: ThirdPartyTransferService, - standingInstructionService: StandingInstructionService, - notificationService: NotificationService, - ktorSavingsAccountService: KtorSavingsAccountService, - ): FineractApiManager { - return FineractApiManager( - authenticationService, - clientService, - savingsAccountsService, - registrationService, - searchService, - documentService, - runReportService, - twoFactorAuthService, - accountTransfersService, - savedCardService, - kYCLevel1Service, - invoiceService, - userService, - thirdPartyTransferService, - standingInstructionService, - notificationService, - ktorSavingsAccountService, - ) - } - - @Provides - @Singleton - fun providesSelfServiceApiManager( - @Named("SelfServiceAuthenticationService") authenticationService: AuthenticationService, - @Named("SelfServiceClientService") clientService: ClientService, - @Named("SelfServiceSavingsAccountsService") savingsAccountsService: SavingsAccountsService, - ktorSavingsAccountService: KtorSavingsAccountService, - @Named("SelfServiceRegistrationService") registrationService: RegistrationService, - beneficiaryService: BeneficiaryService, - @Named("SelfServiceThirdPartyTransferService") thirdPartyTransferService: ThirdPartyTransferService, - ): SelfServiceApiManager { - return SelfServiceApiManager( - authenticationService, - clientService, - savingsAccountsService, - registrationService, - beneficiaryService, - thirdPartyTransferService, - ktorSavingsAccountService, - ) - } - - @Provides - @Singleton - fun provideHttpClient(preferencesHelper: PreferencesHelper): HttpClient { - return HttpClient(Android) { - install(WebSockets) - install(KtorInterceptor) { - this.preferencesHelper = preferencesHelper - } - install(ContentNegotiation) { - json( - Json { - ignoreUnknownKeys = true - isLenient = true - }, - ) - } - install(HttpTimeout) { - requestTimeoutMillis = 15000 - } - install(Logging) { - level = LogLevel.ALL - } - } - } - - @Provides - @Singleton - fun provideAuthenticationService(client: HttpClient): KtorAuthenticationService { - return KtorAuthenticationService(client) - } - - @Provides - @Singleton - fun providesKtorSavingsAccountService( - client: HttpClient, - ): KtorSavingsAccountService { - return KtorSavingsAccountService(client) - } - - // -----Fineract API Service---------// - - @Provides - @Singleton - @Named("FineractAuthenticationService") - fun providesAuthenticationService(@FineractApi retrofit: Retrofit): AuthenticationService { - return retrofit.create(AuthenticationService::class.java) - } - - @Provides - @Singleton - @Named("FineractClientService") - fun providesClientService(@FineractApi retrofit: Retrofit): ClientService { - return retrofit.create(ClientService::class.java) - } - - @Provides - @Singleton - @Named("FineractSavingsAccountsService") - fun providesSavingsAccountsService(@FineractApi retrofit: Retrofit): SavingsAccountsService { - return retrofit.create(SavingsAccountsService::class.java) - } - - @Provides - @Singleton - @Named("FineractRegistrationService") - fun providesRegistrationService(@FineractApi retrofit: Retrofit): RegistrationService { - return retrofit.create(RegistrationService::class.java) - } - - @Provides - @Singleton - fun providesSearchService(@FineractApi retrofit: Retrofit): SearchService { - return retrofit.create(SearchService::class.java) - } - - @Provides - @Singleton - fun providesSavedCardService(@FineractApi retrofit: Retrofit): SavedCardService { - return retrofit.create(SavedCardService::class.java) - } - - @Provides - @Singleton - fun providesDocumentService(@FineractApi retrofit: Retrofit): DocumentService { - return retrofit.create(DocumentService::class.java) - } - - @Provides - @Singleton - fun provideTwoFactorAuthService(@FineractApi retrofit: Retrofit): TwoFactorAuthService { - return retrofit.create(TwoFactorAuthService::class.java) - } - - @Provides - @Singleton - fun providesAccountTransfersService(@FineractApi retrofit: Retrofit): AccountTransfersService { - return retrofit.create(AccountTransfersService::class.java) - } - - @Provides - @Singleton - fun providesRunReportService(@FineractApi retrofit: Retrofit): RunReportService { - return retrofit.create(RunReportService::class.java) - } - - @Provides - @Singleton - fun providesKYCLevel1Service(@FineractApi retrofit: Retrofit): KYCLevel1Service { - return retrofit.create(KYCLevel1Service::class.java) - } - - @Provides - @Singleton - fun providesInvoiceService(@FineractApi retrofit: Retrofit): InvoiceService { - return retrofit.create(InvoiceService::class.java) - } - - @Provides - @Singleton - fun providesUserService(@FineractApi retrofit: Retrofit): UserService { - return retrofit.create(UserService::class.java) - } - - @Provides - @Singleton - @Named("FineractThirdPartyTransferService") - fun providesThirdPartyTransferService(@FineractApi retrofit: Retrofit): ThirdPartyTransferService { - return retrofit.create(ThirdPartyTransferService::class.java) - } - - @Provides - @Singleton - fun providesNotificationService(@FineractApi retrofit: Retrofit): NotificationService { - return retrofit.create(NotificationService::class.java) - } - - @Provides - @Singleton - fun providesStandingInstructionService(@FineractApi retrofit: Retrofit): StandingInstructionService { - return retrofit.create(StandingInstructionService::class.java) - } - - // -------SelfService API Service-------// - - @Provides - @Singleton - @Named("SelfServiceAuthenticationService") - fun providesSelfServiceAuthenticationService( - @SelfServiceApi retrofit: Retrofit, - ): AuthenticationService { - return retrofit.create(AuthenticationService::class.java) - } - - @Provides - @Singleton - @Named("SelfServiceClientService") - fun providesSelfServiceClientService( - @SelfServiceApi retrofit: Retrofit, - ): ClientService { - return retrofit.create(ClientService::class.java) - } - - @Provides - @Singleton - @Named("SelfServiceSavingsAccountsService") - fun providesSelfServiceSavingsAccountsService( - @SelfServiceApi retrofit: Retrofit, - ): SavingsAccountsService { - return retrofit.create(SavingsAccountsService::class.java) - } - - @Provides - @Singleton - @Named("SelfServiceRegistrationService") - fun providesSelfServiceRegistrationService( - @SelfServiceApi retrofit: Retrofit, - ): RegistrationService { - return retrofit.create(RegistrationService::class.java) - } - - @Provides - @Singleton - fun providesSelfServiceBeneficiaryService( - @SelfServiceApi retrofit: Retrofit, - ): BeneficiaryService { - return retrofit.create(BeneficiaryService::class.java) - } - - @Provides - @Singleton - @Named("SelfServiceThirdPartyTransferService") - fun providesSelfServiceThirdPartyTransferService( - @SelfServiceApi retrofit: Retrofit, - ): ThirdPartyTransferService { - return retrofit.create(ThirdPartyTransferService::class.java) - } -} diff --git a/core/network/src/test/java/org/mifospay/mobilewallet/mifospay/network/ExampleUnitTest.kt b/core/network/src/test/java/org/mifospay/mobilewallet/mifospay/network/ExampleUnitTest.kt deleted file mode 100644 index bbaddbe81..000000000 --- a/core/network/src/test/java/org/mifospay/mobilewallet/mifospay/network/ExampleUnitTest.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.mobilewallet.mifospay.network - -import org.junit.Assert.assertEquals -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 74cbb02cc..3426567e3 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -8,30 +8,40 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.library) - alias(libs.plugins.mifospay.android.library.compose) + alias(libs.plugins.mifospay.kmp.library) + alias(libs.plugins.jetbrainsCompose) + alias(libs.plugins.compose.compiler) } android { namespace = "org.mifospay.core.ui" - defaultConfig { - consumerProguardFiles("consumer-rules.pro") - } } -dependencies { - api(projects.core.designsystem) - api(projects.core.model) - api(projects.core.common) - api(libs.androidx.metrics) - api(projects.core.analytics) - - implementation(libs.androidx.compose.runtime) - implementation(libs.accompanist.pager) - implementation(libs.androidx.browser) - implementation(libs.coil.kt) - implementation(libs.coil.kt.compose) +kotlin { + sourceSets { + androidMain.dependencies { + api(libs.androidx.metrics) + implementation(libs.androidx.browser) + implementation(libs.androidx.compose.runtime) + implementation(libs.accompanist.pager) + } + commonMain.dependencies { + api(projects.core.analytics) + api(projects.core.designsystem) + api(projects.core.model) + implementation(libs.coil.kt) + implementation(libs.coil.kt.compose) + implementation(compose.material3) + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) + } + androidInstrumentedTest.dependencies { + implementation(libs.bundles.androidx.compose.ui.test) + } + } +} - testImplementation(libs.androidx.compose.ui.test) - androidTestImplementation(libs.bundles.androidx.compose.ui.test) +compose.resources { + publicResClass = true + generateResClass = always } \ No newline at end of file diff --git a/feature/accounts/build.gradle.kts b/feature/accounts/build.gradle.kts index 75d75c8b1..a0ddb8c38 100644 --- a/feature/accounts/build.gradle.kts +++ b/feature/accounts/build.gradle.kts @@ -20,4 +20,5 @@ dependencies { implementation(projects.core.data) implementation(projects.libs.pullrefresh) + implementation(libs.play.services.auth) } \ No newline at end of file diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountViewModel.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountViewModel.kt index 2010c9eda..1512449d8 100644 --- a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountViewModel.kt +++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountViewModel.kt @@ -12,17 +12,14 @@ package org.mifospay.feature.bank.accounts import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mifospay.core.model.domain.BankAccountDetails -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch import java.util.Random -import javax.inject.Inject -@HiltViewModel -class AccountViewModel @Inject constructor() : ViewModel() { +class AccountViewModel : ViewModel() { private val _bankAccountDetailsList = MutableStateFlow>(emptyList()) val bankAccountDetailsList: StateFlow> = _bankAccountDetailsList diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountsScreen.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountsScreen.kt index 45fa9d047..cfa68243f 100644 --- a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountsScreen.kt +++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/AccountsScreen.kt @@ -28,12 +28,12 @@ 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 com.mifos.library.pullrefresh.PullRefreshIndicator import com.mifos.library.pullrefresh.pullRefresh import com.mifos.library.pullrefresh.rememberPullRefreshState import com.mifospay.core.model.domain.BankAccountDetails +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.ui.EmptyContentScreen @@ -44,7 +44,7 @@ fun AccountsScreen( navigateToBankAccountDetailScreen: (BankAccountDetails, Int) -> Unit, navigateToLinkBankAccountScreen: () -> Unit, modifier: Modifier = Modifier, - viewModel: AccountViewModel = hiltViewModel(), + viewModel: AccountViewModel = koinViewModel(), ) { val accountsUiState by viewModel.accountsUiState.collectAsStateWithLifecycle() val isRefreshing by viewModel.isRefreshing.collectAsStateWithLifecycle() diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/di/AccountsModule.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/di/AccountsModule.kt new file mode 100644 index 000000000..db21bb51c --- /dev/null +++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/di/AccountsModule.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.bank.accounts.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.core.data.di.DataModule +import org.mifospay.feature.bank.accounts.AccountViewModel +import org.mifospay.feature.bank.accounts.link.LinkBankAccountViewModel + +val AccountsModule = module { + includes(DataModule) + viewModel { + LinkBankAccountViewModel(localAssetRepository = get()) + } + viewModel { + AccountViewModel() + } +} diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountScreen.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountScreen.kt index ec319bc8c..d51bfce27 100644 --- a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountScreen.kt +++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountScreen.kt @@ -50,10 +50,10 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifospay.core.model.domain.Bank import com.mifospay.core.model.domain.BankType +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel import org.mifospay.core.designsystem.component.MifosCard @@ -67,7 +67,7 @@ import org.mifospay.feature.bank.accounts.choose.sim.ChooseSimDialogSheet @Composable internal fun LinkBankAccountRoute( - viewModel: LinkBankAccountViewModel = hiltViewModel(), + viewModel: LinkBankAccountViewModel = koinViewModel(), onBackClick: () -> Unit, ) { val bankUiState by viewModel.bankListUiState.collectAsStateWithLifecycle() diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountViewModel.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountViewModel.kt index 9f6c107ac..2d23eb372 100644 --- a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountViewModel.kt +++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/link/LinkBankAccountViewModel.kt @@ -17,7 +17,6 @@ import androidx.lifecycle.viewModelScope import com.mifospay.core.model.domain.Bank import com.mifospay.core.model.domain.BankAccountDetails import com.mifospay.core.model.domain.BankType -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -26,14 +25,12 @@ import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update -import org.mifospay.core.data.repository.local.MifosLocalAssetRepository +import org.mifospay.core.data.repository.local.LocalAssetRepository import org.mifospay.feature.bank.accounts.R import java.util.Random -import javax.inject.Inject -@HiltViewModel -class LinkBankAccountViewModel @Inject constructor( - localAssetRepository: MifosLocalAssetRepository, +class LinkBankAccountViewModel( + localAssetRepository: LocalAssetRepository, ) : ViewModel() { private val searchQuery = MutableStateFlow("") diff --git a/feature/auth/build.gradle.kts b/feature/auth/build.gradle.kts index 31e838893..ae4c6d07b 100644 --- a/feature/auth/build.gradle.kts +++ b/feature/auth/build.gradle.kts @@ -20,8 +20,6 @@ android { } dependencies { - implementation(projects.core.data) - implementation(projects.libs.countryCodePicker) // Credentials Manager diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt new file mode 100644 index 000000000..7da08aa6a --- /dev/null +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.auth.login.LoginViewModel +import org.mifospay.feature.auth.mobileVerify.MobileVerificationViewModel +import org.mifospay.feature.auth.signup.SignupViewModel + +val AuthModule = module { + viewModel { + LoginViewModel( + mUseCaseHandler = get(), + authenticateUserUseCase = get(), + fetchClientDataUseCase = get(), + fetchUserDetailsUseCase = get(), + preferencesHelper = get(), + ) + } + viewModel { + SignupViewModel( + localAssetRepository = get(), + useCaseHandler = get(), + preferencesHelper = get(), + searchClientUseCase = get(), + createClientUseCase = get(), + createUserUseCase = get(), + updateUserUseCase = get(), + authenticateUserUseCase = get(), + fetchClientDataUseCase = get(), + deleteUserUseCase = get(), + fetchUserDetailsUseCase = get(), + ) + } + viewModel { + MobileVerificationViewModel( + mUseCaseHandler = get(), + searchClientUseCase = get(), + ) + } +} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt index efc373fe5..4cddd202e 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt @@ -43,8 +43,8 @@ import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosOutlinedTextField @@ -59,7 +59,7 @@ import org.mifospay.feature.auth.socialSignup.SocialSignupMethodContentScreen internal fun LoginScreen( navigateToPasscodeScreen: () -> Unit, modifier: Modifier = Modifier, - viewModel: LoginViewModel = hiltViewModel(), + viewModel: LoginViewModel = koinViewModel(), navigateToSignupScreen: () -> Unit, ) { val context = LocalContext.current diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt index 6ecde19a8..8ed1a1cec 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt @@ -14,7 +14,6 @@ import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.client.Client import com.mifospay.core.model.domain.user.User import com.mifospay.core.model.entity.UserWithRole -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.update @@ -24,10 +23,8 @@ import org.mifospay.core.data.domain.usecase.client.FetchClientData import org.mifospay.core.data.domain.usecase.user.AuthenticateUser import org.mifospay.core.data.domain.usecase.user.FetchUserDetails import org.mifospay.core.datastore.PreferencesHelper -import javax.inject.Inject -@HiltViewModel -class LoginViewModel @Inject constructor( +class LoginViewModel( private val mUseCaseHandler: UseCaseHandler, private val authenticateUserUseCase: AuthenticateUser, private val fetchClientDataUseCase: FetchClientData, diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt index ef304a4e9..db9ec6611 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt @@ -39,9 +39,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifos.library.countrycodepicker.CountryCodePicker +import org.koin.androidx.compose.koinViewModel import org.mifospay.common.Constants import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosLoadingWheel @@ -53,7 +53,7 @@ import org.mifospay.feature.auth.R internal fun MobileVerificationScreen( onOtpVerificationSuccess: (String) -> Unit, modifier: Modifier = Modifier, - viewModel: MobileVerificationViewModel = hiltViewModel(), + viewModel: MobileVerificationViewModel = koinViewModel(), ) { val context = LocalContext.current val uiState by viewModel.uiState.collectAsStateWithLifecycle() diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt index 001e82647..fa0e3b7ab 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt @@ -14,7 +14,6 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -23,11 +22,9 @@ import kotlinx.coroutines.launch import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.client.SearchClient -import javax.inject.Inject -@HiltViewModel @Suppress("UnusedParameter") -class MobileVerificationViewModel @Inject constructor( +class MobileVerificationViewModel( private val mUseCaseHandler: UseCaseHandler, private val searchClientUseCase: SearchClient, ) : ViewModel() { diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt index 1306520e9..d52642be0 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt @@ -42,11 +42,11 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifospay.core.model.State import com.mifospay.core.model.signup.PasswordStrength import com.mifospay.core.model.signup.SignupData +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.data.util.Constants.MIFOS_MERCHANT_SAVINGS_PRODUCT_ID import org.mifospay.core.designsystem.component.MfOutlinedTextField import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel @@ -68,7 +68,7 @@ internal fun SignupScreen( businessName: String, onLoginSuccess: () -> Unit, modifier: Modifier = Modifier, - viewModel: SignupViewModel = hiltViewModel(), + viewModel: SignupViewModel = koinViewModel(), ) { val context = LocalContext.current diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt index e6f664726..c9e3aeb77 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt @@ -20,7 +20,6 @@ import com.mifospay.core.model.domain.user.UpdateUserEntityClients import com.mifospay.core.model.domain.user.User import com.mifospay.core.model.entity.UserWithRole import com.mifospay.core.model.signup.SignupData -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine @@ -40,10 +39,8 @@ import org.mifospay.core.data.domain.usecase.user.FetchUserDetails import org.mifospay.core.data.domain.usecase.user.UpdateUser import org.mifospay.core.data.repository.local.LocalAssetRepository import org.mifospay.core.datastore.PreferencesHelper -import javax.inject.Inject -@HiltViewModel -class SignupViewModel @Inject constructor( +class SignupViewModel( localAssetRepository: LocalAssetRepository, private val useCaseHandler: UseCaseHandler, private val preferencesHelper: PreferencesHelper, diff --git a/feature/editpassword/build.gradle.kts b/feature/editpassword/build.gradle.kts index 0fd1e480d..34b701da8 100644 --- a/feature/editpassword/build.gradle.kts +++ b/feature/editpassword/build.gradle.kts @@ -16,6 +16,4 @@ android { namespace = "org.mifospay.feature.editpassword" } -dependencies { - implementation(projects.core.data) -} \ No newline at end of file +dependencies {} \ No newline at end of file diff --git a/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordScreen.kt b/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordScreen.kt index 9d04e31c3..e49c4ede1 100644 --- a/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordScreen.kt +++ b/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordScreen.kt @@ -35,9 +35,9 @@ 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 kotlinx.coroutines.launch +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfPasswordTextField import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosScaffold @@ -48,7 +48,7 @@ internal fun EditPasswordScreen( onBackPress: () -> Unit, onCancelChanges: () -> Unit, modifier: Modifier = Modifier, - viewModel: EditPasswordViewModel = hiltViewModel(), + viewModel: EditPasswordViewModel = koinViewModel(), ) { val editPasswordUiState by viewModel.editPasswordUiState.collectAsStateWithLifecycle() EditPasswordScreen( diff --git a/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordViewModel.kt b/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordViewModel.kt index c22134728..f905b6e28 100644 --- a/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordViewModel.kt +++ b/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordViewModel.kt @@ -11,7 +11,6 @@ package org.mifospay.feature.editpassword import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.user.UpdateUserEntityPassword -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.common.Constants @@ -20,11 +19,9 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.user.AuthenticateUser import org.mifospay.core.data.domain.usecase.user.UpdateUser import org.mifospay.core.datastore.PreferencesHelper -import javax.inject.Inject -@HiltViewModel @Suppress("NestedBlockDepth") -class EditPasswordViewModel @Inject constructor( +class EditPasswordViewModel( private val mUseCaseHandler: UseCaseHandler, private val mPreferencesHelper: PreferencesHelper, private val authenticateUserUseCase: AuthenticateUser, diff --git a/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/di/EditPasswordModule.kt b/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/di/EditPasswordModule.kt new file mode 100644 index 000000000..ed1432c0a --- /dev/null +++ b/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/di/EditPasswordModule.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.editpassword.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.editpassword.EditPasswordViewModel + +val EditPasswordModule = module { + viewModel { + EditPasswordViewModel( + mUseCaseHandler = get(), + mPreferencesHelper = get(), + authenticateUserUseCase = get(), + updateUserUseCase = get(), + ) + } +} diff --git a/feature/faq/build.gradle.kts b/feature/faq/build.gradle.kts index b735d0ec9..053183d86 100644 --- a/feature/faq/build.gradle.kts +++ b/feature/faq/build.gradle.kts @@ -16,6 +16,4 @@ android { namespace = "org.mifospay.feature.faq" } -dependencies { - -} \ No newline at end of file +dependencies { } \ No newline at end of file diff --git a/feature/faq/src/main/kotlin/org/mifospay/feature/faq/FAQViewModel.kt b/feature/faq/src/main/kotlin/org/mifospay/feature/faq/FAQViewModel.kt index 70c74979b..1a5376313 100644 --- a/feature/faq/src/main/kotlin/org/mifospay/feature/faq/FAQViewModel.kt +++ b/feature/faq/src/main/kotlin/org/mifospay/feature/faq/FAQViewModel.kt @@ -10,11 +10,8 @@ package org.mifospay.feature.faq import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject -@HiltViewModel -internal class FAQViewModel @Inject constructor() : ViewModel() { +internal class FAQViewModel : ViewModel() { /** * Retrieves a list of Frequently Asked Questions (FAQs). diff --git a/feature/faq/src/main/kotlin/org/mifospay/feature/faq/FaqScreen.kt b/feature/faq/src/main/kotlin/org/mifospay/feature/faq/FaqScreen.kt index 47675f9bc..a3a7a5426 100644 --- a/feature/faq/src/main/kotlin/org/mifospay/feature/faq/FaqScreen.kt +++ b/feature/faq/src/main/kotlin/org/mifospay/feature/faq/FaqScreen.kt @@ -18,7 +18,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.navigation.compose.hiltViewModel +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MifosTopBar import org.mifospay.core.ui.FaqItemScreen @@ -26,7 +26,7 @@ import org.mifospay.core.ui.FaqItemScreen internal fun FaqScreenRoute( navigateBack: () -> Unit, modifier: Modifier = Modifier, - faqViewModel: FAQViewModel = hiltViewModel(), + faqViewModel: FAQViewModel = koinViewModel(), ) { FaqScreen( modifier = modifier, diff --git a/core/network/src/main/kotlin/org/mifospay/core/network/di/Qualifier.kt b/feature/faq/src/main/kotlin/org/mifospay/feature/faq/di/FaqModule.kt similarity index 58% rename from core/network/src/main/kotlin/org/mifospay/core/network/di/Qualifier.kt rename to feature/faq/src/main/kotlin/org/mifospay/feature/faq/di/FaqModule.kt index 10c2ed1a8..844a6e8cc 100644 --- a/core/network/src/main/kotlin/org/mifospay/core/network/di/Qualifier.kt +++ b/feature/faq/src/main/kotlin/org/mifospay/feature/faq/di/FaqModule.kt @@ -7,14 +7,15 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.network.di +package org.mifospay.feature.faq.di -import javax.inject.Qualifier +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.faq.FAQViewModel -@Qualifier -@Retention(AnnotationRetention.BINARY) -annotation class SelfServiceApi +val FaqModule = module { -@Qualifier -@Retention(AnnotationRetention.BINARY) -annotation class FineractApi + viewModel { + FAQViewModel() + } +} diff --git a/feature/history/build.gradle.kts b/feature/history/build.gradle.kts index 6cae0e1c1..77b20cc0b 100644 --- a/feature/history/build.gradle.kts +++ b/feature/history/build.gradle.kts @@ -17,5 +17,6 @@ android { } dependencies { - implementation(projects.core.data) + + implementation(projects.libs.pullrefresh) } \ No newline at end of file diff --git a/feature/history/src/main/kotlin/org/mifospay/feature/di/HistoryModule.kt b/feature/history/src/main/kotlin/org/mifospay/feature/di/HistoryModule.kt new file mode 100644 index 000000000..e2be88b04 --- /dev/null +++ b/feature/history/src/main/kotlin/org/mifospay/feature/di/HistoryModule.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.history.HistoryViewModel +import org.mifospay.feature.specific.transactions.SpecificTransactionsViewModel +import org.mifospay.feature.transaction.detail.TransactionDetailViewModel + +val HistoryModule = module { + + viewModel { + HistoryViewModel( + mUseCaseHandler = get(), + mLocalRepository = get(), + mFetchAccountUseCase = get(), + fetchAccountTransactionsUseCase = get(), + ) + } + + viewModel { + SpecificTransactionsViewModel( + mUseCaseFactory = get(), + mTaskLooper = get(), + savedStateHandle = get(), + ) + } + + viewModel { + TransactionDetailViewModel(mUseCaseHandler = get(), mFetchAccountTransferUseCase = get()) + } +} diff --git a/feature/history/src/main/kotlin/org/mifospay/feature/history/HistoryScreen.kt b/feature/history/src/main/kotlin/org/mifospay/feature/history/HistoryScreen.kt index 328b6bbb7..93077d2e2 100644 --- a/feature/history/src/main/kotlin/org/mifospay/feature/history/HistoryScreen.kt +++ b/feature/history/src/main/kotlin/org/mifospay/feature/history/HistoryScreen.kt @@ -36,12 +36,12 @@ 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 com.mifospay.core.model.domain.Currency import com.mifospay.core.model.domain.Transaction import com.mifospay.core.model.domain.TransactionType import com.mifospay.core.model.entity.accounts.savings.TransferDetail +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MifosBottomSheet import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosLoadingWheel @@ -56,7 +56,7 @@ fun HistoryScreen( viewReceipt: (String) -> Unit, accountClicked: (String, ArrayList) -> Unit, modifier: Modifier = Modifier, - viewModel: HistoryViewModel = hiltViewModel(), + viewModel: HistoryViewModel = koinViewModel(), ) { val historyUiState by viewModel.historyUiState.collectAsStateWithLifecycle() diff --git a/feature/history/src/main/kotlin/org/mifospay/feature/history/HistoryViewModel.kt b/feature/history/src/main/kotlin/org/mifospay/feature/history/HistoryViewModel.kt index 1bbb8fad6..16bc6e090 100644 --- a/feature/history/src/main/kotlin/org/mifospay/feature/history/HistoryViewModel.kt +++ b/feature/history/src/main/kotlin/org/mifospay/feature/history/HistoryViewModel.kt @@ -11,7 +11,6 @@ package org.mifospay.feature.history import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.Transaction -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCase @@ -19,10 +18,8 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.account.FetchAccount import org.mifospay.core.data.domain.usecase.account.FetchAccountTransactions import org.mifospay.core.data.repository.local.LocalRepository -import javax.inject.Inject -@HiltViewModel -class HistoryViewModel @Inject constructor( +class HistoryViewModel( private val mUseCaseHandler: UseCaseHandler, private val mLocalRepository: LocalRepository, private val mFetchAccountUseCase: FetchAccount, diff --git a/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsScreen.kt b/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsScreen.kt index 907853c89..83cc4297b 100644 --- a/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsScreen.kt +++ b/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsScreen.kt @@ -34,12 +34,12 @@ 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 com.mifospay.core.model.domain.Transaction import com.mifospay.core.model.domain.TransactionType import com.mifospay.core.model.domain.client.Client import com.mifospay.core.model.entity.accounts.savings.SavingAccount +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.component.MifosScaffold import org.mifospay.core.designsystem.icon.MifosIcons @@ -56,7 +56,7 @@ internal fun SpecificTransactionsScreen( backPress: () -> Unit, transactionItemClicked: (String) -> Unit, modifier: Modifier = Modifier, - viewModel: SpecificTransactionsViewModel = hiltViewModel(), + viewModel: SpecificTransactionsViewModel = koinViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() diff --git a/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsViewModel.kt b/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsViewModel.kt index 03276dc37..ad53eef1d 100644 --- a/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsViewModel.kt +++ b/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.specific.transactions import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.Transaction -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import org.mifospay.core.data.base.TaskLooper @@ -23,10 +22,8 @@ import org.mifospay.core.data.util.Constants import org.mifospay.feature.specific.transactions.SpecificTransactionsUiState.Loading import org.mifospay.feature.specific.transactions.navigation.ACCOUNT_NUMBER_ARG import org.mifospay.feature.specific.transactions.navigation.TRANSACTIONS_ARG -import javax.inject.Inject -@HiltViewModel -class SpecificTransactionsViewModel @Inject constructor( +class SpecificTransactionsViewModel( private val mUseCaseFactory: UseCaseFactory, private var mTaskLooper: TaskLooper? = null, savedStateHandle: SavedStateHandle, diff --git a/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailScreen.kt b/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailScreen.kt index ffb59961d..d57010eb1 100644 --- a/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailScreen.kt +++ b/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailScreen.kt @@ -33,11 +33,11 @@ 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 com.mifospay.core.model.domain.Transaction import com.mifospay.core.model.domain.TransactionType import com.mifospay.core.model.entity.accounts.savings.TransferDetail +import org.koin.androidx.compose.koinViewModel import org.mifospay.common.Constants import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.theme.MifosTheme @@ -51,7 +51,7 @@ internal fun TransactionDetailScreen( viewReceipt: () -> Unit, accountClicked: (String) -> Unit, modifier: Modifier = Modifier, - viewModel: TransactionDetailViewModel = hiltViewModel(), + viewModel: TransactionDetailViewModel = koinViewModel(), ) { val uiState = viewModel.transactionDetailUiState.collectAsStateWithLifecycle() diff --git a/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailViewModel.kt b/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailViewModel.kt index 5f33079af..5543b2228 100644 --- a/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailViewModel.kt +++ b/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailViewModel.kt @@ -11,15 +11,12 @@ package org.mifospay.feature.transaction.detail import androidx.lifecycle.ViewModel import com.mifospay.core.model.entity.accounts.savings.TransferDetail -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.account.FetchAccountTransfer -import javax.inject.Inject -@HiltViewModel -class TransactionDetailViewModel @Inject constructor( +class TransactionDetailViewModel( private val mUseCaseHandler: UseCaseHandler, private val mFetchAccountTransferUseCase: FetchAccountTransfer, ) : ViewModel() { diff --git a/feature/home/build.gradle.kts b/feature/home/build.gradle.kts index 9e50d5e5f..0fe68be92 100644 --- a/feature/home/build.gradle.kts +++ b/feature/home/build.gradle.kts @@ -17,5 +17,5 @@ android { } dependencies { - implementation(projects.core.data) + } \ No newline at end of file diff --git a/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeScreen.kt b/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeScreen.kt index d3ad4d895..847d509ce 100644 --- a/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeScreen.kt +++ b/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeScreen.kt @@ -45,12 +45,12 @@ import androidx.compose.ui.text.font.FontWeight 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 com.mifospay.core.model.domain.Account import com.mifospay.core.model.domain.Currency import com.mifospay.core.model.domain.Transaction import com.mifospay.core.model.domain.TransactionType +import org.koin.androidx.compose.koinViewModel import org.mifospay.common.Utils import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.theme.border @@ -63,7 +63,7 @@ internal fun HomeRoute( onRequest: (String) -> Unit, onPay: () -> Unit, modifier: Modifier = Modifier, - homeViewModel: HomeViewModel = hiltViewModel(), + homeViewModel: HomeViewModel = koinViewModel(), ) { val homeUIState by homeViewModel .homeUIState diff --git a/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeViewModel.kt b/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeViewModel.kt index ca572713f..eb2d3832a 100644 --- a/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeViewModel.kt +++ b/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.home import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.Account import com.mifospay.core.model.domain.Transaction -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -24,10 +23,8 @@ import org.mifospay.core.data.domain.usecase.history.HistoryContract import org.mifospay.core.data.domain.usecase.history.TransactionsHistory import org.mifospay.core.data.repository.local.LocalRepository import org.mifospay.core.datastore.PreferencesHelper -import javax.inject.Inject -@HiltViewModel -class HomeViewModel @Inject constructor( +class HomeViewModel( private val useCaseHandler: UseCaseHandler, private val localRepository: LocalRepository, private val preferencesHelper: PreferencesHelper, diff --git a/feature/home/src/main/kotlin/org/mifospay/feature/home/di/HomeModule.kt b/feature/home/src/main/kotlin/org/mifospay/feature/home/di/HomeModule.kt new file mode 100644 index 000000000..317f70e96 --- /dev/null +++ b/feature/home/src/main/kotlin/org/mifospay/feature/home/di/HomeModule.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.home.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.home.HomeViewModel + +val HomeModule = module { + viewModel { + HomeViewModel( + useCaseHandler = get(), + localRepository = get(), + preferencesHelper = get(), + fetchAccountUseCase = get(), + transactionsHistory = get(), + ) + } +} diff --git a/feature/invoices/build.gradle.kts b/feature/invoices/build.gradle.kts index 93df48185..94232da14 100644 --- a/feature/invoices/build.gradle.kts +++ b/feature/invoices/build.gradle.kts @@ -16,6 +16,4 @@ android { namespace = "org.mifospay.invoices" } -dependencies { - implementation(projects.core.data) -} \ No newline at end of file +dependencies {} \ No newline at end of file diff --git a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt index 80285cd11..5abca0b6d 100644 --- a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt +++ b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt @@ -35,10 +35,10 @@ 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 com.mifospay.core.model.entity.Invoice import com.mifospay.core.model.utils.DateHelper +import org.koin.androidx.compose.koinViewModel import org.mifospay.common.Constants import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel import org.mifospay.core.designsystem.component.MifosScaffold @@ -51,7 +51,7 @@ internal fun InvoiceDetailScreen( onBackPress: () -> Unit, navigateToReceiptScreen: (String) -> Unit, modifier: Modifier = Modifier, - viewModel: InvoiceDetailViewModel = hiltViewModel(), + viewModel: InvoiceDetailViewModel = koinViewModel(), ) { val invoiceDetailUiState by viewModel.invoiceDetailUiState.collectAsStateWithLifecycle() diff --git a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailViewModel.kt b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailViewModel.kt index baa548f54..d96d64928 100644 --- a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailViewModel.kt +++ b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailViewModel.kt @@ -13,7 +13,6 @@ import android.net.Uri import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import com.mifospay.core.model.entity.Invoice -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCase @@ -21,10 +20,8 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.invoice.FetchInvoice import org.mifospay.core.datastore.PreferencesHelper import org.mifospay.feature.invoices.navigation.INVOICE_DATA_ARG -import javax.inject.Inject -@HiltViewModel -class InvoiceDetailViewModel @Inject constructor( +class InvoiceDetailViewModel( private val mUseCaseHandler: UseCaseHandler, private val mPreferencesHelper: PreferencesHelper, private val fetchInvoiceUseCase: FetchInvoice, diff --git a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceScreen.kt b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceScreen.kt index f2e6a32f3..6768fe3b5 100644 --- a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceScreen.kt +++ b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceScreen.kt @@ -23,9 +23,9 @@ 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.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifospay.core.model.entity.Invoice +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MifosLoadingWheel import org.mifospay.core.designsystem.icon.MifosIcons.Info import org.mifospay.core.designsystem.theme.MifosTheme @@ -36,7 +36,7 @@ import org.mifospay.invoices.R fun InvoiceScreenRoute( navigateToInvoiceDetailScreen: (Uri) -> Unit, modifier: Modifier = Modifier, - viewModel: InvoicesViewModel = hiltViewModel(), + viewModel: InvoicesViewModel = koinViewModel(), ) { val invoiceUiState by viewModel.invoiceUiState.collectAsStateWithLifecycle() InvoiceScreen( diff --git a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoicesViewModel.kt b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoicesViewModel.kt index 6457b089d..5ef00c24c 100644 --- a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoicesViewModel.kt +++ b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoicesViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.invoices import android.net.Uri import androidx.lifecycle.ViewModel import com.mifospay.core.model.entity.Invoice -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.common.Constants.INVOICE_DOMAIN @@ -20,10 +19,8 @@ import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.invoice.FetchInvoices import org.mifospay.core.datastore.PreferencesHelper -import javax.inject.Inject -@HiltViewModel -class InvoicesViewModel @Inject constructor( +class InvoicesViewModel( private val mUseCaseHandler: UseCaseHandler, private val mPreferencesHelper: PreferencesHelper, private val fetchInvoicesUseCase: FetchInvoices, diff --git a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/di/InvoicesModule.kt b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/di/InvoicesModule.kt new file mode 100644 index 000000000..20543b49e --- /dev/null +++ b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/di/InvoicesModule.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.invoices.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.invoices.InvoiceDetailViewModel +import org.mifospay.feature.invoices.InvoicesViewModel + +val InvoicesModule = module { + + viewModel { + InvoiceDetailViewModel( + mUseCaseHandler = get(), + mPreferencesHelper = get(), + fetchInvoiceUseCase = get(), + savedStateHandle = get(), + ) + } + + viewModel { + InvoicesViewModel( + mUseCaseHandler = get(), + mPreferencesHelper = get(), + fetchInvoicesUseCase = get(), + ) + } +} diff --git a/feature/kyc/build.gradle.kts b/feature/kyc/build.gradle.kts index c57fe120b..d855b9d50 100644 --- a/feature/kyc/build.gradle.kts +++ b/feature/kyc/build.gradle.kts @@ -17,8 +17,6 @@ android { } dependencies { - implementation(projects.core.data) - implementation(projects.libs.countryCodePicker) implementation(projects.libs.pullrefresh) diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt index da040068b..b8d30baad 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt @@ -41,12 +41,12 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifos.library.pullrefresh.PullRefreshIndicator import com.mifos.library.pullrefresh.pullRefresh import com.mifos.library.pullrefresh.rememberPullRefreshState import com.mifospay.core.model.entity.kyc.KYCLevel1Details +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosOverlayLoadingWheel import org.mifospay.core.designsystem.icon.MifosIcons @@ -59,7 +59,7 @@ fun KYCScreen( onLevel2Clicked: () -> Unit, onLevel3Clicked: () -> Unit, modifier: Modifier = Modifier, - viewModel: KYCDescriptionViewModel = hiltViewModel(), + viewModel: KYCDescriptionViewModel = koinViewModel(), ) { val kUiState by viewModel.kycDescriptionState.collectAsState() val isRefreshing by viewModel.isRefreshing.collectAsStateWithLifecycle() diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt index c20a7776b..a2f9fd98b 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.kyc import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mifospay.core.model.entity.kyc.KYCLevel1Details -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -23,10 +22,8 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.kyc.FetchKYCLevel1Details import org.mifospay.core.data.repository.local.LocalRepository import org.mifospay.feature.kyc.KYCDescriptionUiState.Loading -import javax.inject.Inject -@HiltViewModel -class KYCDescriptionViewModel @Inject constructor( +class KYCDescriptionViewModel( private val mUseCaseHandler: UseCaseHandler, private val mLocalRepository: LocalRepository, private val fetchKYCLevel1DetailsUseCase: FetchKYCLevel1Details, diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1Screen.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1Screen.kt index 501f40cec..e56cf5a68 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1Screen.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1Screen.kt @@ -38,7 +38,6 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState import com.maxkeppeler.sheets.calendar.CalendarDialog @@ -46,6 +45,7 @@ import com.maxkeppeler.sheets.calendar.models.CalendarConfig import com.maxkeppeler.sheets.calendar.models.CalendarSelection import com.maxkeppeler.sheets.calendar.models.CalendarStyle import com.mifos.library.countrycodepicker.CountryCodePicker +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosOutlinedTextField @@ -57,7 +57,7 @@ import java.time.format.DateTimeFormatter internal fun KYCLevel1Screen( navigateToKycLevel2: () -> Unit, modifier: Modifier = Modifier, - viewModel: KYCLevel1ViewModel = hiltViewModel(), + viewModel: KYCLevel1ViewModel = koinViewModel(), ) { val kyc1uiState by viewModel.kyc1uiState.collectAsStateWithLifecycle() diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt index 1733a968a..3e7f282d1 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt @@ -11,7 +11,6 @@ package org.mifospay.feature.kyc import androidx.lifecycle.ViewModel import com.mifospay.core.model.entity.kyc.KYCLevel1Details -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCase @@ -19,10 +18,8 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.kyc.UploadKYCLevel1Details import org.mifospay.core.data.repository.local.LocalRepository import org.mifospay.feature.kyc.KYCLevel1UiState.Loading -import javax.inject.Inject -@HiltViewModel -class KYCLevel1ViewModel @Inject constructor( +class KYCLevel1ViewModel( private val mUseCaseHandler: UseCaseHandler, private val mLocalRepository: LocalRepository, private val uploadKYCLevel1DetailsUseCase: UploadKYCLevel1Details, diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2Screen.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2Screen.kt index 42363e4ee..35d9bb24a 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2Screen.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2Screen.kt @@ -50,12 +50,12 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale import androidx.core.content.ContextCompat -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.launch +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosOutlinedTextField @@ -66,7 +66,7 @@ import org.mifospay.kyc.R internal fun KYCLevel2Screen( onSuccessKyc2: () -> Unit, modifier: Modifier = Modifier, - viewModel: KYCLevel2ViewModel = hiltViewModel(), + viewModel: KYCLevel2ViewModel = koinViewModel(), ) { val kyc2uiState by viewModel.kyc2uiState.collectAsStateWithLifecycle() diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2ViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2ViewModel.kt index 04fba616d..185589b27 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2ViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2ViewModel.kt @@ -11,7 +11,6 @@ package org.mifospay.feature.kyc import android.net.Uri import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -24,10 +23,8 @@ import org.mifospay.core.data.domain.usecase.kyc.UploadKYCDocs import org.mifospay.core.datastore.PreferencesHelper import org.mifospay.feature.kyc.KYCLevel2UiState.Loading import java.io.File -import javax.inject.Inject -@HiltViewModel -class KYCLevel2ViewModel @Inject constructor( +class KYCLevel2ViewModel( private val mUseCaseHandler: UseCaseHandler, private val preferencesHelper: PreferencesHelper, private val uploadKYCDocsUseCase: UploadKYCDocs, diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel3Screen.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel3Screen.kt index 929282dcd..0f37d7b17 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel3Screen.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel3Screen.kt @@ -25,8 +25,8 @@ 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.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosOutlinedTextField @@ -36,7 +36,7 @@ import org.mifospay.kyc.R @Composable internal fun KYCLevel3Screen( modifier: Modifier = Modifier, - viewModel: KYCLevel3ViewModel = hiltViewModel(), + viewModel: KYCLevel3ViewModel = koinViewModel(), ) { val kyc3uiState by viewModel.kyc3uiState.collectAsStateWithLifecycle() diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel3ViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel3ViewModel.kt index 73ed5e5a6..bddd96f58 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel3ViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel3ViewModel.kt @@ -10,17 +10,14 @@ package org.mifospay.feature.kyc import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.repository.local.LocalRepository import org.mifospay.feature.kyc.KYCLevel3UiState.Loading -import javax.inject.Inject -@HiltViewModel @Suppress("UnusedPrivateProperty") -class KYCLevel3ViewModel @Inject constructor( +class KYCLevel3ViewModel( private val mUseCaseHandler: UseCaseHandler, private val mLocalRepository: LocalRepository, ) : ViewModel() { diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/di/KYCModule.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/di/KYCModule.kt new file mode 100644 index 000000000..ba1a6d1aa --- /dev/null +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/di/KYCModule.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.kyc.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.kyc.KYCDescriptionViewModel +import org.mifospay.feature.kyc.KYCLevel1ViewModel +import org.mifospay.feature.kyc.KYCLevel2ViewModel +import org.mifospay.feature.kyc.KYCLevel3ViewModel + +val KYCModule = module { + viewModel { + KYCDescriptionViewModel( + mUseCaseHandler = get(), + mLocalRepository = get(), + fetchKYCLevel1DetailsUseCase = get(), + ) + } + + viewModel { + KYCLevel1ViewModel( + mUseCaseHandler = get(), + mLocalRepository = get(), + uploadKYCLevel1DetailsUseCase = get(), + ) + } + + viewModel { + KYCLevel2ViewModel( + mUseCaseHandler = get(), + preferencesHelper = get(), + uploadKYCDocsUseCase = get(), + ) + } + + viewModel { + KYCLevel3ViewModel( + mUseCaseHandler = get(), + mLocalRepository = get(), + ) + } +} diff --git a/feature/make-transfer/build.gradle.kts b/feature/make-transfer/build.gradle.kts index 4d74d5926..9b2e16cf6 100644 --- a/feature/make-transfer/build.gradle.kts +++ b/feature/make-transfer/build.gradle.kts @@ -16,6 +16,4 @@ android { namespace = "org.mifospay.feature.make.transfer" } -dependencies { - implementation(projects.core.data) -} +dependencies { } diff --git a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt index 6b56baf7e..4a6bf03cd 100644 --- a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt +++ b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt @@ -41,8 +41,8 @@ import androidx.compose.ui.text.font.FontWeight 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.koin.androidx.compose.koinViewModel import org.mifospay.common.Constants import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosLoadingWheel @@ -51,7 +51,7 @@ import org.mifospay.core.designsystem.component.MifosLoadingWheel internal fun MakeTransferScreenRoute( onDismiss: () -> Unit, modifier: Modifier = Modifier, - viewModel: MakeTransferViewModel = hiltViewModel(), + viewModel: MakeTransferViewModel = koinViewModel(), ) { // TODO: commented out because not using it // val fetchPayeeClient by viewModel.fetchPayeeClient.collectAsStateWithLifecycle() diff --git a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferViewModel.kt b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferViewModel.kt index a4bbda333..1a1ed3df1 100644 --- a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferViewModel.kt +++ b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.make.transfer import androidx.lifecycle.SavedStateHandle 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 @@ -27,10 +26,8 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.account.TransferFunds import org.mifospay.core.data.domain.usecase.client.SearchClient import org.mifospay.core.data.repository.local.LocalRepository -import javax.inject.Inject -@HiltViewModel -class MakeTransferViewModel @Inject constructor( +class MakeTransferViewModel( savedStateHandle: SavedStateHandle, private val useCaseHandler: UseCaseHandler, private val searchClientUseCase: SearchClient, diff --git a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/di/MakeTransferModule.kt b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/di/MakeTransferModule.kt new file mode 100644 index 000000000..226f61da0 --- /dev/null +++ b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/di/MakeTransferModule.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.make.transfer.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.make.transfer.MakeTransferViewModel + +val MakeTransferModule = module { + viewModel { + MakeTransferViewModel( + savedStateHandle = get(), + useCaseHandler = get(), + searchClientUseCase = get(), + transferFundsUseCase = get(), + localRepository = get(), + ) + } +} diff --git a/feature/merchants/build.gradle.kts b/feature/merchants/build.gradle.kts index 01c04256a..3519fb03a 100644 --- a/feature/merchants/build.gradle.kts +++ b/feature/merchants/build.gradle.kts @@ -17,6 +17,5 @@ android { } dependencies { - implementation(projects.core.data) implementation(projects.libs.pullrefresh) } \ No newline at end of file diff --git a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantTransferViewModel.kt b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantTransferViewModel.kt index 679505298..8141528ca 100644 --- a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantTransferViewModel.kt +++ b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantTransferViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.merchants import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.Transaction -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -31,10 +30,8 @@ import org.mifospay.core.data.repository.local.LocalRepository import org.mifospay.core.data.util.Constants.FETCH_ACCOUNT_TRANSFER_USECASE import org.mifospay.core.datastore.PreferencesHelper import org.mifospay.feature.merchants.MerchantTransferUiState.Loading -import javax.inject.Inject -@HiltViewModel -class MerchantTransferViewModel @Inject constructor( +class MerchantTransferViewModel( private val mUseCaseHandler: UseCaseHandler, private val localRepository: LocalRepository, private val preferencesHelper: PreferencesHelper, diff --git a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantViewModel.kt b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantViewModel.kt index 603d72b56..19180991c 100644 --- a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantViewModel.kt +++ b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.merchants import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mifospay.core.model.entity.accounts.savings.SavingsWithAssociations -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -28,17 +27,14 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.account.FetchMerchants import org.mifospay.core.data.domain.usecase.client.FetchClientDetails import org.mifospay.core.data.util.Constants -import javax.inject.Inject -@HiltViewModel -class MerchantViewModel @Inject constructor( +class MerchantViewModel( private val mUseCaseHandler: UseCaseHandler, private val mFetchMerchantsUseCase: FetchMerchants, private val mUseCaseFactory: UseCaseFactory, -) : ViewModel() { + private val mTaskLooper: TaskLooper, - @Inject - lateinit var mTaskLooper: TaskLooper +) : ViewModel() { private val _searchQuery = MutableStateFlow("") private val searchQuery: StateFlow = _searchQuery.asStateFlow() diff --git a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/di/MerchantsModule.kt b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/di/MerchantsModule.kt new file mode 100644 index 000000000..00cc5d8d8 --- /dev/null +++ b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/di/MerchantsModule.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.merchants.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.merchants.MerchantTransferViewModel +import org.mifospay.feature.merchants.MerchantViewModel + +val MerchantsModule = module { + viewModel { + MerchantViewModel( + mUseCaseHandler = get(), + mFetchMerchantsUseCase = get(), + mUseCaseFactory = get(), + mTaskLooper = get(), + ) + } + viewModel { + MerchantTransferViewModel( + mUseCaseHandler = get(), + localRepository = get(), + preferencesHelper = get(), + transactionsHistory = get(), + mUseCaseFactory = get(), + mFetchAccount = get(), + mTaskLooper = get(), + savedStateHandle = get(), + ) + } +} diff --git a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/ui/MerchantScreen.kt b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/ui/MerchantScreen.kt index 665f15394..c1a62dd24 100644 --- a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/ui/MerchantScreen.kt +++ b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/ui/MerchantScreen.kt @@ -35,13 +35,13 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.compose.rememberNavController import com.mifos.library.pullrefresh.PullRefreshIndicator import com.mifos.library.pullrefresh.pullRefresh import com.mifos.library.pullrefresh.rememberPullRefreshState import com.mifospay.core.model.entity.accounts.savings.SavingsWithAssociations +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.MifosTheme @@ -54,7 +54,7 @@ import org.mifospay.feature.merchants.navigation.navigateToMerchantTransferScree @Composable fun MerchantScreen( modifier: Modifier = Modifier, - viewModel: MerchantViewModel = hiltViewModel(), + viewModel: MerchantViewModel = koinViewModel(), ) { val merchantUiState by viewModel.merchantUiState.collectAsStateWithLifecycle() val merchantsListUiState by viewModel.merchantsListUiState.collectAsStateWithLifecycle() diff --git a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/ui/MerchantTransferScreen.kt b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/ui/MerchantTransferScreen.kt index 8b54f0bbe..077f64682 100644 --- a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/ui/MerchantTransferScreen.kt +++ b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/ui/MerchantTransferScreen.kt @@ -50,12 +50,12 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifospay.core.model.domain.Transaction import com.mifospay.core.model.domain.TransactionType import com.mifospay.core.model.domain.client.Client import com.mifospay.core.model.entity.accounts.savings.SavingAccount +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.component.MfOutlinedTextField import org.mifospay.core.designsystem.component.MifosBottomSheet @@ -78,7 +78,7 @@ internal fun MerchantTransferScreenRoute( onBackPressed: () -> Unit, proceedWithMakeTransferFlow: (String, String) -> Unit, modifier: Modifier = Modifier, - viewModel: MerchantTransferViewModel = hiltViewModel(), + viewModel: MerchantTransferViewModel = koinViewModel(), ) { val uiState by viewModel.uiState.collectAsStateWithLifecycle() val merchantName by viewModel.merchantName.collectAsStateWithLifecycle() diff --git a/feature/notification/build.gradle.kts b/feature/notification/build.gradle.kts index 17f96e99b..43e9782c5 100644 --- a/feature/notification/build.gradle.kts +++ b/feature/notification/build.gradle.kts @@ -17,6 +17,5 @@ android { } dependencies { - implementation(projects.core.data) implementation(projects.libs.pullrefresh) } \ No newline at end of file diff --git a/feature/notification/src/main/kotlin/org/mifospay/feature/notification/NotificationScreen.kt b/feature/notification/src/main/kotlin/org/mifospay/feature/notification/NotificationScreen.kt index c0f308480..925a7aa28 100644 --- a/feature/notification/src/main/kotlin/org/mifospay/feature/notification/NotificationScreen.kt +++ b/feature/notification/src/main/kotlin/org/mifospay/feature/notification/NotificationScreen.kt @@ -32,12 +32,12 @@ 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 com.mifos.library.pullrefresh.PullRefreshIndicator import com.mifos.library.pullrefresh.pullRefresh import com.mifos.library.pullrefresh.rememberPullRefreshState import com.mifospay.core.model.domain.NotificationPayload +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.component.MifosTopAppBar import org.mifospay.core.designsystem.icon.MifosIcons @@ -48,7 +48,7 @@ import org.mifospay.notification.R @Composable fun NotificationScreen( modifier: Modifier = Modifier, - viewmodel: NotificationViewModel = hiltViewModel(), + viewmodel: NotificationViewModel = koinViewModel(), ) { val uiState by viewmodel.notificationUiState.collectAsStateWithLifecycle() val isRefreshing by viewmodel.isRefreshing.collectAsStateWithLifecycle() diff --git a/feature/notification/src/main/kotlin/org/mifospay/feature/notification/NotificationViewModel.kt b/feature/notification/src/main/kotlin/org/mifospay/feature/notification/NotificationViewModel.kt index b3e2314ab..4298f8dd6 100644 --- a/feature/notification/src/main/kotlin/org/mifospay/feature/notification/NotificationViewModel.kt +++ b/feature/notification/src/main/kotlin/org/mifospay/feature/notification/NotificationViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.notification import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mifospay.core.model.domain.NotificationPayload -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -22,10 +21,8 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.notification.FetchNotifications import org.mifospay.core.data.repository.local.LocalRepository import org.mifospay.feature.notification.NotificationUiState.Loading -import javax.inject.Inject -@HiltViewModel -class NotificationViewModel @Inject constructor( +class NotificationViewModel( private val mUseCaseHandler: UseCaseHandler, private val mLocalRepository: LocalRepository, private val fetchNotificationsUseCase: FetchNotifications, diff --git a/feature/notification/src/main/kotlin/org/mifospay/feature/notification/di/NotificationModule.kt b/feature/notification/src/main/kotlin/org/mifospay/feature/notification/di/NotificationModule.kt new file mode 100644 index 000000000..5c8217d6a --- /dev/null +++ b/feature/notification/src/main/kotlin/org/mifospay/feature/notification/di/NotificationModule.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.notification.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.notification.NotificationViewModel + +val NotificationModule = module { + viewModel { + NotificationViewModel( + mUseCaseHandler = get(), + mLocalRepository = get(), + fetchNotificationsUseCase = get(), + ) + } +} diff --git a/feature/payments/build.gradle.kts b/feature/payments/build.gradle.kts index 4ddfcbdc2..ae1b679f8 100644 --- a/feature/payments/build.gradle.kts +++ b/feature/payments/build.gradle.kts @@ -17,6 +17,5 @@ android { } dependencies { - implementation(projects.core.data) implementation(libs.accompanist.pager) } \ No newline at end of file diff --git a/feature/payments/src/main/kotlin/org/mifospay/feature/payments/RequestScreen.kt b/feature/payments/src/main/kotlin/org/mifospay/feature/payments/RequestScreen.kt index 49fa8f9e6..222a24c3c 100644 --- a/feature/payments/src/main/kotlin/org/mifospay/feature/payments/RequestScreen.kt +++ b/feature/payments/src/main/kotlin/org/mifospay/feature/payments/RequestScreen.kt @@ -27,7 +27,7 @@ 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.hilt.navigation.compose.hiltViewModel +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.MifosTheme @@ -35,7 +35,7 @@ import org.mifospay.core.designsystem.theme.MifosTheme fun RequestScreen( showQr: (String) -> Unit, modifier: Modifier = Modifier, - viewModel: TransferViewModel = hiltViewModel(), + viewModel: TransferViewModel = koinViewModel(), ) { val vpa by viewModel.vpa.collectAsState() val mobile by viewModel.mobile.collectAsState() diff --git a/feature/payments/src/main/kotlin/org/mifospay/feature/payments/TransferViewModel.kt b/feature/payments/src/main/kotlin/org/mifospay/feature/payments/TransferViewModel.kt index 3502effe9..4fb2fb8e0 100644 --- a/feature/payments/src/main/kotlin/org/mifospay/feature/payments/TransferViewModel.kt +++ b/feature/payments/src/main/kotlin/org/mifospay/feature/payments/TransferViewModel.kt @@ -11,7 +11,6 @@ package org.mifospay.feature.payments 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.launch @@ -19,10 +18,8 @@ import org.mifospay.core.data.base.UseCase.UseCaseCallback import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.account.FetchAccount import org.mifospay.core.data.repository.local.LocalRepository -import javax.inject.Inject -@HiltViewModel -class TransferViewModel @Inject constructor( +class TransferViewModel( val mUsecaseHandler: UseCaseHandler, val localRepository: LocalRepository, val mFetchAccount: FetchAccount, diff --git a/feature/payments/src/main/kotlin/org/mifospay/feature/payments/di/PaymentsModule.kt b/feature/payments/src/main/kotlin/org/mifospay/feature/payments/di/PaymentsModule.kt new file mode 100644 index 000000000..0abf8b38f --- /dev/null +++ b/feature/payments/src/main/kotlin/org/mifospay/feature/payments/di/PaymentsModule.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.payments.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.payments.TransferViewModel + +val PaymentsModule = module { + viewModel { + TransferViewModel( + mUsecaseHandler = get(), + localRepository = get(), + mFetchAccount = get(), + ) + } +} diff --git a/feature/profile/build.gradle.kts b/feature/profile/build.gradle.kts index 94a9b9509..637ee6226 100644 --- a/feature/profile/build.gradle.kts +++ b/feature/profile/build.gradle.kts @@ -7,7 +7,6 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -import com.android.build.gradle.internal.tasks.ApplicationIdWriterTask plugins { alias(libs.plugins.mifospay.android.feature) @@ -22,8 +21,7 @@ android { } dependencies { - implementation(projects.core.data) implementation(projects.libs.countryCodePicker) - + implementation(libs.squareup.okhttp) implementation(libs.coil.kt.compose) } \ No newline at end of file diff --git a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileScreen.kt b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileScreen.kt index 52a10b100..e33399b72 100644 --- a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileScreen.kt +++ b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileScreen.kt @@ -38,8 +38,8 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider 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.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.ui.ProfileImage @@ -49,7 +49,7 @@ fun ProfileRoute( onEditProfile: () -> Unit, onSettings: () -> Unit, modifier: Modifier = Modifier, - viewModel: ProfileViewModel = hiltViewModel(), + viewModel: ProfileViewModel = koinViewModel(), ) { val profileState by viewModel.profileState.collectAsStateWithLifecycle() diff --git a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileViewModel.kt b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileViewModel.kt index e008b1f2b..dd6d71855 100644 --- a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileViewModel.kt +++ b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileViewModel.kt @@ -13,7 +13,6 @@ import android.graphics.Bitmap import android.graphics.BitmapFactory 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.launch @@ -24,10 +23,8 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.client.FetchClientImage import org.mifospay.core.data.repository.local.LocalRepository import org.mifospay.core.datastore.PreferencesHelper -import javax.inject.Inject -@HiltViewModel -class ProfileViewModel @Inject constructor( +class ProfileViewModel( private val mUseCaseHandler: UseCaseHandler, private val fetchClientImageUseCase: FetchClientImage, private val localRepository: LocalRepository, diff --git a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/di/ProfileModule.kt b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/di/ProfileModule.kt new file mode 100644 index 000000000..c93e8ab9d --- /dev/null +++ b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/di/ProfileModule.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.profile.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.profile.ProfileViewModel +import org.mifospay.feature.profile.edit.EditProfileViewModel + +val ProfileModule = module { + viewModel { + ProfileViewModel( + mUseCaseHandler = get(), + fetchClientImageUseCase = get(), + localRepository = get(), + mPreferencesHelper = get(), + ) + } + + viewModel { + EditProfileViewModel( + mUseCaseHandler = get(), + mPreferencesHelper = get(), + updateUserUseCase = get(), + updateClientUseCase = get(), + ) + } +} diff --git a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileScreen.kt b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileScreen.kt index dfa8d1f6a..cefd425eb 100644 --- a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileScreen.kt +++ b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileScreen.kt @@ -51,9 +51,9 @@ 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 com.mifos.library.countrycodepicker.CountryCodePicker +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.component.MfOutlinedTextField import org.mifospay.core.designsystem.component.MifosBottomSheet @@ -78,7 +78,7 @@ fun EditProfileScreenRoute( onBackClick: () -> Unit, getUri: (context: Context, file: File) -> Uri, modifier: Modifier = Modifier, - viewModel: EditProfileViewModel = hiltViewModel(), + viewModel: EditProfileViewModel = koinViewModel(), ) { val editProfileUiState by viewModel.editProfileUiState.collectAsStateWithLifecycle() val updateSuccess by viewModel.updateSuccess.collectAsStateWithLifecycle() diff --git a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileViewModel.kt b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileViewModel.kt index 4cbe2636b..2e2cac8e1 100644 --- a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileViewModel.kt +++ b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.profile.edit import android.graphics.Bitmap import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.user.UpdateUserEntityEmail -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCase @@ -21,10 +20,8 @@ import org.mifospay.core.data.domain.usecase.client.UpdateClient import org.mifospay.core.data.domain.usecase.user.UpdateUser import org.mifospay.core.datastore.PreferencesHelper import org.mifospay.feature.profile.edit.EditProfileUiState.Loading -import javax.inject.Inject -@HiltViewModel -class EditProfileViewModel @Inject constructor( +class EditProfileViewModel( private val mUseCaseHandler: UseCaseHandler, private val mPreferencesHelper: PreferencesHelper, private val updateUserUseCase: UpdateUser, diff --git a/feature/qr/build.gradle.kts b/feature/qr/build.gradle.kts index b85da1fe1..0741a395f 100644 --- a/feature/qr/build.gradle.kts +++ b/feature/qr/build.gradle.kts @@ -18,7 +18,6 @@ android { dependencies { implementation(libs.zxing) - implementation(projects.core.data) implementation(libs.androidx.camera.view) implementation(libs.androidx.camera.lifecycle) // TODO:: this should be removed diff --git a/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/ReadQrScreen.kt b/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/ReadQrScreen.kt index f2def8a20..4b463cd2c 100644 --- a/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/ReadQrScreen.kt +++ b/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/ReadQrScreen.kt @@ -50,9 +50,9 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.compose.ui.viewinterop.AndroidView import androidx.core.content.ContextCompat -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.LocalLifecycleOwner import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.component.MifosScaffold import org.mifospay.core.designsystem.component.PermissionBox @@ -66,7 +66,7 @@ import org.mifospay.feature.read.qr.utils.QrCodeAnalyzer internal fun ShowQrScreenRoute( backPress: () -> Unit, modifier: Modifier = Modifier, - viewModel: ReadQrViewModel = hiltViewModel(), + viewModel: ReadQrViewModel = koinViewModel(), ) { val uiState = viewModel.readQrUiState.collectAsStateWithLifecycle() diff --git a/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/ReadQrViewModel.kt b/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/ReadQrViewModel.kt index a3bb2b417..b213b9ffb 100644 --- a/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/ReadQrViewModel.kt +++ b/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/ReadQrViewModel.kt @@ -11,17 +11,14 @@ package org.mifospay.feature.read.qr import android.graphics.Bitmap import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.feature.read.qr.utils.ScanQr -import javax.inject.Inject -@HiltViewModel -class ReadQrViewModel @Inject constructor( +class ReadQrViewModel( private val useCaseHandler: UseCaseHandler, private val scanQrUseCase: ScanQr, ) : ViewModel() { diff --git a/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/di/QrModule.kt b/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/di/QrModule.kt new file mode 100644 index 000000000..db7face32 --- /dev/null +++ b/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/di/QrModule.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.read.qr.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.read.qr.ReadQrViewModel +import org.mifospay.feature.read.qr.utils.ScanQr + +val QrModule = module { + single { + ScanQr() + } + viewModel { + ReadQrViewModel(useCaseHandler = get(), scanQrUseCase = get()) + } +} diff --git a/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/utils/ScanQr.kt b/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/utils/ScanQr.kt index cec0225e7..82e849658 100644 --- a/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/utils/ScanQr.kt +++ b/feature/qr/src/main/kotlin/org/mifospay/feature/read/qr/utils/ScanQr.kt @@ -16,9 +16,8 @@ import com.google.zxing.Result import com.google.zxing.common.HybridBinarizer import com.google.zxing.qrcode.QRCodeReader import org.mifospay.core.data.base.UseCase -import javax.inject.Inject -class ScanQr @Inject constructor() : UseCase() { +class ScanQr : UseCase() { override fun executeUseCase(requestValues: RequestValues) { val bitmap = requestValues.bitmap diff --git a/feature/receipt/build.gradle.kts b/feature/receipt/build.gradle.kts index 87bf360b3..943600377 100644 --- a/feature/receipt/build.gradle.kts +++ b/feature/receipt/build.gradle.kts @@ -19,5 +19,4 @@ android { dependencies { // TODO:: this should be removed implementation(libs.squareup.okhttp) - implementation(projects.core.data) } \ No newline at end of file diff --git a/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptScreen.kt b/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptScreen.kt index 7da744baf..16c18febd 100644 --- a/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptScreen.kt +++ b/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptScreen.kt @@ -55,11 +55,11 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.core.content.FileProvider -import androidx.hilt.navigation.compose.hiltViewModel import com.mifospay.core.model.domain.Transaction import com.mifospay.core.model.domain.TransactionType import com.mifospay.core.model.entity.accounts.savings.TransferDetail import kotlinx.coroutines.launch +import org.koin.androidx.compose.koinViewModel import org.mifospay.common.Constants import org.mifospay.core.designsystem.component.FloatingActionButtonContent import org.mifospay.core.designsystem.component.MifosOverlayLoadingWheel @@ -76,10 +76,10 @@ internal fun ReceiptScreenRoute( openPassCodeActivity: () -> Unit, onBackClick: () -> Unit, modifier: Modifier = Modifier, - viewModel: ReceiptViewModel = hiltViewModel(), + viewModel: ReceiptViewModel = koinViewModel(), ) { /** - * This function serves as the main entry point for the Receipt screen UI. + * This function serves as the androidMain entry point for the Receipt screen UI. * It collects the receiptUiState and fileState from the ViewModel and * calls the ReceiptScreen function, passing the collected states and * other necessary parameters. diff --git a/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptViewModel.kt b/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptViewModel.kt index dc47e87c7..6769ac271 100644 --- a/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptViewModel.kt +++ b/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptViewModel.kt @@ -15,7 +15,6 @@ import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.Transaction import com.mifospay.core.model.entity.accounts.savings.TransferDetail -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -29,10 +28,8 @@ import org.mifospay.core.data.domain.usecase.account.FetchAccountTransaction import org.mifospay.core.data.domain.usecase.account.FetchAccountTransfer import org.mifospay.core.datastore.PreferencesHelper import java.io.File -import javax.inject.Inject -@HiltViewModel -class ReceiptViewModel @Inject constructor( +class ReceiptViewModel( private val mUseCaseHandler: UseCaseHandler, private val preferencesHelper: PreferencesHelper, private val downloadTransactionReceiptUseCase: DownloadTransactionReceipt, diff --git a/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/di/ReceiptModule.kt b/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/di/ReceiptModule.kt new file mode 100644 index 000000000..a59f7cd29 --- /dev/null +++ b/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/di/ReceiptModule.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.receipt.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.receipt.ReceiptViewModel + +val ReceiptModule = module { + viewModel { + ReceiptViewModel( + mUseCaseHandler = get(), + preferencesHelper = get(), + downloadTransactionReceiptUseCase = get(), + fetchAccountTransactionUseCase = get(), + fetchAccountTransferUseCase = get(), + savedStateHandle = get(), + ) + } +} diff --git a/feature/request-money/build.gradle.kts b/feature/request-money/build.gradle.kts index 61c223c41..e9ae4a1ba 100644 --- a/feature/request-money/build.gradle.kts +++ b/feature/request-money/build.gradle.kts @@ -20,8 +20,6 @@ android { } dependencies { - implementation(projects.core.data) - implementation(libs.zxing) implementation(libs.coil.kt.compose) } \ No newline at end of file diff --git a/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/GenerateQr.kt b/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/GenerateQr.kt index ede2d6770..30457707a 100644 --- a/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/GenerateQr.kt +++ b/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/GenerateQr.kt @@ -17,12 +17,11 @@ import com.google.zxing.common.BitMatrix import org.mifospay.common.Constants import org.mifospay.core.data.base.UseCase import java.util.Base64 -import javax.inject.Inject /** * Created by naman on 8/7/17. */ -class GenerateQr @Inject constructor() : +class GenerateQr : UseCase() { override fun executeUseCase(requestValues: RequestValues) { try { diff --git a/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/ShowQrScreenRoute.kt b/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/ShowQrScreenRoute.kt index 2d1fa677c..4c539cfcc 100644 --- a/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/ShowQrScreenRoute.kt +++ b/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/ShowQrScreenRoute.kt @@ -35,8 +35,8 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.core.content.ContextCompat.startActivity -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.component.MifosScaffold import org.mifospay.core.designsystem.icon.MifosIcons @@ -47,7 +47,7 @@ import org.mifospay.feature.request.money.util.ImageUtils internal fun ShowQrScreenRoute( backPress: () -> Unit, modifier: Modifier = Modifier, - viewModel: ShowQrViewModel = hiltViewModel(), + viewModel: ShowQrViewModel = koinViewModel(), ) { val uiState by viewModel.showQrUiState.collectAsStateWithLifecycle() val vpaId by viewModel.vpaId.collectAsStateWithLifecycle() diff --git a/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/ShowQrViewModel.kt b/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/ShowQrViewModel.kt index aae190a48..484002812 100644 --- a/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/ShowQrViewModel.kt +++ b/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/ShowQrViewModel.kt @@ -12,16 +12,13 @@ package org.mifospay.feature.request.money import android.graphics.Bitmap import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.datastore.PreferencesHelper import org.mifospay.feature.request.money.ShowQrUiState.Loading -import javax.inject.Inject -@HiltViewModel -class ShowQrViewModel @Inject constructor( +class ShowQrViewModel( private val mUseCaseHandler: UseCaseHandler, private val generateQrUseCase: GenerateQr, private val mPreferencesHelper: PreferencesHelper, diff --git a/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/di/RequestMoneyModule.kt b/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/di/RequestMoneyModule.kt new file mode 100644 index 000000000..fe0f86e83 --- /dev/null +++ b/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/di/RequestMoneyModule.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.request.money.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.request.money.GenerateQr +import org.mifospay.feature.request.money.ShowQrViewModel + +val RequestMoneyModule = module { + single { + GenerateQr() + } + + viewModel { + ShowQrViewModel( + mUseCaseHandler = get(), + generateQrUseCase = get(), + mPreferencesHelper = get(), + savedStateHandle = get(), + ) + } +} diff --git a/feature/savedcards/build.gradle.kts b/feature/savedcards/build.gradle.kts index 24ee46998..68361a5c3 100644 --- a/feature/savedcards/build.gradle.kts +++ b/feature/savedcards/build.gradle.kts @@ -16,6 +16,4 @@ android { namespace = "org.mifospay.savedcards" } -dependencies { - implementation(projects.core.data) -} \ No newline at end of file +dependencies {} \ No newline at end of file diff --git a/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/CardsScreen.kt b/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/CardsScreen.kt index 31ed2be8c..7586e00e8 100644 --- a/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/CardsScreen.kt +++ b/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/CardsScreen.kt @@ -46,9 +46,9 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifospay.core.model.entity.savedcards.Card +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.component.MifosDialogBox import org.mifospay.core.designsystem.icon.MifosIcons @@ -61,7 +61,7 @@ import org.mifospay.savedcards.R fun CardsScreen( onEditCard: (Card) -> Unit, modifier: Modifier = Modifier, - viewModel: CardsScreenViewModel = hiltViewModel(), + viewModel: CardsScreenViewModel = koinViewModel(), ) { val cardState by viewModel.cardState.collectAsStateWithLifecycle() val cardListUiState by viewModel.cardListUiState.collectAsStateWithLifecycle() diff --git a/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/CardsScreenViewModel.kt b/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/CardsScreenViewModel.kt index 12e57472a..be508e1d4 100644 --- a/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/CardsScreenViewModel.kt +++ b/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/CardsScreenViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.savedcards import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mifospay.core.model.entity.savedcards.Card -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow @@ -27,10 +26,8 @@ import org.mifospay.core.data.domain.usecase.savedcards.DeleteCard import org.mifospay.core.data.domain.usecase.savedcards.EditCard import org.mifospay.core.data.domain.usecase.savedcards.FetchSavedCards import org.mifospay.core.data.repository.local.LocalRepository -import javax.inject.Inject -@HiltViewModel -class CardsScreenViewModel @Inject constructor( +class CardsScreenViewModel( private val mUseCaseHandler: UseCaseHandler, private val mLocalRepository: LocalRepository, private val addCardUseCase: AddCard, diff --git a/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/di/SavedCardsModule.kt b/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/di/SavedCardsModule.kt new file mode 100644 index 000000000..bd8619570 --- /dev/null +++ b/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/di/SavedCardsModule.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.savedcards.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.savedcards.CardsScreenViewModel + +val SavedCardsModule = module { + viewModel { + CardsScreenViewModel( + mUseCaseHandler = get(), + mLocalRepository = get(), + addCardUseCase = get(), + fetchSavedCardsUseCase = get(), + editCardUseCase = get(), + deleteCardUseCase = get(), + ) + } +} diff --git a/feature/search/build.gradle.kts b/feature/search/build.gradle.kts index 12ab53902..2576ecd05 100644 --- a/feature/search/build.gradle.kts +++ b/feature/search/build.gradle.kts @@ -16,6 +16,4 @@ android { namespace = "org.mifospay.feature.search" } -dependencies { - implementation(projects.core.data) -} +dependencies { } diff --git a/feature/search/src/main/kotlin/org/mifospay/feature/search/SearchScreen.kt b/feature/search/src/main/kotlin/org/mifospay/feature/search/SearchScreen.kt index 3f3e0b011..1263fbac3 100644 --- a/feature/search/src/main/kotlin/org/mifospay/feature/search/SearchScreen.kt +++ b/feature/search/src/main/kotlin/org/mifospay/feature/search/SearchScreen.kt @@ -39,8 +39,8 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import com.mifospay.core.model.domain.SearchResult +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.MifosTheme @@ -49,7 +49,7 @@ import org.mifospay.core.designsystem.theme.MifosTheme fun SearchScreenRoute( onBackClick: () -> Unit, modifier: Modifier = Modifier, - viewModel: SearchViewModel = hiltViewModel(), + viewModel: SearchViewModel = koinViewModel(), ) { val searchQuery by viewModel.searchQuery.collectAsState() val searchResultState by viewModel.searchResults.collectAsState() diff --git a/feature/search/src/main/kotlin/org/mifospay/feature/search/SearchViewModel.kt b/feature/search/src/main/kotlin/org/mifospay/feature/search/SearchViewModel.kt index d37913c8a..3f50176ef 100644 --- a/feature/search/src/main/kotlin/org/mifospay/feature/search/SearchViewModel.kt +++ b/feature/search/src/main/kotlin/org/mifospay/feature/search/SearchViewModel.kt @@ -12,17 +12,14 @@ package org.mifospay.feature.search import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.SearchResult -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.client.SearchClient -import javax.inject.Inject -@HiltViewModel -class SearchViewModel @Inject constructor( +class SearchViewModel( private val mUseCaseHandler: UseCaseHandler, private val searchClient: SearchClient, private val savedStateHandle: SavedStateHandle, diff --git a/feature/search/src/main/kotlin/org/mifospay/feature/search/di/SearchModule.kt b/feature/search/src/main/kotlin/org/mifospay/feature/search/di/SearchModule.kt new file mode 100644 index 000000000..7db0651a3 --- /dev/null +++ b/feature/search/src/main/kotlin/org/mifospay/feature/search/di/SearchModule.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.search.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.search.SearchViewModel + +val SearchModule = module { + viewModel { + SearchViewModel( + mUseCaseHandler = get(), + searchClient = get(), + savedStateHandle = get(), + ) + } +} diff --git a/feature/send-money/build.gradle.kts b/feature/send-money/build.gradle.kts index 83461917a..4e5e691af 100644 --- a/feature/send-money/build.gradle.kts +++ b/feature/send-money/build.gradle.kts @@ -17,8 +17,6 @@ android { } dependencies { - implementation(projects.core.data) - // we need it for country picker library implementation(projects.libs.countryCodePicker) diff --git a/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendPaymentViewModel.kt b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendPaymentViewModel.kt index 94024573e..4e8cd7e62 100644 --- a/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendPaymentViewModel.kt +++ b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendPaymentViewModel.kt @@ -11,7 +11,6 @@ package org.mifospay.feature.send.money 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.update @@ -20,10 +19,8 @@ import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.account.FetchAccount import org.mifospay.core.data.repository.local.LocalRepository -import javax.inject.Inject -@HiltViewModel -class SendPaymentViewModel @Inject constructor( +class SendPaymentViewModel( private val useCaseHandler: UseCaseHandler, private val localRepository: LocalRepository, private val fetchAccount: FetchAccount, diff --git a/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendScreenRoute.kt b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendScreenRoute.kt index 954f4110d..4452bd258 100644 --- a/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendScreenRoute.kt +++ b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/SendScreenRoute.kt @@ -49,7 +49,6 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.google.mlkit.vision.barcode.common.Barcode import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions @@ -57,6 +56,7 @@ import com.google.mlkit.vision.codescanner.GmsBarcodeScanning import com.mifos.library.countrycodepicker.CountryCodePicker import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MfOutlinedTextField import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel import org.mifospay.core.designsystem.component.MifosButton @@ -71,7 +71,7 @@ fun SendScreenRoute( onBackClick: () -> Unit, proceedWithMakeTransferFlow: (String, String) -> Unit, modifier: Modifier = Modifier, - viewModel: SendPaymentViewModel = hiltViewModel(), + viewModel: SendPaymentViewModel = koinViewModel(), ) { val context = LocalContext.current val selfVpa by viewModel.vpa.collectAsStateWithLifecycle() diff --git a/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/di/SendMoneyModule.kt b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/di/SendMoneyModule.kt new file mode 100644 index 000000000..34e02030e --- /dev/null +++ b/feature/send-money/src/main/kotlin/org/mifospay/feature/send/money/di/SendMoneyModule.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.send.money.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.send.money.SendPaymentViewModel + +val SendMoneyModule = module { + viewModel { + SendPaymentViewModel( + useCaseHandler = get(), + localRepository = get(), + fetchAccount = get(), + ) + } +} diff --git a/feature/settings/build.gradle.kts b/feature/settings/build.gradle.kts index 6933a49c2..0de327314 100644 --- a/feature/settings/build.gradle.kts +++ b/feature/settings/build.gradle.kts @@ -16,6 +16,4 @@ android { namespace = "org.mifospay.feature.settings" } -dependencies { - implementation(projects.core.data) -} \ No newline at end of file +dependencies {} \ No newline at end of file diff --git a/feature/settings/src/main/kotlin/org/mifospay/feature/settings/SettingsScreen.kt b/feature/settings/src/main/kotlin/org/mifospay/feature/settings/SettingsScreen.kt index 8d9b30bc6..42b487b8d 100644 --- a/feature/settings/src/main/kotlin/org/mifospay/feature/settings/SettingsScreen.kt +++ b/feature/settings/src/main/kotlin/org/mifospay/feature/settings/SettingsScreen.kt @@ -31,7 +31,7 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.hilt.navigation.compose.hiltViewModel +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MifosCard import org.mifospay.core.designsystem.component.MifosTopBar import org.mifospay.core.ui.utility.DialogState @@ -44,7 +44,7 @@ fun SettingsScreenRoute( onLogout: () -> Unit, onChangePasscode: () -> Unit, modifier: Modifier = Modifier, - viewmodel: SettingsViewModel = hiltViewModel(), + viewmodel: SettingsViewModel = koinViewModel(), ) { var dialogState by remember { mutableStateOf(DialogState()) } val paddingValues = PaddingValues(start = 20.dp, end = 20.dp, top = 20.dp, bottom = 4.dp) @@ -196,6 +196,6 @@ private fun SettingsScreenPreview() { navigateToEditPasswordScreen = {}, onLogout = {}, onChangePasscode = {}, - viewmodel = hiltViewModel(), + viewmodel = koinViewModel(), ) } diff --git a/feature/settings/src/main/kotlin/org/mifospay/feature/settings/SettingsViewModel.kt b/feature/settings/src/main/kotlin/org/mifospay/feature/settings/SettingsViewModel.kt index fefafd297..2ab18b0bd 100644 --- a/feature/settings/src/main/kotlin/org/mifospay/feature/settings/SettingsViewModel.kt +++ b/feature/settings/src/main/kotlin/org/mifospay/feature/settings/SettingsViewModel.kt @@ -10,15 +10,12 @@ package org.mifospay.feature.settings import androidx.lifecycle.ViewModel -import dagger.hilt.android.lifecycle.HiltViewModel import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.account.BlockUnblockCommand import org.mifospay.core.data.repository.local.LocalRepository -import javax.inject.Inject -@HiltViewModel -class SettingsViewModel @Inject constructor( +class SettingsViewModel( private val mUseCaseHandler: UseCaseHandler, private val mLocalRepository: LocalRepository, private val blockUnblockCommandUseCase: BlockUnblockCommand, diff --git a/feature/settings/src/main/kotlin/org/mifospay/feature/settings/di/SettingsModule.kt b/feature/settings/src/main/kotlin/org/mifospay/feature/settings/di/SettingsModule.kt new file mode 100644 index 000000000..5b912b4bf --- /dev/null +++ b/feature/settings/src/main/kotlin/org/mifospay/feature/settings/di/SettingsModule.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.settings.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.settings.SettingsViewModel + +val SettingsModule = module { + viewModel { + SettingsViewModel( + mUseCaseHandler = get(), + mLocalRepository = get(), + blockUnblockCommandUseCase = get(), + ) + } +} diff --git a/feature/standing-instruction/build.gradle.kts b/feature/standing-instruction/build.gradle.kts index b0f12fdc7..8fac8140e 100644 --- a/feature/standing-instruction/build.gradle.kts +++ b/feature/standing-instruction/build.gradle.kts @@ -17,8 +17,6 @@ android { } dependencies { - implementation(projects.core.data) - // Google Bar code scanner implementation(libs.google.play.services.code.scanner) } \ No newline at end of file diff --git a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/NewSIScreenRoute.kt b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/NewSIScreenRoute.kt index b27321f6b..6ade5bfc8 100644 --- a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/NewSIScreenRoute.kt +++ b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/NewSIScreenRoute.kt @@ -46,11 +46,11 @@ import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.google.mlkit.vision.barcode.common.Barcode import com.google.mlkit.vision.codescanner.GmsBarcodeScannerOptions import com.google.mlkit.vision.codescanner.GmsBarcodeScanning +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosOutlinedTextField import org.mifospay.core.designsystem.component.MifosScaffold @@ -62,7 +62,7 @@ import java.util.Calendar internal fun NewSIScreenRoute( onBackPress: () -> Unit, modifier: Modifier = Modifier, - viewModel: NewSIViewModel = hiltViewModel(), + viewModel: NewSIViewModel = koinViewModel(), ) { val uiState by viewModel.newSIUiState.collectAsStateWithLifecycle() val updateSuccess by viewModel.updateSuccess.collectAsStateWithLifecycle() diff --git a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/NewSIViewModel.kt b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/NewSIViewModel.kt index 4df994588..64afb8992 100644 --- a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/NewSIViewModel.kt +++ b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/NewSIViewModel.kt @@ -11,7 +11,6 @@ package org.mifospay.feature.standing.instruction import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.SearchResult -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCase @@ -22,10 +21,8 @@ import org.mifospay.core.datastore.PreferencesHelper import java.text.SimpleDateFormat import java.util.Date import java.util.Locale -import javax.inject.Inject -@HiltViewModel -class NewSIViewModel @Inject constructor( +class NewSIViewModel( private val mUseCaseHandler: UseCaseHandler, private val preferencesHelper: PreferencesHelper, private val searchClient: SearchClient, diff --git a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/SIDetailsScreen.kt b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/SIDetailsScreen.kt index 408ffe387..6ae9df3b6 100644 --- a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/SIDetailsScreen.kt +++ b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/SIDetailsScreen.kt @@ -27,12 +27,12 @@ import androidx.compose.ui.text.font.FontWeight 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 com.mifospay.core.model.entity.accounts.savings.SavingAccount import com.mifospay.core.model.entity.client.Client import com.mifospay.core.model.entity.client.Status import com.mifospay.core.model.entity.standinginstruction.StandingInstruction +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.FloatingActionButtonContent import org.mifospay.core.designsystem.component.MifosLoadingWheel import org.mifospay.core.designsystem.component.MifosScaffold @@ -43,7 +43,7 @@ internal fun SIDetailsScreen( onClickCreateNew: () -> Unit, onBackPress: () -> Unit, modifier: Modifier = Modifier, - viewModel: StandingInstructionDetailsViewModel = hiltViewModel(), + viewModel: StandingInstructionDetailsViewModel = koinViewModel(), ) { val siDetailUiState by viewModel.siDetailsUiState.collectAsStateWithLifecycle() diff --git a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionDetailsViewModel.kt b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionDetailsViewModel.kt index babfcf585..ec6b5adb2 100644 --- a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionDetailsViewModel.kt +++ b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionDetailsViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay.feature.standing.instruction import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import com.mifospay.core.model.entity.standinginstruction.StandingInstruction -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCase @@ -20,10 +19,8 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.standinginstruction.DeleteStandingInstruction import org.mifospay.core.data.domain.usecase.standinginstruction.FetchStandingInstruction import org.mifospay.core.data.domain.usecase.standinginstruction.UpdateStandingInstruction -import javax.inject.Inject -@HiltViewModel -class StandingInstructionDetailsViewModel @Inject constructor( +class StandingInstructionDetailsViewModel( private val mUseCaseHandler: UseCaseHandler, private val fetchStandingInstruction: FetchStandingInstruction, private val updateStandingInstruction: UpdateStandingInstruction, diff --git a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionScreen.kt b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionScreen.kt index 63d961a71..006193666 100644 --- a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionScreen.kt +++ b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionScreen.kt @@ -22,8 +22,8 @@ import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier 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.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.FloatingActionButtonContent import org.mifospay.core.designsystem.component.MifosLoadingWheel import org.mifospay.core.designsystem.component.MifosScaffold @@ -35,7 +35,7 @@ fun StandingInstructionsScreenRoute( onNewSI: () -> Unit, onBackPress: () -> Unit, modifier: Modifier = Modifier, - viewModel: StandingInstructionViewModel = hiltViewModel(), + viewModel: StandingInstructionViewModel = koinViewModel(), ) { val standingInstructionsUiState by viewModel.standingInstructionsUiState.collectAsStateWithLifecycle() diff --git a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionViewModel.kt b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionViewModel.kt index fabbca00a..7d1c6b798 100644 --- a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionViewModel.kt +++ b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/StandingInstructionViewModel.kt @@ -11,7 +11,6 @@ package org.mifospay.feature.standing.instruction import androidx.lifecycle.ViewModel import com.mifospay.core.model.entity.standinginstruction.StandingInstruction -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCase @@ -19,10 +18,8 @@ import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.standinginstruction.GetAllStandingInstructions import org.mifospay.core.data.repository.local.LocalRepository import org.mifospay.feature.standing.instruction.StandingInstructionsUiState.Loading -import javax.inject.Inject -@HiltViewModel -class StandingInstructionViewModel @Inject constructor( +class StandingInstructionViewModel( private val mUseCaseHandler: UseCaseHandler, private val localRepository: LocalRepository, private val getAllStandingInstructions: GetAllStandingInstructions, diff --git a/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/di/StandingInstructionModule.kt b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/di/StandingInstructionModule.kt new file mode 100644 index 000000000..072a611b6 --- /dev/null +++ b/feature/standing-instruction/src/main/kotlin/org/mifospay/feature/standing/instruction/di/StandingInstructionModule.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.standing.instruction.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.standing.instruction.NewSIViewModel +import org.mifospay.feature.standing.instruction.StandingInstructionDetailsViewModel +import org.mifospay.feature.standing.instruction.StandingInstructionViewModel + +val StandingInstructionModule = module { + viewModel { + NewSIViewModel( + mUseCaseHandler = get(), + preferencesHelper = get(), + searchClient = get(), + createStandingTransaction = get(), + ) + } + + viewModel { + StandingInstructionViewModel( + mUseCaseHandler = get(), + localRepository = get(), + getAllStandingInstructions = get(), + ) + } + + viewModel { + StandingInstructionDetailsViewModel( + mUseCaseHandler = get(), + fetchStandingInstruction = get(), + updateStandingInstruction = get(), + deleteStandingInstruction = get(), + savedStateHandle = get(), + ) + } +} diff --git a/feature/upi-setup/build.gradle.kts b/feature/upi-setup/build.gradle.kts index 73c9e4b92..a40950877 100644 --- a/feature/upi-setup/build.gradle.kts +++ b/feature/upi-setup/build.gradle.kts @@ -16,6 +16,4 @@ android { namespace = "org.mifospay.feature.upi_setup" } -dependencies { - implementation(projects.core.data) -} \ No newline at end of file +dependencies { } \ No newline at end of file diff --git a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/di/UpiSetupModule.kt b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/di/UpiSetupModule.kt new file mode 100644 index 000000000..8810f7b96 --- /dev/null +++ b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/di/UpiSetupModule.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.upiSetup.di + +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.feature.upiSetup.viewmodel.DebitCardViewModel +import org.mifospay.feature.upiSetup.viewmodel.SetUpUpiViewModal + +val UpiSetupModule = module { + + viewModel { + DebitCardViewModel() + } + + viewModel { + SetUpUpiViewModal() + } +} diff --git a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/DebitCardScreen.kt b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/DebitCardScreen.kt index d1173b61c..06c7de46a 100644 --- a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/DebitCardScreen.kt +++ b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/DebitCardScreen.kt @@ -23,8 +23,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MifosLoadingWheel import org.mifospay.core.designsystem.theme.MifosTheme import org.mifospay.core.ui.VerifyStepHeader @@ -38,7 +38,7 @@ internal fun DebitCardScreen( modifier: Modifier = Modifier, verificationStatus: Boolean = false, isContentVisible: Boolean = true, - viewModel: DebitCardViewModel = hiltViewModel(), + viewModel: DebitCardViewModel = koinViewModel(), ) { val debitCardUiState by viewModel.debitCardUiState.collectAsStateWithLifecycle() diff --git a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUPiPinScreen.kt b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUPiPinScreen.kt index e8aa98455..02e57efc5 100644 --- a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUPiPinScreen.kt +++ b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUPiPinScreen.kt @@ -28,8 +28,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview -import androidx.hilt.navigation.compose.hiltViewModel import com.mifospay.core.model.domain.BankAccountDetails +import org.koin.androidx.compose.koinViewModel import org.mifospay.common.Constants import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.feature.upiSetup.viewmodel.SetUpUpiViewModal @@ -42,7 +42,7 @@ internal fun SetupUpiPinScreenRoute( bankAccountDetails: BankAccountDetails, onBackPress: () -> Unit, modifier: Modifier = Modifier, - setUpViewModel: SetUpUpiViewModal = hiltViewModel(), + setUpViewModel: SetUpUpiViewModal = koinViewModel(), ) { SetupUpiPinScreen( type = type, diff --git a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/viewmodel/DebitCardViewModal.kt b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/viewmodel/DebitCardViewModal.kt index 57cc2cf2a..5dd5bbf72 100644 --- a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/viewmodel/DebitCardViewModal.kt +++ b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/viewmodel/DebitCardViewModal.kt @@ -11,15 +11,12 @@ package org.mifospay.feature.upiSetup.viewmodel import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch -import javax.inject.Inject -@HiltViewModel -class DebitCardViewModel @Inject constructor() : ViewModel() { +class DebitCardViewModel : ViewModel() { private val _debitCardUiState = MutableStateFlow(DebitCardUiState.Initials) val debitCardUiState: StateFlow = _debitCardUiState diff --git a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/viewmodel/SetUpUpiViewModal.kt b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/viewmodel/SetUpUpiViewModal.kt index cb0276321..1f402a00c 100644 --- a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/viewmodel/SetUpUpiViewModal.kt +++ b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/viewmodel/SetUpUpiViewModal.kt @@ -11,12 +11,9 @@ package org.mifospay.feature.upiSetup.viewmodel import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.BankAccountDetails -import dagger.hilt.android.lifecycle.HiltViewModel -import javax.inject.Inject -@HiltViewModel @Suppress("UnusedParameter") -class SetUpUpiViewModal @Inject constructor() : ViewModel() { +class SetUpUpiViewModal : ViewModel() { fun requestOtp(bankAccountDetails: BankAccountDetails?): String { val otp = "0000" diff --git a/gradle.properties b/gradle.properties index 7416e13c6..79d506e00 100644 --- a/gradle.properties +++ b/gradle.properties @@ -46,6 +46,7 @@ kotlin.code.style=official # https://developer.android.com/build/releases/gradle-plugin#default-changes android.defaults.buildfeatures.resvalues=false android.defaults.buildfeatures.shaders=false +android.testOptions.unitTests.isIncludeAndroidResources = true RblClientIdProp=a RblClientSecretProp=b diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 88d3d2a5e..9b9c19999 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,66 +1,67 @@ [versions] accompanistPagerVersion = "0.34.0" -activityVersion = "1.9.1" -androidDesugarJdkLibs = "2.0.4" +activityVersion = "1.9.2" +androidDesugarJdkLibs = "2.1.2" androidGradlePlugin = "8.5.2" androidTools = "31.5.2" androidx-test-ext-junit = "1.2.1" -androidxActivity = "1.9.1" +androidxActivity = "1.9.2" androidxBrowser = "1.8.0" -androidxComposeBom = "2024.08.00" +androidxComposeBom = "2024.09.02" androidxComposeCompiler = "1.5.15" -androidxComposeMaterial3Adaptive = "1.0.0-rc01" -androidxComposeRuntime = "1.6.8" +androidxComposeMaterial3Adaptive = "1.0.0" androidxComposeRuntimeTracing = "1.0.0-beta01" -androidxComposeUi = "1.6.8" -androidxComposeUiTest = "1.7.0-beta01" androidxCoreSplashscreen = "1.0.1" androidxDataStore = "1.1.1" -androidxHilt = "1.2.0" -androidxLifecycle = "2.8.4" +androidxLifecycle = "2.8.6" androidxMetrics = "1.0.0-beta01" -androidxNavigation = "2.8.0-rc01" -androidxProfileinstaller = "1.3.1" +androidxNavigation = "2.8.1" +androidxProfileinstaller = "1.4.0" androidxTracing = "1.3.0-alpha02" appcompatVersion = "1.7.0" cameraLifecycleVersion = "1.3.4" cameraViewVersion = "1.3.4" -coil = "2.6.0" +coil = "3.0.0-alpha10" compileSdk = "34" compose-plugin = "1.6.11" coreKtxVersion = "1.13.1" credentialsVersion = "1.2.2" datastore = "1.1.1" dependencyGuard = "0.5.0" -detekt = "1.23.5" +detekt = "1.23.7" espresso-core = "3.6.1" -firebaseBom = "33.1.2" +fineractSdk = "1.06" +firebaseBom = "33.3.0" firebaseCrashlyticsPlugin = "3.0.2" firebasePerfPlugin = "1.4.2" gmsPlugin = "4.4.2" googleOss = "17.1.0" googleOssPlugin = "0.10.6" googleidVersion = "1.1.1" -hilt = "2.52" junitVersion = "4.13.2" -koin = "3.6.0-Beta4" +koin = "4.0.0-RC2" +koinAnnotationsVersion = "1.4.0-RC4" koinComposeMultiplatform = "1.2.0-Beta4" kotlin = "2.0.20" -kotlinStdlibVersion = "1.9.0" -kotlinxCoroutines = "1.8.1" +kotlinInject = "0.7.2" +kotlinStdlibVersion = "2.0.20" +kotlinxCoroutines = "1.9.0" kotlinxDatetime = "0.6.0" -kotlinxImmutable = "0.3.7" -kotlinxSerializationJson = "1.7.1" +kotlinxImmutable = "0.3.8" +kotlinxSerializationJson = "1.7.2" kotlinxSerializationJsonVersion = "1.3.0" ksp = "2.0.20-1.0.24" ktlint = "12.1.1" ktorVersion = "2.3.4" +ktorfit = "2.1.0" +ktorfitKsp = "2.1.0-1.0.25" libphonenumberAndroidVersion = "8.13.35" lifecycleExtensionsVersion = "2.2.0" -lifecycleVersion = "2.8.4" -logbackClassicVersion = "1.2.3" +lifecycleVersion = "2.8.6" +logbackClassicVersion = "1.3.14" minSdk = "24" moduleGraph = "2.5.0" +multiplatformSettings = "1.2.0" okHttp3Version = "4.12.0" playServicesAuthVersion = "21.2.0" playServicesCodeScanner = "16.1.0" @@ -74,10 +75,11 @@ rxandroidVersion = "1.1.0" rxjavaVersion = "1.3.8" secrets = "2.0.1" sheets_compose_dialogs_core = "1.3.0" -spotlessVersion = "6.23.3" +spotlessVersion = "6.25.0" targetSdk = "34" -truth = "1.4.2" +truth = "1.4.4" twitter-detekt-compose = "0.0.26" +uiDesktopVersion = "1.7.0" versionCatalogLinterVersion = "1.0.3" wire = "5.0.0" zxingVersion = "3.5.3" @@ -104,20 +106,19 @@ androidx-compose-material3-adaptive = { group = "androidx.compose.material3.adap androidx-compose-material3-adaptive-layout = { group = "androidx.compose.material3.adaptive", name = "adaptive-layout", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-adaptive-navigation = { group = "androidx.compose.material3.adaptive", name = "adaptive-navigation", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-windowSizeClass = { group = "androidx.compose.material3", name = "material3-window-size-class" } -androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime", version.ref = "androidxComposeRuntime" } +androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime" } androidx-compose-runtime-tracing = { group = "androidx.compose.runtime", name = "runtime-tracing", version.ref = "androidxComposeRuntimeTracing" } -androidx-compose-ui = { group = "androidx.compose.ui", name = "ui", version.ref = "androidxComposeUi" } -androidx-compose-ui-test = { group = "androidx.compose.ui", name = "ui-test-junit4", version.ref = "androidxComposeUiTest" } +androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } +androidx-compose-ui-test = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } -androidx-compose-ui-util = { group = "androidx.compose.ui", name = "ui-util", version.ref = "androidxComposeUi" } +androidx-compose-ui-util = { group = "androidx.compose.ui", name = "ui-util" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtxVersion" } androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidxCoreSplashscreen" } androidx-credentials = { group = "androidx.credentials", name = "credentials", version.ref = "credentialsVersion" } androidx-credentials-play-services-auth = { group = "androidx.credentials", name = "credentials-play-services-auth", version.ref = "credentialsVersion" } androidx-dataStore-core = { group = "androidx.datastore", name = "datastore", version.ref = "androidxDataStore" } -androidx-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "androidxHilt" } androidx-lifecycle-extensions = { group = "androidx.lifecycle", name = "lifecycle-extensions", version.ref = "lifecycleExtensionsVersion" } androidx-lifecycle-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleVersion" } androidx-lifecycle-runtimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycle" } @@ -129,13 +130,18 @@ androidx-navigation-testing = { group = "androidx.navigation", name = "navigatio androidx-profileinstaller = { group = "androidx.profileinstaller", name = "profileinstaller", version.ref = "androidxProfileinstaller" } androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" } androidx-tracing-ktx = { group = "androidx.tracing", name = "tracing-ktx", version.ref = "androidxTracing" } -coil-kt = { group = "io.coil-kt", name = "coil", version.ref = "coil" } -coil-kt-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil" } +androidx-ui-desktop = { group = "androidx.compose.ui", name = "ui-desktop", version.ref = "uiDesktopVersion" } +coil-core = { group = "io.coil-kt.coil3", name = "coil-core", version.ref = "coil" } +coil-kt = { group = "io.coil-kt.coil3", name = "coil", version.ref = "coil" } +coil-kt-compose = { group = "io.coil-kt.coil3", name = "coil-compose-core", version.ref = "coil" } +coil-network-ktor = { group = "io.coil-kt.coil3", name = "coil-network-ktor3", version.ref = "coil" } +coil-svg = { group = "io.coil-kt.coil3", name = "coil-svg", version.ref = "coil" } compose-gradlePlugin = { group = "org.jetbrains.kotlin", name = "compose-compiler-gradle-plugin", version.ref = "kotlin" } datastore = { group = "androidx.datastore", name = "datastore-core-okio", version.ref = "datastore" } detekt-formatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" } detekt-gradlePlugin = { group = "io.gitlab.arturbosch.detekt", name = "detekt-gradle-plugin", version.ref = "detekt" } espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" } +fineract-sdk = { group = "com.github.openMF", name = "mifos-android-sdk-arch", version.ref = "fineractSdk" } firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics-ktx" } firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" } firebase-cloud-messaging = { group = "com.google.firebase", name = "firebase-messaging-ktx" } @@ -147,39 +153,61 @@ google-oss-licenses = { group = "com.google.android.gms", name = "play-services- google-oss-licenses-plugin = { group = "com.google.android.gms", name = "oss-licenses-plugin", version.ref = "googleOssPlugin" } google-play-services-code-scanner = { group = "com.google.android.gms", name = "play-services-code-scanner", version.ref = "playServicesCodeScanner" } googleid = { group = "com.google.android.libraries.identity.googleid", name = "googleid", version.ref = "googleidVersion" } -hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" } -hilt-android-testing = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt" } -hilt-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt" } jetbrains-kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlinStdlibVersion" } junit = { group = "junit", name = "junit", version.ref = "junitVersion" } koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } koin-androidx-compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } +koin-androidx-navigation = { group = "io.insert-koin", name = "koin-androidx-navigation", version.ref = "koin" } +koin-annotations = { group = "io.insert-koin", name = "koin-annotations", version.ref = "koinAnnotationsVersion" } +koin-bom = { group = "io.insert-koin", name = "koin-bom", version.ref = "koin" } koin-compose = { group = "io.insert-koin", name = "koin-compose", version.ref = "koinComposeMultiplatform" } koin-compose-viewmodel = { group = "io.insert-koin", name = "koin-compose-viewmodel", version.ref = "koinComposeMultiplatform" } koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } +koin-core-viewmodel = { group = "io.insert-koin", name = "koin-core-viewmodel", version.ref = "koin" } +koin-ksp-compiler = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koinAnnotationsVersion" } +koin-test = { group = "io.insert-koin", name = "koin-test", version.ref = "koin" } +koin-test-junit4 = { group = "io.insert-koin", name = "koin-test-junit4", version.ref = "koin" } +koin-test-junit5 = { group = "io.insert-koin", name = "koin-test-junit5", version.ref = "koin" } kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } +kotlin-inject-compiler-ksp = { group = "me.tatarka.inject", name = "kotlin-inject-compiler-ksp", version.ref = "kotlinInject" } +kotlin-inject-runtime = { group = "me.tatarka.inject", name = "kotlin-inject-runtime", version.ref = "kotlinInject" } +kotlin-inject-runtime-kmp = { group = "me.tatarka.inject", name = "kotlin-inject-runtime-kmp", version.ref = "kotlinInject" } kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" } +kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin" } kotlinx-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinxImmutable" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" } kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" } +kotlinx-serialization-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-core", version.ref = "kotlinxSerializationJson" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } ktlint-gradlePlugin = { group = "org.jlleitschuh.gradle", name = "ktlint-gradle", version.ref = "ktlint" } ktor-client-android = { group = "io.ktor", name = "ktor-client-android", version.ref = "ktorVersion" } ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktorVersion" } ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktorVersion" } +ktor-client-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktorVersion" } +ktor-client-java = { group = "io.ktor", name = "ktor-client-java", version.ref = "ktorVersion" } +ktor-client-js = { group = "io.ktor", name = "ktor-client-js", version.ref = "ktorVersion" } ktor-client-json = { group = "io.ktor", name = "ktor-client-json", version.ref = "ktorVersion" } ktor-client-logging = { group = "io.ktor", name = "ktor-client-logging", version.ref = "ktorVersion" } ktor-client-serialization = { group = "io.ktor", name = "ktor-client-serialization", version.ref = "ktorVersion" } ktor-client-websockets = { group = "io.ktor", name = "ktor-client-websockets", version.ref = "ktorVersion" } +ktor-client-winhttp = { group = "io.ktor", name = "ktor-client-winhttp", version.ref = "ktorVersion" } ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktorVersion" } +ktorfit-converters-call = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-converters-call", version.ref = "ktorfit" } +ktorfit-converters-flow = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-converters-flow", version.ref = "ktorfit" } +ktorfit-ksp = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-ksp", version.ref = "ktorfitKsp" } +ktorfit-lib = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-lib", version.ref = "ktorfit" } libphonenumber-android = { group = "io.michaelrocks", name = "libphonenumber-android", version.ref = "libphonenumberAndroidVersion" } lint-api = { group = "com.android.tools.lint", name = "lint-api", version.ref = "androidTools" } lint-checks = { group = "com.android.tools.lint", name = "lint-checks", version.ref = "androidTools" } lint-tests = { group = "com.android.tools.lint", name = "lint-tests", version.ref = "androidTools" } logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logbackClassicVersion" } +multiplatform-settings = { group = "com.russhwolf", name = "multiplatform-settings-no-arg", version.ref = "multiplatformSettings" } +multiplatform-settings-coroutines = { group = "com.russhwolf", name = "multiplatform-settings-coroutines", version.ref = "multiplatformSettings" } +multiplatform-settings-serialization = { group = "com.russhwolf", name = "multiplatform-settings-serialization", version.ref = "multiplatformSettings" } +multiplatform-settings-test = { group = "com.russhwolf", name = "multiplatform-settings-test", version.ref = "multiplatformSettings" } play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "playServicesAuthVersion" } protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version.ref = "protobuf" } protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" } @@ -215,7 +243,6 @@ detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "firebaseCrashlyticsPlugin" } firebase-perf = { id = "com.google.firebase.firebase-perf", version.ref = "firebasePerfPlugin" } gms = { id = "com.google.gms.google-services", version.ref = "gmsPlugin" } -hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" } jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" } kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } @@ -224,6 +251,7 @@ kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlint" } +ktrofit = { id = "de.jensklingenberg.ktorfit", version.ref = "ktorfit" } mifos-detekt-plugin = { id = "mifos.detekt.plugin", version = "unspecified" } mifos-git-hooks = { id = "mifos.git.hooks", version = "unspecified" } mifos-ktlint-plugin = { id = "mifos.ktlint.plugin", version = "unspecified" } @@ -233,13 +261,16 @@ mifospay-android-application-compose = { id = "mifospay.android.application.comp mifospay-android-application-firebase = { id = "mifospay.android.application.firebase", version = "unspecified" } mifospay-android-application-flavors = { id = "mifospay.android.application.flavors", version = "unspecified" } mifospay-android-feature = { id = "mifospay.android.feature", version = "unspecified" } -mifospay-android-hilt = { id = "mifospay.android.hilt", version = "unspecified" } +mifospay-android-koin = { id = "mifospay.android.koin", version = "unspecified" } mifospay-android-library = { id = "mifospay.android.library", version = "unspecified" } mifospay-android-library-compose = { id = "mifospay.android.library.compose", version = "unspecified" } mifospay-android-lint = { id = "mifospay.android.lint", version = "unspecified" } mifospay-android-room = { id = "mifospay.android.room", version = "unspecified" } mifospay-android-test = { id = "mifospay.android.test", version = "unspecified" } +mifospay-cmp-feature = { id = "mifospay.cmp.feature", version = "unspecified" } mifospay-jvm-library = { id = "mifospay.jvm.library", version = "unspecified" } +mifospay-kmp-koin = { id = "mifospay.kmp.koin", version = "unspecified" } +mifospay-kmp-library = { id = "mifospay.kmp.library", version = "unspecified" } module-graph = { id = "com.jraska.module.graph.assertion", version.ref = "moduleGraph" } protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" } roborazzi = { id = "io.github.takahirom.roborazzi", version.ref = "roborazzi" } diff --git a/libs/country-code-picker/src/main/kotlin/com/mifos/library/countrycodepicker/CountryCodePicker.kt b/libs/country-code-picker/src/main/kotlin/com/mifos/library/countrycodepicker/CountryCodePicker.kt index 86da45a5d..322552949 100644 --- a/libs/country-code-picker/src/main/kotlin/com/mifos/library/countrycodepicker/CountryCodePicker.kt +++ b/libs/country-code-picker/src/main/kotlin/com/mifos/library/countrycodepicker/CountryCodePicker.kt @@ -262,7 +262,6 @@ fun CountryCodePicker( visualTransformation = phoneNumberTransformation, keyboardOptions = keyboardOptions ?: KeyboardOptions.Default.copy( keyboardType = KeyboardType.Phone, - autoCorrect = true, imeAction = ImeAction.Done, ), keyboardActions = keyboardActions ?: KeyboardActions( diff --git a/libs/material3-navigation/src/main/kotlin/com/mifos/library/material3/navigation/BottomSheet.kt b/libs/material3-navigation/src/main/kotlin/com/mifos/library/material3/navigation/BottomSheet.kt index 7ddaeafc1..27389dac3 100644 --- a/libs/material3-navigation/src/main/kotlin/com/mifos/library/material3/navigation/BottomSheet.kt +++ b/libs/material3-navigation/src/main/kotlin/com/mifos/library/material3/navigation/BottomSheet.kt @@ -11,6 +11,7 @@ package com.mifos.library.material3.navigation import androidx.compose.foundation.layout.Column import androidx.compose.material3.BottomSheetDefaults +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ModalBottomSheet import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable @@ -24,6 +25,7 @@ import androidx.compose.ui.unit.Dp * * @see [ModalBottomSheetLayout] */ +@OptIn(ExperimentalMaterial3Api::class) @Composable public fun ModalBottomSheetLayout( bottomSheetNavigator: BottomSheetNavigator, diff --git a/libs/mifos-passcode/build.gradle.kts b/libs/mifos-passcode/build.gradle.kts index fa250ec66..93d85ab8f 100644 --- a/libs/mifos-passcode/build.gradle.kts +++ b/libs/mifos-passcode/build.gradle.kts @@ -10,7 +10,7 @@ plugins { alias(libs.plugins.mifospay.android.library) alias(libs.plugins.mifospay.android.library.compose) - alias(libs.plugins.mifospay.android.hilt) + id("com.google.devtools.ksp") } android { @@ -30,6 +30,17 @@ dependencies { implementation(libs.androidx.lifecycle.runtimeCompose) implementation(libs.androidx.lifecycle.viewModelCompose) implementation(libs.androidx.navigation.compose) - implementation(libs.androidx.hilt.navigation.compose) + + implementation(platform(libs.koin.bom)) + implementation(libs.koin.core) + implementation(libs.koin.android) + implementation(libs.koin.androidx.navigation) + implementation(libs.koin.androidx.compose) + implementation(libs.koin.core.viewmodel) + + + testImplementation(libs.koin.test) + testImplementation(libs.koin.test.junit4) + testImplementation(libs.koin.test.junit5) } diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/PassCodeScreen.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/PassCodeScreen.kt index c20e54ad4..e7225a959 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/PassCodeScreen.kt +++ b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/PassCodeScreen.kt @@ -44,8 +44,8 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp -import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle +import org.koin.androidx.compose.koinViewModel import org.mifos.library.passcode.component.MifosIcon import org.mifos.library.passcode.component.PasscodeForgotButton import org.mifos.library.passcode.component.PasscodeHeader @@ -67,7 +67,7 @@ internal fun PasscodeScreen( onPasscodeConfirm: (String) -> Unit, onPasscodeRejected: () -> Unit, modifier: Modifier = Modifier, - viewModel: PasscodeViewModel = hiltViewModel(), + viewModel: PasscodeViewModel = koinViewModel(), ) { val context = LocalContext.current val preferenceManager = remember { PreferenceManager(context) } diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeManager.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeManager.kt index f2436f02d..15899edd1 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeManager.kt +++ b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeManager.kt @@ -9,16 +9,11 @@ */ package org.mifos.library.passcode.data -import android.content.Context -import dagger.hilt.android.qualifiers.ApplicationContext import org.mifos.library.passcode.utility.PreferenceManager -import javax.inject.Inject -class PasscodeManager @Inject constructor( - @ApplicationContext - private val context: Context, +class PasscodeManager( + private val passcodePreferencesHelper: PreferenceManager, ) { - private val passcodePreferencesHelper = PreferenceManager(context) val getPasscode = passcodePreferencesHelper.getSavedPasscode() diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepositoryImpl.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepositoryImpl.kt index 8f4cbd863..3346a2670 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepositoryImpl.kt +++ b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepositoryImpl.kt @@ -10,9 +10,8 @@ package org.mifos.library.passcode.data import org.mifos.library.passcode.utility.PreferenceManager -import javax.inject.Inject -class PasscodeRepositoryImpl @Inject constructor( +class PasscodeRepositoryImpl( private val preferenceManager: PreferenceManager, ) : PasscodeRepository { diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/di/ApplicationModule.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/di/ApplicationModule.kt index c5a5e821d..ad1c93c66 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/di/ApplicationModule.kt +++ b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/di/ApplicationModule.kt @@ -9,29 +9,27 @@ */ package org.mifos.library.passcode.di -import android.content.Context -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.qualifiers.ApplicationContext -import dagger.hilt.components.SingletonComponent +import org.koin.android.ext.koin.androidContext +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifos.library.passcode.data.PasscodeManager import org.mifos.library.passcode.data.PasscodeRepository import org.mifos.library.passcode.data.PasscodeRepositoryImpl import org.mifos.library.passcode.utility.PreferenceManager -import javax.inject.Singleton +import org.mifos.library.passcode.viewmodels.PasscodeViewModel -@Module -@InstallIn(SingletonComponent::class) -object ApplicationModule { - @Provides - @Singleton - fun providePrefManager(@ApplicationContext context: Context): PreferenceManager { - return PreferenceManager(context) +val ApplicationModule = module { + + factory { + PreferenceManager(context = androidContext()) } - @Provides - @Singleton - fun providesPasscodeRepository(preferenceManager: PreferenceManager): PasscodeRepository { - return PasscodeRepositoryImpl(preferenceManager) + single { PasscodeRepositoryImpl(preferenceManager = get()) } + + viewModel { + PasscodeViewModel(passcodeRepository = get()) + } + factory { + PasscodeManager(passcodePreferencesHelper = get()) } } diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt index 4842a5800..c0d2631a6 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt +++ b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt @@ -12,7 +12,6 @@ package org.mifos.library.passcode.viewmodels import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asSharedFlow @@ -21,10 +20,8 @@ import kotlinx.coroutines.launch import org.mifos.library.passcode.data.PasscodeRepository import org.mifos.library.passcode.utility.Constants.PASSCODE_LENGTH import org.mifos.library.passcode.utility.Step -import javax.inject.Inject -@HiltViewModel -internal class PasscodeViewModel @Inject constructor( +internal class PasscodeViewModel( private val passcodeRepository: PasscodeRepository, ) : ViewModel() { diff --git a/mifospay/build.gradle.kts b/mifospay/build.gradle.kts index 4460c2e83..5921928a6 100644 --- a/mifospay/build.gradle.kts +++ b/mifospay/build.gradle.kts @@ -8,6 +8,7 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ import org.mifospay.MifosBuildType +import org.mifospay.dynamicVersion /* * Copyright 2024 Mifos Initiative @@ -23,10 +24,10 @@ plugins { alias(libs.plugins.mifospay.android.application) alias(libs.plugins.mifospay.android.application.compose) alias(libs.plugins.mifospay.android.application.flavors) - alias(libs.plugins.mifospay.android.hilt) alias(libs.plugins.mifospay.android.application.firebase) alias(libs.plugins.roborazzi) id("com.google.android.gms.oss-licenses-plugin") + id("com.google.devtools.ksp") } android { @@ -34,7 +35,7 @@ android { defaultConfig { applicationId = "org.mifospay" - versionName = project.version.toString() + versionName = project.dynamicVersion versionCode = System.getenv("VERSION_CODE")?.toIntOrNull() ?: 1 vectorDrawables.useSupportLibrary = true testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" @@ -86,8 +87,6 @@ android { } dependencies { - implementation(projects.shared) - implementation(projects.core.data) implementation(projects.core.ui) implementation(projects.core.designsystem) @@ -132,8 +131,6 @@ dependencies { implementation(libs.androidx.compose.material3.windowSizeClass) implementation(libs.androidx.compose.runtime.tracing) - implementation(libs.androidx.hilt.navigation.compose) - ksp(libs.hilt.compiler) implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.android) @@ -150,16 +147,20 @@ dependencies { runtimeOnly(libs.androidx.compose.runtime) debugImplementation(libs.androidx.compose.ui.tooling) - kspTest(libs.hilt.compiler) testImplementation(libs.junit) - testImplementation(libs.hilt.android.testing) testImplementation(libs.androidx.compose.ui.test) androidTestImplementation(libs.androidx.compose.ui.test) androidTestImplementation(libs.espresso.core) androidTestImplementation(libs.androidx.test.ext.junit) - androidTestImplementation(libs.hilt.android.testing) + + implementation(libs.koin.android) + implementation(libs.ktor.client.core) + + testImplementation(kotlin("test")) + testImplementation(libs.koin.test) + testImplementation(libs.koin.test.junit4) } dependencyGuard { diff --git a/mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt b/mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt index b96d6758e..9abd02dd6 100644 --- a/mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt +++ b/mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt @@ -1,57 +1,57 @@ +--- androidx.databinding:databinding-common:8.5.2 +--- androidx.databinding:databinding-runtime:8.5.2 -| +--- androidx.collection:collection:1.0.0 -> 1.4.2 -| | \--- androidx.collection:collection-jvm:1.4.2 +| +--- androidx.collection:collection:1.0.0 -> 1.4.4 +| | \--- androidx.collection:collection-jvm:1.4.4 | | +--- androidx.annotation:annotation:1.8.1 | | | \--- androidx.annotation:annotation-jvm:1.8.1 | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 | | | +--- org.jetbrains:annotations:13.0 -> 23.0.0 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 1.9.20 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0 -> 1.9.20 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.0.0 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0 -> 2.0.0 (c) | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:2.0.20 (c) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.collection:collection-ktx:1.4.2 (c) -| | \--- androidx.collection:collection-ktx:1.3.0 -> 1.4.2 (c) +| | +--- androidx.collection:collection-ktx:1.4.4 (c) +| | \--- androidx.collection:collection-ktx:1.3.0 -> 1.4.4 (c) | +--- androidx.databinding:databinding-common:8.5.2 | +--- androidx.databinding:viewbinding:8.5.2 | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| \--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.4 -| \--- androidx.lifecycle:lifecycle-runtime-android:2.8.4 +| \--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 +| \--- androidx.lifecycle:lifecycle-runtime-android:2.8.6 | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) | +--- androidx.arch.core:core-common:2.2.0 | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | +--- androidx.arch.core:core-runtime:2.2.0 | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | | \--- androidx.arch.core:core-common:2.2.0 (*) -| +--- androidx.lifecycle:lifecycle-common:2.8.4 -| | \--- androidx.lifecycle:lifecycle-common-jvm:2.8.4 +| +--- androidx.lifecycle:lifecycle-common:2.8.6 +| | \--- androidx.lifecycle:lifecycle-common-jvm:2.8.6 | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1 +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 | | | +--- org.jetbrains:annotations:23.0.0 -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.8.1 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 (c) -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.8.1 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) -| +--- androidx.profileinstaller:profileinstaller:1.3.1 -| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0 (c) +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.9.0 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 +| | +--- androidx.annotation:annotation:1.8.1 (*) | | +--- androidx.concurrent:concurrent-futures:1.1.0 | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | | | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava @@ -62,357 +62,346 @@ | | | \--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (c) | | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.8.1 -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +--- androidx.databinding:databinding-adapters:8.5.2 | +--- androidx.databinding:databinding-runtime:8.5.2 (*) | \--- androidx.databinding:databinding-common:8.5.2 +--- androidx.databinding:databinding-ktx:8.5.2 | +--- androidx.databinding:databinding-runtime:8.5.2 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 -> 2.0.20 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1 -> 1.8.1 (*) -| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.4 -| | \--- androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.4 +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20 -> 2.0.0 +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1 -> 1.9.0 (*) +| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.6 +| | \--- androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.6 | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-livedata:2.6.1 -> 2.8.4 +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata:2.6.1 -> 2.8.6 | | +--- androidx.arch.core:core-common:2.2.0 (*) | | +--- androidx.arch.core:core-runtime:2.2.0 (*) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 | | | +--- androidx.arch.core:core-common:2.2.0 (*) | | | +--- androidx.arch.core:core-runtime:2.2.0 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.4 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (*) | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-process:2.6.1 -> 2.8.4 +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-process:2.6.1 -> 2.8.6 | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) | | +--- androidx.startup:startup-runtime:1.1.1 (*) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-service:2.6.1 -> 2.8.4 -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-service:2.6.1 -> 2.8.6 +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) -| \--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.4 -| \--- androidx.lifecycle:lifecycle-viewmodel-android:2.8.4 +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| \--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 +| \--- androidx.lifecycle:lifecycle-viewmodel-android:2.8.6 | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) -| +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -+--- androidx.compose:compose-bom:2024.08.00 -| +--- androidx.compose.material3:material3-window-size-class:1.2.1 (c) -| +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-tooling-preview:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.foundation:foundation:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.foundation:foundation-layout:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.material:material-icons-extended:1.6.8 (c) -| +--- androidx.compose.material3:material3:1.2.1 (c) -| +--- androidx.compose.ui:ui-util:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.runtime:runtime-saveable:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.animation:animation:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.material3:material3-window-size-class-android:1.2.1 (c) -| +--- androidx.compose.animation:animation-graphics:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-geometry:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.animation:animation-core:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.foundation:foundation-layout-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.runtime:runtime-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.runtime:runtime-saveable-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.material3:material3-android:1.2.1 (c) -| +--- androidx.compose.material:material-icons-extended-android:1.6.8 (c) -| +--- androidx.compose.animation:animation-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-unit:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.animation:animation-core-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-graphics:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-text:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.material:material-icons-core:1.6.8 (c) -| +--- androidx.compose.material:material-ripple:1.6.8 (c) -| +--- androidx.compose.ui:ui-unit-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-util-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.foundation:foundation-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-geometry-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-tooling-preview-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-graphics-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-text-android:1.6.8 -> 1.7.0-rc01 (c) -| +--- androidx.compose.material:material-icons-core-android:1.6.8 (c) -| +--- androidx.compose.material:material-ripple-android:1.6.8 (c) -| \--- androidx.compose.animation:animation-graphics-android:1.6.8 -> 1.7.0-rc01 (c) -+--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 -| \--- androidx.compose.ui:ui-tooling-preview-android:1.7.0-rc01 ++--- androidx.compose:compose-bom:2024.09.02 +| +--- androidx.compose.material3:material3-window-size-class:1.3.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) +| +--- androidx.compose.runtime:runtime:1.7.2 (c) +| +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| +--- androidx.compose.foundation:foundation:1.7.2 (c) +| +--- androidx.compose.foundation:foundation-layout:1.7.2 (c) +| +--- androidx.compose.material:material-icons-extended:1.7.2 (c) +| +--- androidx.compose.material3:material3:1.3.0 (c) +| +--- androidx.compose.ui:ui-util:1.7.2 (c) +| +--- androidx.compose.runtime:runtime-saveable:1.7.2 (c) +| +--- androidx.compose.ui:ui:1.7.2 (c) +| +--- androidx.compose.material3.adaptive:adaptive-android:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 (c) +| +--- androidx.compose.animation:animation:1.7.2 (c) +| +--- androidx.compose.material3:material3-window-size-class-android:1.3.0 (c) +| +--- androidx.compose.runtime:runtime-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-tooling-preview-android:1.7.2 (c) +| +--- androidx.compose.material:material:1.7.2 (c) +| +--- androidx.compose.animation:animation-graphics:1.7.2 (c) +| +--- androidx.compose.foundation:foundation-layout-android:1.7.2 (c) +| +--- androidx.compose.runtime:runtime-saveable-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-android:1.7.2 (c) +| +--- androidx.compose.foundation:foundation-android:1.7.2 (c) +| +--- androidx.compose.material:material-icons-extended-android:1.7.2 (c) +| +--- androidx.compose.material3:material3-android:1.3.0 (c) +| +--- androidx.compose.ui:ui-util-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| +--- androidx.compose.animation:animation-core:1.7.2 (c) +| +--- androidx.compose.animation:animation-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| +--- androidx.compose.material:material-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-geometry-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-unit-android:1.7.2 (c) +| +--- androidx.compose.animation:animation-graphics-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| +--- androidx.compose.ui:ui-text:1.7.2 (c) +| +--- androidx.compose.material:material-icons-core:1.7.2 (c) +| +--- androidx.compose.material:material-ripple:1.7.2 (c) +| +--- androidx.compose.animation:animation-core-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-graphics-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-text-android:1.7.2 (c) +| +--- androidx.compose.material:material-icons-core-android:1.7.2 (c) +| \--- androidx.compose.material:material-ripple-android:1.7.2 (c) ++--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 +| \--- androidx.compose.ui:ui-tooling-preview-android:1.7.2 | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| +--- androidx.compose.runtime:runtime:1.7.0-rc01 -| | \--- androidx.compose.runtime:runtime-android:1.7.0-rc01 -| | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 +| +--- androidx.compose.runtime:runtime:1.7.2 +| | \--- androidx.compose.runtime:runtime-android:1.7.2 +| | +--- androidx.annotation:annotation-experimental:1.4.1 | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) -| | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) +| | +--- androidx.collection:collection:1.4.4 (*) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.8.1 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) -| | \--- androidx.compose.runtime:runtime-saveable:1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui:1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-geometry:1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-graphics:1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-text:1.7.0-rc01 (c) -| +--- androidx.compose.ui:ui-unit:1.7.0-rc01 (c) -| \--- androidx.compose.ui:ui-util:1.7.0-rc01 (c) -+--- com.google.dagger:hilt-android:2.52 -| +--- com.google.dagger:dagger:2.52 -| | +--- jakarta.inject:jakarta.inject-api:2.0.1 -| | \--- javax.inject:javax.inject:1 -| +--- com.google.dagger:dagger-lint-aar:2.52 -| +--- com.google.dagger:hilt-core:2.52 -| | +--- com.google.dagger:dagger:2.52 (*) -| | +--- com.google.code.findbugs:jsr305:3.0.2 -| | \--- javax.inject:javax.inject:1 -| +--- com.google.code.findbugs:jsr305:3.0.2 -| +--- androidx.activity:activity:1.5.1 -> 1.9.1 -| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) -| | +--- androidx.core:core:1.13.0 -> 1.13.1 -| | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) -| | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | | +--- androidx.interpolator:interpolator:1.0.0 -| | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 -> 2.8.4 (*) -| | | +--- androidx.versionedparcelable:versionedparcelable:1.1.1 -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | \--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.core:core-ktx:1.13.1 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.4 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.4 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.4 -| | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- androidx.core:core:1.13.1 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | \--- androidx.core:core:1.13.1 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (*) -| | | +--- androidx.savedstate:savedstate:1.2.1 -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) -| | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.8.4 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) -| | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.8.1 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | | \--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | +--- androidx.profileinstaller:profileinstaller:1.3.1 (*) -| | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | +--- androidx.tracing:tracing:1.0.0 -> 1.3.0-alpha02 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.activity:activity-compose:1.9.1 (c) -| | \--- androidx.activity:activity-ktx:1.9.1 (c) -| +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| +--- androidx.annotation:annotation-experimental:1.3.1 -> 1.4.1 (*) -| +--- androidx.fragment:fragment:1.5.1 -> 1.7.1 -| | +--- androidx.activity:activity:1.8.1 -> 1.9.1 (*) -| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | +--- androidx.collection:collection:1.1.0 -> 1.4.2 (*) -| | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.1 -> 2.8.4 (*) -| | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.4 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.4 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.4 (*) -| | +--- androidx.loader:loader:1.0.0 -> 1.1.0 -| | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0 -> 2.8.4 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.8.4 (*) -| | | \--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) -| | +--- androidx.profileinstaller:profileinstaller:1.3.1 (*) -| | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | +--- androidx.viewpager:viewpager:1.0.0 -| | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | | \--- androidx.customview:customview:1.0.0 -| | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | \--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | \--- androidx.fragment:fragment-ktx:1.7.1 (c) -| +--- androidx.lifecycle:lifecycle-common:2.5.1 -> 2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel:2.5.1 -> 2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.5.1 -> 2.8.4 (*) -| +--- androidx.savedstate:savedstate:1.2.0 -> 1.2.1 (*) -| +--- javax.inject:javax.inject:1 -| \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) -+--- com.google.firebase:firebase-bom:33.1.2 +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | \--- androidx.compose.runtime:runtime-saveable:1.7.2 (c) +| +--- androidx.compose.ui:ui:1.7.2 (c) +| +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| +--- androidx.compose.ui:ui-util:1.7.2 (c) +| +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| \--- androidx.compose.ui:ui-text:1.7.2 (c) ++--- com.google.firebase:firebase-bom:33.3.0 | +--- com.google.firebase:firebase-perf-ktx:21.0.1 (c) -| +--- com.google.firebase:firebase-crashlytics-ktx:19.0.3 (c) -| +--- com.google.firebase:firebase-analytics-ktx:22.0.2 (c) -| +--- com.google.firebase:firebase-messaging-ktx:24.0.0 (c) +| +--- com.google.firebase:firebase-crashlytics-ktx:19.1.0 (c) +| +--- com.google.firebase:firebase-analytics-ktx:22.1.0 (c) +| +--- com.google.firebase:firebase-messaging-ktx:24.0.1 (c) | +--- com.google.firebase:firebase-perf:21.0.1 (c) | +--- com.google.firebase:firebase-common:21.0.0 (c) | +--- com.google.firebase:firebase-common-ktx:21.0.0 (c) -| +--- com.google.firebase:firebase-crashlytics:19.0.3 (c) -| +--- com.google.firebase:firebase-analytics:22.0.2 (c) -| +--- com.google.firebase:firebase-messaging:24.0.0 (c) +| +--- com.google.firebase:firebase-crashlytics:19.1.0 (c) +| +--- com.google.firebase:firebase-analytics:22.1.0 (c) +| +--- com.google.firebase:firebase-messaging:24.0.1 (c) | +--- com.google.firebase:firebase-encoders:17.0.0 (c) | +--- com.google.firebase:firebase-config:22.0.0 (c) | \--- com.google.firebase:firebase-installations:18.0.0 (c) -+--- com.google.firebase:firebase-analytics-ktx -> 22.0.2 -| +--- com.google.firebase:firebase-analytics:22.0.2 -| | +--- com.google.android.gms:play-services-measurement:22.0.2 -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) ++--- com.google.firebase:firebase-analytics-ktx -> 22.1.0 +| +--- com.google.firebase:firebase-analytics:22.1.0 +| | +--- com.google.android.gms:play-services-measurement:22.1.0 +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) | | | +--- androidx.legacy:legacy-support-core-utils:1.0.0 | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) +| | | | +--- androidx.core:core:1.0.0 -> 1.13.1 +| | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) +| | | | | +--- androidx.interpolator:interpolator:1.0.0 +| | | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 -> 2.8.6 (*) +| | | | | +--- androidx.versionedparcelable:versionedparcelable:1.1.1 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | \--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | \--- androidx.core:core-ktx:1.13.1 (c) | | | | +--- androidx.documentfile:documentfile:1.0.0 | | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 (*) +| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 +| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.8.6 (*) +| | | | | \--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) | | | | +--- androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 | | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) | | | | \--- androidx.print:print:1.0.0 | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) | | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 | | | | \--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) +| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) | | | | +--- androidx.core:core:1.2.0 -> 1.13.1 (*) -| | | | \--- androidx.fragment:fragment:1.1.0 -> 1.7.1 (*) +| | | | \--- androidx.fragment:fragment:1.1.0 -> 1.8.2 +| | | | +--- androidx.activity:activity:1.8.1 -> 1.9.2 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- androidx.core:core:1.13.0 -> 1.13.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.6 +| | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 +| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.core:core:1.13.1 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | | \--- androidx.core:core:1.13.1 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) +| | | | | | +--- androidx.savedstate:savedstate:1.2.1 +| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) +| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.8.6 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) +| | | | | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | | | | \--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | +--- androidx.tracing:tracing:1.0.0 -> 1.3.0-alpha02 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- androidx.activity:activity-compose:1.9.2 (c) +| | | | | \--- androidx.activity:activity-ktx:1.9.2 (c) +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 (*) +| | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- androidx.viewpager:viewpager:1.0.0 +| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) +| | | | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | \--- androidx.fragment:fragment-ktx:1.8.2 (c) | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-base:22.0.2 +| | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 | | | | \--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-impl:22.0.2 -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) +| | | +--- com.google.android.gms:play-services-measurement-impl:22.1.0 +| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) | | | | +--- androidx.core:core:1.9.0 -> 1.13.1 (*) | | | | +--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 | | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) | | | | | +--- androidx.core:core-ktx:1.8.0 -> 1.13.1 (*) | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) | | | | | \--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 (c) | | | | +--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 | | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) @@ -428,31 +417,31 @@ | | | | | | \--- com.google.j2objc:j2objc-annotations:1.3 | | | | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) | | | | | \--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 (c) | | | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 (*) | | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | | +--- com.google.android.gms:play-services-measurement-base:22.0.2 (*) +| | | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) | | | | +--- com.google.android.gms:play-services-stats:17.0.2 | | | | | +--- androidx.legacy:legacy-support-core-utils:1.0.0 (*) | | | | | \--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) | | | | \--- com.google.guava:guava:31.1-android (*) | | | \--- com.google.android.gms:play-services-stats:17.0.2 (*) -| | +--- com.google.android.gms:play-services-measurement-api:22.0.2 +| | +--- com.google.android.gms:play-services-measurement-api:22.1.0 | | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 (*) | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-base:22.0.2 (*) -| | | +--- com.google.android.gms:play-services-measurement-sdk-api:22.0.2 +| | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) +| | | +--- com.google.android.gms:play-services-measurement-sdk-api:22.1.0 | | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | | \--- com.google.android.gms:play-services-measurement-base:22.0.2 (*) +| | | | \--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) | | | +--- com.google.android.gms:play-services-tasks:18.2.0 | | | | \--- com.google.android.gms:play-services-basement:18.4.0 (*) | | | +--- com.google.firebase:firebase-common:21.0.0 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4 -> 1.8.1 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4 -> 1.9.0 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) | | | | | +--- com.google.android.gms:play-services-tasks:16.0.1 -> 18.2.0 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) | | | | +--- com.google.firebase:firebase-components:18.0.0 | | | | | +--- com.google.firebase:firebase-annotations:16.2.0 | | | | | | \--- javax.inject:javax.inject:1 @@ -466,7 +455,7 @@ | | | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) | | | +--- com.google.firebase:firebase-common-ktx:21.0.0 | | | | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) | | | | +--- com.google.firebase:firebase-components:18.0.0 (*) | | | | \--- com.google.firebase:firebase-annotations:16.2.0 (*) | | | +--- com.google.firebase:firebase-components:18.0.0 (*) @@ -486,11 +475,11 @@ | | | | \--- com.google.firebase:firebase-annotations:16.0.0 -> 16.2.0 (*) | | | +--- com.google.guava:guava:31.1-android (*) | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) -| | \--- com.google.android.gms:play-services-measurement-sdk:22.0.2 -| | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) +| | \--- com.google.android.gms:play-services-measurement-sdk:22.1.0 +| | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | +--- com.google.android.gms:play-services-measurement-base:22.0.2 (*) -| | \--- com.google.android.gms:play-services-measurement-impl:22.0.2 (*) +| | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) +| | \--- com.google.android.gms:play-services-measurement-impl:22.1.0 (*) | +--- com.google.firebase:firebase-common:21.0.0 (*) | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) | +--- com.google.firebase:firebase-components:18.0.0 (*) @@ -507,7 +496,7 @@ | | +--- com.google.firebase:firebase-config:21.5.0 -> 22.0.0 | | | +--- com.google.firebase:firebase-config-interop:16.0.1 | | | | +--- com.google.firebase:firebase-encoders-json:18.0.1 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 -> 1.9.20 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 -> 2.0.0 (*) | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | | | | | \--- com.google.firebase:firebase-encoders:17.0.0 | | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) @@ -526,7 +515,7 @@ | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) -| | +--- com.google.firebase:firebase-sessions:2.0.0 -> 2.0.3 +| | +--- com.google.firebase:firebase-sessions:2.0.0 -> 2.0.4 | | | +--- com.google.firebase:firebase-common:21.0.0 (*) | | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) | | | +--- com.google.firebase:firebase-components:18.0.0 (*) @@ -534,7 +523,7 @@ | | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) | | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) | | | +--- com.google.firebase:firebase-encoders-json:18.0.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) | | | +--- com.google.firebase:firebase-installations:18.0.0 (*) | | | +--- com.google.firebase:firebase-datatransport:19.0.0 | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) @@ -554,85 +543,45 @@ | | | | | +--- com.google.firebase:firebase-encoders-json:18.0.0 -> 18.0.1 (*) | | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | | | | +--- com.google.android.datatransport:transport-runtime:3.2.0 -> 3.3.0 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | +--- androidx.datastore:datastore-preferences:1.0.0 -> 1.1.1 -| | | | \--- androidx.datastore:datastore-preferences-android:1.1.1 -| | | | +--- androidx.datastore:datastore:1.1.1 -| | | | | \--- androidx.datastore:datastore-android:1.1.1 -| | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | | +--- androidx.datastore:datastore-core:1.1.1 -| | | | | | \--- androidx.datastore:datastore-core-android:1.1.1 -| | | | | | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-parcelize-runtime:1.9.22 -> 2.0.20 -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | | | | | \--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.20 -| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) -| | | | | | +--- androidx.datastore:datastore:1.1.1 (c) -| | | | | | +--- androidx.datastore:datastore-core-okio:1.1.1 (c) -| | | | | | +--- androidx.datastore:datastore-preferences:1.1.1 (c) -| | | | | | \--- androidx.datastore:datastore-preferences-core:1.1.1 (c) -| | | | | +--- androidx.datastore:datastore-core-okio:1.1.1 -| | | | | | \--- androidx.datastore:datastore-core-okio-jvm:1.1.1 -| | | | | | +--- androidx.datastore:datastore-core:1.1.1 (*) -| | | | | | +--- com.squareup.okio:okio:3.4.0 -> 3.9.0 -| | | | | | | \--- com.squareup.okio:okio-jvm:3.9.0 -| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) -| | | | | | +--- androidx.datastore:datastore-core:1.1.1 (c) -| | | | | | +--- androidx.datastore:datastore:1.1.1 (c) -| | | | | | +--- androidx.datastore:datastore-preferences:1.1.1 (c) -| | | | | | \--- androidx.datastore:datastore-preferences-core:1.1.1 (c) -| | | | | +--- com.squareup.okio:okio:3.4.0 -> 3.9.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) -| | | | | +--- androidx.datastore:datastore-core:1.1.1 (c) -| | | | | +--- androidx.datastore:datastore-core-okio:1.1.1 (c) -| | | | | +--- androidx.datastore:datastore-preferences:1.1.1 (c) -| | | | | \--- androidx.datastore:datastore-preferences-core:1.1.1 (c) -| | | | +--- androidx.datastore:datastore-preferences-core:1.1.1 -| | | | | \--- androidx.datastore:datastore-preferences-core-jvm:1.1.1 -| | | | | +--- androidx.datastore:datastore-core:1.1.1 (*) -| | | | | +--- androidx.datastore:datastore-core-okio:1.1.1 (*) -| | | | | +--- com.squareup.okio:okio:3.4.0 -> 3.9.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- androidx.datastore:datastore:1.1.1 (c) -| | | | | +--- androidx.datastore:datastore-core:1.1.1 (c) -| | | | | +--- androidx.datastore:datastore-core-okio:1.1.1 (c) -| | | | | \--- androidx.datastore:datastore-preferences:1.1.1 (c) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) -| | | | +--- androidx.datastore:datastore:1.1.1 (c) -| | | | +--- androidx.datastore:datastore-core:1.1.1 (c) -| | | | +--- androidx.datastore:datastore-core-okio:1.1.1 (c) -| | | | \--- androidx.datastore:datastore-preferences-core:1.1.1 (c) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | +--- androidx.datastore:datastore-preferences:1.0.0 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | +--- androidx.datastore:datastore:1.0.0 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.9.0 (*) +| | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | | \--- androidx.datastore:datastore-core:1.0.0 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.9.0 (*) +| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | \--- androidx.datastore:datastore-preferences-core:1.0.0 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | \--- androidx.datastore:datastore-core:1.0.0 (*) | | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) | | | \--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) | | +--- com.google.firebase:firebase-datatransport:18.1.8 -> 19.0.0 (*) | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-process:2.3.1 -> 2.8.4 (*) +| | +--- androidx.lifecycle:lifecycle-process:2.3.1 -> 2.8.6 (*) | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) | | +--- com.google.protobuf:protobuf-javalite:3.21.11 -> 4.26.0 | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) | | +--- androidx.appcompat:appcompat:1.2.0 -> 1.7.0 -| | | +--- androidx.activity:activity:1.7.0 -> 1.9.1 (*) +| | | +--- androidx.activity:activity:1.7.0 -> 1.9.2 (*) | | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) | | | +--- androidx.appcompat:appcompat-resources:1.7.0 | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) +| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) | | | | +--- androidx.core:core:1.6.0 -> 1.13.1 (*) | | | | +--- androidx.vectordrawable:vectordrawable:1.1.0 | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.2 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) | | | | +--- androidx.vectordrawable:vectordrawable-animated:1.1.0 | | | | | +--- androidx.vectordrawable:vectordrawable:1.1.0 (*) | | | | | +--- androidx.interpolator:interpolator:1.0.0 (*) -| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.2 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) | | | | \--- androidx.appcompat:appcompat:1.7.0 (c) -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) | | | +--- androidx.core:core:1.13.0 -> 1.13.1 (*) | | | +--- androidx.core:core-ktx:1.13.0 -> 1.13.1 (*) | | | +--- androidx.cursoradapter:cursoradapter:1.0.0 @@ -640,40 +589,43 @@ | | | +--- androidx.drawerlayout:drawerlayout:1.0.0 | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | | | \--- androidx.customview:customview:1.0.0 (*) +| | | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 (*) | | | +--- androidx.emoji2:emoji2:1.3.0 | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.2 (*) +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) | | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) -| | | | +--- androidx.lifecycle:lifecycle-process:2.4.1 -> 2.8.4 (*) +| | | | +--- androidx.lifecycle:lifecycle-process:2.4.1 -> 2.8.6 (*) | | | | +--- androidx.startup:startup-runtime:1.0.0 -> 1.1.1 (*) | | | | \--- androidx.emoji2:emoji2-views-helper:1.3.0 (c) | | | +--- androidx.emoji2:emoji2-views-helper:1.2.0 -> 1.3.0 -| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.2 (*) +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) | | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) | | | | +--- androidx.emoji2:emoji2:1.3.0 (*) | | | | \--- androidx.emoji2:emoji2:1.3.0 (c) -| | | +--- androidx.fragment:fragment:1.5.4 -> 1.7.1 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.4 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.4 (*) -| | | +--- androidx.profileinstaller:profileinstaller:1.3.1 (*) +| | | +--- androidx.fragment:fragment:1.5.4 -> 1.8.2 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) | | | +--- androidx.resourceinspection:resourceinspection-annotation:1.0.1 | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | | | +--- androidx.savedstate:savedstate:1.2.1 (*) | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) | | | \--- androidx.appcompat:appcompat-resources:1.7.0 (c) | | +--- com.google.android.datatransport:transport-api:3.0.0 -> 3.2.0 (*) -| | +--- com.google.dagger:dagger:2.27 -> 2.52 (*) +| | +--- com.google.dagger:dagger:2.27 +| | | \--- javax.inject:javax.inject:1 | | \--- com.squareup.okhttp3:okhttp:3.12.1 -> 4.12.0 -| | +--- com.squareup.okio:okio:3.6.0 -> 3.9.0 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 1.9.20 (*) +| | +--- com.squareup.okio:okio:3.6.0 -> 3.9.0 +| | | \--- com.squareup.okio:okio-jvm:3.9.0 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 2.0.0 (*) | +--- com.google.firebase:firebase-common:21.0.0 (*) | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) | \--- com.google.firebase:firebase-components:18.0.0 (*) -+--- com.google.firebase:firebase-crashlytics-ktx -> 19.0.3 -| +--- com.google.firebase:firebase-crashlytics:19.0.3 -| | +--- com.google.firebase:firebase-sessions:2.0.3 (*) ++--- com.google.firebase:firebase-crashlytics-ktx -> 19.1.0 +| +--- com.google.firebase:firebase-crashlytics:19.1.0 +| | +--- com.google.firebase:firebase-sessions:2.0.4 (*) | | +--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) | | +--- com.google.firebase:firebase-common:21.0.0 (*) @@ -685,17 +637,17 @@ | | +--- com.google.firebase:firebase-installations:18.0.0 (*) | | +--- com.google.firebase:firebase-installations-interop:17.2.0 (*) | | +--- com.google.firebase:firebase-measurement-connector:20.0.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) | | +--- com.google.android.datatransport:transport-backend-cct:3.3.0 (*) | | +--- com.google.android.datatransport:transport-runtime:3.3.0 (*) | | \--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) | +--- com.google.firebase:firebase-common:21.0.0 (*) | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) | \--- com.google.firebase:firebase-components:18.0.0 (*) -+--- com.google.firebase:firebase-messaging-ktx -> 24.0.0 -| +--- com.google.firebase:firebase-messaging:24.0.0 ++--- com.google.firebase:firebase-messaging-ktx -> 24.0.1 +| +--- com.google.firebase:firebase-messaging:24.0.1 | | +--- com.google.firebase:firebase-common:21.0.0 (*) | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) | | +--- com.google.firebase:firebase-components:18.0.0 (*) @@ -714,9 +666,9 @@ | | +--- com.google.android.datatransport:transport-backend-cct:3.1.8 -> 3.3.0 (*) | | +--- com.google.android.datatransport:transport-runtime:3.1.8 -> 3.3.0 (*) | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) | | | +--- androidx.core:core:1.2.0 -> 1.13.1 (*) -| | | +--- androidx.fragment:fragment:1.0.0 -> 1.7.1 (*) +| | | +--- androidx.fragment:fragment:1.0.0 -> 1.8.2 (*) | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) | | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) | | +--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) @@ -729,835 +681,992 @@ | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) | +--- com.google.firebase:firebase-common:21.0.0 (*) | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) | \--- com.google.firebase:firebase-components:18.0.0 (*) -+--- project :shared -| +--- org.jetbrains.compose.ui:ui-tooling-preview:1.6.11 -| | \--- androidx.compose.ui:ui-tooling-preview:1.6.7 -> 1.7.0-rc01 (*) -| +--- androidx.activity:activity-compose:1.9.1 -| | +--- androidx.activity:activity-ktx:1.9.1 -| | | +--- androidx.activity:activity:1.9.1 (*) ++--- project :core:data +| +--- androidx.core:core-ktx:1.13.1 (*) +| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 +| | +--- androidx.tracing:tracing:1.3.0-alpha02 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | \--- androidx.tracing:tracing:1.3.0-alpha02 (c) +| +--- io.insert-koin:koin-android:4.0.0-RC2 +| | +--- io.insert-koin:koin-core:4.0.0-RC2 +| | | \--- io.insert-koin:koin-core-jvm:4.0.0-RC2 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- co.touchlab:stately-concurrency:2.0.7 +| | | | \--- co.touchlab:stately-concurrency-jvm:2.0.7 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | | | \--- co.touchlab:stately-strict:2.0.7 +| | | | \--- co.touchlab:stately-strict-jvm:2.0.7 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | | \--- co.touchlab:stately-concurrent-collections:2.0.7 +| | | \--- co.touchlab:stately-concurrent-collections-jvm:2.0.7 +| | | +--- co.touchlab:stately-concurrency:2.0.7 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 +| | | \--- io.insert-koin:koin-core-viewmodel-jvm:4.0.0-RC2 +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.0 +| | | | \--- androidx.lifecycle:lifecycle-viewmodel:2.8.0 -> 2.8.6 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 +| | | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 -> 2.8.6 (*) +| | | +--- org.jetbrains.androidx.core:core-bundle:1.0.0 +| | | | \--- org.jetbrains.androidx.core:core-bundle-android:1.0.0 +| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.0 +| | | | \--- androidx.savedstate:savedstate:1.2.1 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- androidx.appcompat:appcompat:1.7.0 (*) +| | +--- androidx.activity:activity-ktx:1.9.1 -> 1.9.2 +| | | +--- androidx.activity:activity:1.9.2 (*) | | | +--- androidx.core:core-ktx:1.13.0 -> 1.13.1 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.4 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.4 -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.6 +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.8.1 (*) -| | | | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.activity:activity:1.9.1 (c) -| | | \--- androidx.activity:activity-compose:1.9.1 (c) -| | +--- androidx.compose.runtime:runtime:1.0.1 -> 1.7.0-rc01 (*) -| | +--- androidx.compose.runtime:runtime-saveable:1.0.1 -> 1.7.0-rc01 -| | | \--- androidx.compose.runtime:runtime-saveable-android:1.7.0-rc01 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.compose.runtime:runtime:1.7.0-rc01 (c) -| | +--- androidx.compose.ui:ui:1.0.1 -> 1.7.0-rc01 -| | | \--- androidx.compose.ui:ui-android:1.7.0-rc01 -| | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.9.1 (*) -| | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.autofill:autofill:1.0.0 -| | | | \--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | +--- androidx.compose.runtime:runtime-saveable:1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui-geometry:1.7.0-rc01 -| | | | \--- androidx.compose.ui:ui-geometry-android:1.7.0-rc01 -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | | +--- androidx.compose.ui:ui-util:1.7.0-rc01 -| | | | | \--- androidx.compose.ui:ui-util-android:1.7.0-rc01 -| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- androidx.compose.ui:ui:1.7.0-rc01 (c) -| | | | | +--- androidx.compose.ui:ui-geometry:1.7.0-rc01 (c) -| | | | | +--- androidx.compose.ui:ui-graphics:1.7.0-rc01 (c) -| | | | | +--- androidx.compose.ui:ui-text:1.7.0-rc01 (c) -| | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.0-rc01 (c) -| | | | | \--- androidx.compose.ui:ui-unit:1.7.0-rc01 (c) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- androidx.compose.ui:ui:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-graphics:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-text:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-unit:1.7.0-rc01 (c) -| | | | \--- androidx.compose.ui:ui-util:1.7.0-rc01 (c) -| | | +--- androidx.compose.ui:ui-graphics:1.7.0-rc01 -| | | | \--- androidx.compose.ui:ui-graphics-android:1.7.0-rc01 -| | | | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) -| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | | +--- androidx.compose.ui:ui-unit:1.7.0-rc01 -| | | | | \--- androidx.compose.ui:ui-unit-android:1.7.0-rc01 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | | | | +--- androidx.collection:collection-ktx:1.2.0 -> 1.4.2 -| | | | | | +--- androidx.collection:collection:1.4.2 (*) -| | | | | | \--- androidx.collection:collection:1.4.2 (c) -| | | | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | | | +--- androidx.compose.ui:ui-geometry:1.7.0-rc01 (*) -| | | | | +--- androidx.compose.ui:ui-util:1.7.0-rc01 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- androidx.compose.ui:ui:1.7.0-rc01 (c) -| | | | | +--- androidx.compose.ui:ui-geometry:1.7.0-rc01 (c) -| | | | | +--- androidx.compose.ui:ui-graphics:1.7.0-rc01 (c) -| | | | | +--- androidx.compose.ui:ui-text:1.7.0-rc01 (c) -| | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.0-rc01 (c) -| | | | | \--- androidx.compose.ui:ui-util:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-util:1.7.0-rc01 (*) -| | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) -| | | | +--- androidx.graphics:graphics-path:1.0.1 -| | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- androidx.compose.ui:ui:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-geometry:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-text:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-unit:1.7.0-rc01 (c) -| | | | \--- androidx.compose.ui:ui-util:1.7.0-rc01 (c) -| | | +--- androidx.compose.ui:ui-text:1.7.0-rc01 -| | | | \--- androidx.compose.ui:ui-text-android:1.7.0-rc01 -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | | +--- androidx.compose.runtime:runtime-saveable:1.6.0 -> 1.7.0-rc01 (*) -| | | | +--- androidx.compose.ui:ui-graphics:1.7.0-rc01 (*) -| | | | +--- androidx.compose.ui:ui-unit:1.7.0-rc01 (*) -| | | | +--- androidx.compose.ui:ui-util:1.7.0-rc01 (*) -| | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) -| | | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) -| | | | +--- androidx.compose.ui:ui:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-geometry:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-graphics:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.0-rc01 (c) -| | | | +--- androidx.compose.ui:ui-unit:1.7.0-rc01 (c) -| | | | \--- androidx.compose.ui:ui-util:1.7.0-rc01 (c) -| | | +--- androidx.compose.ui:ui-unit:1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui-util:1.7.0-rc01 (*) -| | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) -| | | +--- androidx.customview:customview-poolingcontainer:1.0.0 -| | | | +--- androidx.core:core-ktx:1.5.0 -> 1.13.1 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) -| | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.3 -> 2.8.4 -| | | | \--- androidx.lifecycle:lifecycle-runtime-compose-android:2.8.4 -| | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | | | +--- androidx.compose.runtime:runtime:1.6.5 -> 1.7.0-rc01 (*) -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (*) -| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (*) -| | | | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) -| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.4 (*) -| | | +--- androidx.profileinstaller:profileinstaller:1.3.1 (*) -| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.8.1 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) -| | | +--- androidx.compose.ui:ui-geometry:1.7.0-rc01 (c) -| | | +--- androidx.compose.ui:ui-graphics:1.7.0-rc01 (c) -| | | +--- androidx.compose.ui:ui-text:1.7.0-rc01 (c) -| | | +--- androidx.compose.ui:ui-tooling-preview:1.7.0-rc01 (c) -| | | +--- androidx.compose.ui:ui-unit:1.7.0-rc01 (c) -| | | +--- androidx.compose.ui:ui-util:1.7.0-rc01 (c) -| | | \--- androidx.compose.foundation:foundation:1.7.0-rc01 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.4 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.activity:activity:1.9.1 (c) -| | \--- androidx.activity:activity-ktx:1.9.1 (c) -| +--- io.insert-koin:koin-android:3.6.0-Beta4 -| | +--- io.insert-koin:koin-core:3.6.0-Beta4 -| | | \--- io.insert-koin:koin-core-jvm:3.6.0-Beta4 -| | | +--- co.touchlab:stately-concurrency:2.0.6 -| | | | \--- co.touchlab:stately-concurrency-jvm:2.0.6 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10 -> 1.9.20 (*) -| | | | \--- co.touchlab:stately-strict:2.0.6 -| | | | \--- co.touchlab:stately-strict-jvm:2.0.6 -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10 -> 1.9.20 (*) -| | | +--- co.touchlab:stately-concurrent-collections:2.0.6 -| | | | \--- co.touchlab:stately-concurrent-collections-jvm:2.0.6 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10 -> 1.9.20 (*) -| | | | \--- co.touchlab:stately-concurrency:2.0.6 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) -| | +--- androidx.appcompat:appcompat:1.6.1 -> 1.7.0 (*) -| | +--- androidx.activity:activity-ktx:1.9.0 -> 1.9.1 (*) -| | +--- androidx.fragment:fragment-ktx:1.7.1 -| | | +--- androidx.activity:activity-ktx:1.8.1 -> 1.9.1 (*) -| | | +--- androidx.collection:collection-ktx:1.1.0 -> 1.4.2 (*) +| | | +--- androidx.activity:activity:1.9.2 (c) +| | | \--- androidx.activity:activity-compose:1.9.2 (c) +| | +--- androidx.fragment:fragment-ktx:1.8.2 +| | | +--- androidx.activity:activity-ktx:1.8.1 -> 1.9.2 (*) +| | | +--- androidx.collection:collection-ktx:1.1.0 -> 1.4.4 +| | | | +--- androidx.collection:collection:1.4.4 (*) +| | | | \--- androidx.collection:collection:1.4.4 (c) | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) -| | | +--- androidx.fragment:fragment:1.7.1 (*) -| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.1 -> 2.8.4 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.4 (*) +| | | +--- androidx.fragment:fragment:1.8.2 (*) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.6 (*) | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.fragment:fragment:1.7.1 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0 -> 2.8.4 (*) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.0 -> 2.8.4 +| | | \--- androidx.fragment:fragment:1.8.2 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 -> 2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 -> 2.8.6 | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.4 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) -| +--- io.insert-koin:koin-androidx-compose:3.6.0-Beta4 -| | +--- io.insert-koin:koin-android:3.6.0-Beta4 (*) -| | +--- io.insert-koin:koin-compose:1.2.0-Beta4 -| | | \--- io.insert-koin:koin-compose-jvm:1.2.0-Beta4 -| | | +--- io.insert-koin:koin-core:3.6.0-Beta4 (*) -| | | +--- org.jetbrains.compose.runtime:runtime:1.6.10-rc03 -> 1.6.11 -| | | | \--- androidx.compose.runtime:runtime:1.6.7 -> 1.7.0-rc01 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) -| | +--- androidx.compose.runtime:runtime:1.6.7 -> 1.7.0-rc01 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0 -> 2.8.4 -| | | \--- androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.4 -| | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | | +--- androidx.compose.runtime:runtime:1.6.0 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.0-rc01 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.4 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.4 (c) -| | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 (c) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) -| +--- io.insert-koin:koin-core:3.6.0-Beta4 (*) -| +--- com.squareup.wire:wire-runtime:5.0.0 -| | \--- com.squareup.wire:wire-runtime-jvm:5.0.0 -| | +--- com.squareup.okio:okio:3.9.0 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) -| +--- org.jetbrains.compose.material3:material3:1.6.11 -| | \--- androidx.compose.material3:material3:1.2.1 -| | \--- androidx.compose.material3:material3-android:1.2.1 -| | +--- androidx.activity:activity-compose:1.5.0 -> 1.9.1 (*) -| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | +--- androidx.compose.animation:animation-core:1.6.0 -> 1.7.0-rc01 -| | | \--- androidx.compose.animation:animation-core-android:1.7.0-rc01 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui-graphics:1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui-unit:1.6.0 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui-util:1.7.0-rc01 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) -| | | +--- androidx.compose.animation:animation:1.7.0-rc01 (c) -| | | \--- androidx.compose.animation:animation-graphics:1.7.0-rc01 (c) -| | +--- androidx.compose.foundation:foundation:1.6.0 -> 1.7.0-rc01 -| | | \--- androidx.compose.foundation:foundation-android:1.7.0-rc01 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | | +--- androidx.compose.animation:animation:1.7.0-rc01 -| | | | \--- androidx.compose.animation:animation-android:1.7.0-rc01 -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | | | +--- androidx.compose.animation:animation-core:1.7.0-rc01 (*) -| | | | +--- androidx.compose.foundation:foundation-layout:1.6.0 -> 1.7.0-rc01 -| | | | | \--- androidx.compose.foundation:foundation-layout-android:1.7.0-rc01 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | | | | +--- androidx.compose.animation:animation-core:1.2.1 -> 1.7.0-rc01 (*) -| | | | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.0-rc01 (*) -| | | | | +--- androidx.compose.ui:ui-unit:1.7.0-rc01 (*) -| | | | | +--- androidx.compose.ui:ui-util:1.7.0-rc01 (*) -| | | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) -| | | | | \--- androidx.compose.foundation:foundation:1.7.0-rc01 (c) -| | | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | | +--- androidx.compose.ui:ui:1.7.0-rc01 (*) -| | | | +--- androidx.compose.ui:ui-geometry:1.6.0 -> 1.7.0-rc01 (*) -| | | | +--- androidx.compose.ui:ui-graphics:1.7.0-rc01 (*) -| | | | +--- androidx.compose.ui:ui-util:1.7.0-rc01 (*) -| | | | +--- androidx.compose.animation:animation-core:1.7.0-rc01 (c) -| | | | \--- androidx.compose.animation:animation-graphics:1.7.0-rc01 (c) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.0-rc01 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui:1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui-text:1.6.0 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.0-rc01 (*) -| | | +--- androidx.core:core:1.13.1 (*) -| | | +--- androidx.emoji2:emoji2:1.3.0 (*) -| | | \--- androidx.compose.foundation:foundation-layout:1.7.0-rc01 (c) -| | +--- androidx.compose.foundation:foundation-layout:1.6.0 -> 1.7.0-rc01 (*) -| | +--- androidx.compose.material:material-icons-core:1.6.0 -> 1.6.8 -| | | \--- androidx.compose.material:material-icons-core-android:1.6.8 -| | | +--- androidx.compose.ui:ui:1.6.8 -> 1.7.0-rc01 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.compose.material:material-icons-extended:1.6.8 (c) -| | | \--- androidx.compose.material:material-ripple:1.6.8 (c) -| | +--- androidx.compose.material:material-ripple:1.6.0 -> 1.6.8 -| | | \--- androidx.compose.material:material-ripple-android:1.6.8 -| | | +--- androidx.compose.animation:animation:1.6.8 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.foundation:foundation:1.6.8 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui-util:1.6.8 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.material:material-icons-core:1.6.8 (c) -| | | \--- androidx.compose.material:material-icons-extended:1.6.8 (c) -| | +--- androidx.compose.runtime:runtime:1.6.0 -> 1.7.0-rc01 (*) -| | +--- androidx.compose.ui:ui-graphics:1.6.0 -> 1.7.0-rc01 (*) -| | +--- androidx.compose.ui:ui-text:1.6.0 -> 1.7.0-rc01 (*) -| | +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.0-rc01 (*) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.6.1 -> 2.8.4 (*) -| | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.4 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.4 (*) -| | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) -| | \--- androidx.compose.material3:material3-window-size-class:1.2.1 (c) -| +--- org.jetbrains.compose.ui:ui:1.6.11 -| | \--- androidx.compose.ui:ui:1.6.7 -> 1.7.0-rc01 (*) -| +--- org.jetbrains.compose.components:components-resources:1.6.11 -| | \--- org.jetbrains.compose.components:components-resources-android:1.6.11 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) -| | +--- org.jetbrains.compose.foundation:foundation:1.6.11 -| | | \--- androidx.compose.foundation:foundation:1.6.7 -> 1.7.0-rc01 (*) -| | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.8.1 (*) -| +--- org.jetbrains.compose.components:components-ui-tooling-preview:1.6.11 -| | \--- org.jetbrains.compose.components:components-ui-tooling-preview-android:1.6.11 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 -| | \--- org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.0 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1 -| | \--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.1 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.1 -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.1 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.1 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1 (c) -| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.1 (c) -| | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.1 -| | \--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.1 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.1 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib-common:2.0.0 -> 2.0.20 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-compose:1.2.0-Beta4 (*) -| +--- io.insert-koin:koin-compose-viewmodel:1.2.0-Beta4 -| | \--- io.insert-koin:koin-compose-viewmodel-jvm:1.2.0-Beta4 -| | +--- io.insert-koin:koin-compose:1.2.0-Beta4 (*) -| | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0-rc03 -| | | \--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0 -> 2.8.4 (*) -| | +--- org.jetbrains.androidx.navigation:navigation-compose:2.7.0-alpha06 -| | | \--- androidx.navigation:navigation-compose:2.7.7 -> 2.8.0-rc01 -| | | +--- androidx.activity:activity-compose:1.8.0 -> 1.9.1 (*) -| | | +--- androidx.compose.animation:animation:1.7.0-rc01 (*) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.0-rc01 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | +--- androidx.compose.runtime:runtime-saveable:1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui:1.7.0-rc01 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2 -> 2.8.4 (*) -| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.0-rc01 -| | | | +--- androidx.navigation:navigation-common-ktx:2.8.0-rc01 -| | | | | +--- androidx.navigation:navigation-common:2.8.0-rc01 -| | | | | | +--- androidx.annotation:annotation:1.8.1 (*) -| | | | | | +--- androidx.collection:collection-ktx:1.4.2 (*) -| | | | | | +--- androidx.core:core-ktx:1.1.0 -> 1.13.1 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.2 -> 2.8.4 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.4 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.4 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 -> 2.8.4 (*) -| | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 (*) -| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.1 (*) -| | | | | | +--- androidx.navigation:navigation-common-ktx:2.8.0-rc01 (c) -| | | | | | +--- androidx.navigation:navigation-compose:2.8.0-rc01 (c) -| | | | | | +--- androidx.navigation:navigation-runtime:2.8.0-rc01 (c) -| | | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.0-rc01 (c) -| | | | | +--- androidx.navigation:navigation-common:2.8.0-rc01 (c) -| | | | | +--- androidx.navigation:navigation-compose:2.8.0-rc01 (c) -| | | | | +--- androidx.navigation:navigation-runtime:2.8.0-rc01 (c) -| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.0-rc01 (c) -| | | | +--- androidx.navigation:navigation-runtime:2.8.0-rc01 -| | | | | +--- androidx.activity:activity-ktx:1.7.1 -> 1.9.1 (*) -| | | | | +--- androidx.annotation:annotation-experimental:1.4.1 (*) -| | | | | +--- androidx.collection:collection:1.4.2 (*) -| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.4 (*) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.4 (*) -| | | | | +--- androidx.navigation:navigation-common:2.8.0-rc01 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.1 (*) -| | | | | +--- androidx.navigation:navigation-common:2.8.0-rc01 (c) -| | | | | +--- androidx.navigation:navigation-common-ktx:2.8.0-rc01 (c) -| | | | | +--- androidx.navigation:navigation-compose:2.8.0-rc01 (c) -| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.0-rc01 (c) -| | | | +--- androidx.navigation:navigation-common-ktx:2.8.0-rc01 (c) -| | | | +--- androidx.navigation:navigation-compose:2.8.0-rc01 (c) -| | | | +--- androidx.navigation:navigation-runtime:2.8.0-rc01 (c) -| | | | \--- androidx.navigation:navigation-common:2.8.0-rc01 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.1 (*) -| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.0-rc01 (c) -| | | +--- androidx.navigation:navigation-runtime:2.8.0-rc01 (c) -| | | +--- androidx.navigation:navigation-common-ktx:2.8.0-rc01 (c) -| | | \--- androidx.navigation:navigation-common:2.8.0-rc01 (c) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) -| +--- androidx.datastore:datastore-core-okio:1.1.1 (*) -| \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) -+--- project :core:data +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) | +--- project :core:common +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (*) +| | +--- io.coil-kt.coil3:coil:3.0.0-alpha10 +| | | \--- io.coil-kt.coil3:coil-android:3.0.0-alpha10 +| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 +| | | | \--- io.coil-kt.coil3:coil-core-android:3.0.0-alpha10 +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 -> 2.8.6 (*) +| | | | +--- androidx.annotation:annotation:1.8.1 (*) +| | | | +--- androidx.appcompat:appcompat-resources:1.7.0 (*) +| | | | +--- androidx.core:core-ktx:1.13.1 (*) +| | | | +--- androidx.exifinterface:exifinterface:1.3.7 +| | | | | \--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 -> 1.9.0 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | | \--- com.squareup.okio:okio:3.9.0 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | +--- io.coil-kt.coil3:coil-svg:3.0.0-alpha10 +| | | \--- io.coil-kt.coil3:coil-svg-android:3.0.0-alpha10 +| | | +--- androidx.core:core-ktx:1.13.1 (*) +| | | +--- com.caverock:androidsvg-aar:1.4 +| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | +--- io.coil-kt.coil3:coil-network-ktor3:3.0.0-alpha10 +| | | \--- io.coil-kt.coil3:coil-network-ktor3-android:3.0.0-alpha10 +| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | +--- io.coil-kt.coil3:coil-network-core:3.0.0-alpha10 +| | | | \--- io.coil-kt.coil3:coil-network-core-android:3.0.0-alpha10 +| | | | +--- androidx.core:core-ktx:1.13.1 (*) +| | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | +--- io.ktor:ktor-client-core:3.0.0-beta-2 +| | | | \--- io.ktor:ktor-client-core-jvm:3.0.0-beta-2 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.13 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-http:3.0.0-beta-2 +| | | | | \--- io.ktor:ktor-http-jvm:3.0.0-beta-2 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:2.0.13 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | +--- io.ktor:ktor-utils:3.0.0-beta-2 +| | | | | | \--- io.ktor:ktor-utils-jvm:3.0.0-beta-2 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.13 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-io:3.0.0-beta-2 +| | | | | | | \--- io.ktor:ktor-io-jvm:3.0.0-beta-2 +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | | | +--- org.slf4j:slf4j-api:2.0.13 +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-io-core:0.5.1 +| | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.5.1 +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-io-bytestring:0.5.1 +| | | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.5.1 +| | | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- io.ktor:ktor-events:3.0.0-beta-2 +| | | | | \--- io.ktor:ktor-events-jvm:3.0.0-beta-2 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:2.0.13 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) +| | | | | +--- io.ktor:ktor-utils:3.0.0-beta-2 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- io.ktor:ktor-websocket-serialization:3.0.0-beta-2 +| | | | | \--- io.ktor:ktor-websocket-serialization-jvm:3.0.0-beta-2 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:2.0.13 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) +| | | | | +--- io.ktor:ktor-serialization:3.0.0-beta-2 +| | | | | | \--- io.ktor:ktor-serialization-jvm:3.0.0-beta-2 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.13 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) +| | | | | | +--- io.ktor:ktor-websockets:3.0.0-beta-2 +| | | | | | | \--- io.ktor:ktor-websockets-jvm:3.0.0-beta-2 +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | | | +--- org.slf4j:slf4j-api:2.0.13 +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- io.ktor:ktor-sse:3.0.0-beta-2 +| | | | | \--- io.ktor:ktor-sse-jvm:3.0.0-beta-2 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:2.0.13 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.8.0 -> 1.9.0 +| | | | +--- org.slf4j:slf4j-api:1.7.32 -> 2.0.13 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 -| | | +--- androidx.tracing:tracing:1.3.0-alpha02 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.tracing:tracing:1.3.0-alpha02 (c) -| | \--- com.google.dagger:hilt-android:2.52 (*) -| +--- project :core:model -| | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (c) +| | | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (c) +| | | +--- io.insert-koin:koin-android:4.0.0-RC2 (c) +| | | +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (c) +| | | +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (c) +| | | \--- io.insert-koin:koin-compose:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 +| | | \--- io.insert-koin:koin-annotations-jvm:1.4.0-RC4 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| +--- project :core:datastore | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | +--- com.squareup.retrofit2:converter-gson:2.11.0 -| | | +--- com.squareup.retrofit2:retrofit:2.11.0 -| | | | \--- com.squareup.okhttp3:okhttp:3.14.9 -> 4.12.0 (*) -| | | \--- com.google.code.gson:gson:2.10.1 -| | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1 (*) -| | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | +--- com.russhwolf:multiplatform-settings-no-arg:1.2.0 +| | | \--- com.russhwolf:multiplatform-settings-no-arg-android:1.2.0 +| | | +--- androidx.startup:startup-runtime:1.1.1 (*) +| | | +--- com.russhwolf:multiplatform-settings:1.2.0 +| | | | \--- com.russhwolf:multiplatform-settings-android:1.2.0 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | +--- com.russhwolf:multiplatform-settings-serialization:1.2.0 +| | | \--- com.russhwolf:multiplatform-settings-serialization-android:1.2.0 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | +--- com.russhwolf:multiplatform-settings:1.2.0 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 +| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 (c) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (c) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 (c) +| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (c) +| | +--- com.russhwolf:multiplatform-settings-coroutines:1.2.0 +| | | \--- com.russhwolf:multiplatform-settings-coroutines-android:1.2.0 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | +--- com.russhwolf:multiplatform-settings:1.2.0 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | +--- project :core:model +| | | +--- com.squareup.retrofit2:converter-gson:2.11.0 +| | | | +--- com.squareup.retrofit2:retrofit:2.11.0 +| | | | | \--- com.squareup.okhttp3:okhttp:3.14.9 -> 4.12.0 (*) +| | | | \--- com.google.code.gson:gson:2.10.1 +| | | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 +| | | | \--- org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.0 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 +| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (c) +| | | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | \--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.20 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- project :core:common (*) +| | \--- project :core:datastore-proto +| | +--- com.google.protobuf:protobuf-kotlin-lite:4.26.0 +| | | +--- com.google.protobuf:protobuf-javalite:4.26.0 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.0 -> 2.0.20 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) | +--- project :core:network +| | +--- io.ktor:ktor-client-android:2.3.4 +| | | \--- io.ktor:ktor-client-android-jvm:2.3.4 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) | | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 (*) | | +--- project :core:common (*) | | +--- project :core:model (*) -| | +--- project :core:datastore -| | | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 (*) -| | | +--- androidx.datastore:datastore:1.1.1 (*) -| | | +--- project :core:datastore-proto -| | | | +--- com.google.protobuf:protobuf-kotlin-lite:4.26.0 -| | | | | +--- com.google.protobuf:protobuf-javalite:4.26.0 -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.0 -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | | \--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | | +--- project :core:common (*) -| | | +--- project :core:model (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | | +--- com.google.dagger:hilt-android:2.52 (*) -| | | \--- com.squareup.retrofit2:converter-gson:2.11.0 (*) -| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | +--- com.google.dagger:hilt-android:2.52 (*) -| | +--- com.squareup.okhttp3:okhttp:4.12.0 (*) -| | +--- com.squareup.okhttp3:logging-interceptor:4.12.0 -| | | +--- com.squareup.okhttp3:okhttp:4.12.0 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 1.9.20 (*) -| | +--- com.squareup.retrofit2:retrofit:2.11.0 (*) -| | +--- com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0 -| | | +--- com.squareup.retrofit2:retrofit:2.9.0 -> 2.11.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.0 -> 1.7.1 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.10 -> 1.9.20 (*) -| | +--- com.squareup.retrofit2:adapter-rxjava:2.11.0 -| | | +--- com.squareup.retrofit2:retrofit:2.11.0 (*) -| | | \--- io.reactivex:rxjava:1.3.8 -| | +--- com.squareup.retrofit2:converter-gson:2.11.0 (*) -| | +--- io.reactivex:rxandroid:1.1.0 -| | | \--- io.reactivex:rxjava:1.1.0 -> 1.3.8 -| | +--- io.reactivex:rxjava:1.3.8 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.0 -> 2.0.20 (*) -| | +--- io.ktor:ktor-client-core:2.3.4 -| | | \--- io.ktor:ktor-client-core-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 (*) -| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | +--- io.ktor:ktor-http:2.3.4 -| | | | \--- io.ktor:ktor-http-jvm:2.3.4 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | | +--- io.ktor:ktor-utils:2.3.4 -| | | | | \--- io.ktor:ktor-utils-jvm:2.3.4 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | | | +--- org.slf4j:slf4j-api:1.7.36 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | | | +--- io.ktor:ktor-io:2.3.4 -| | | | | | \--- io.ktor:ktor-io-jvm:2.3.4 -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | | | | +--- org.slf4j:slf4j-api:1.7.36 -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | +--- io.ktor:ktor-events:2.3.4 -| | | | \--- io.ktor:ktor-events-jvm:2.3.4 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | | +--- io.ktor:ktor-http:2.3.4 (*) -| | | | +--- io.ktor:ktor-utils:2.3.4 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | +--- io.ktor:ktor-websocket-serialization:2.3.4 -| | | | \--- io.ktor:ktor-websocket-serialization-jvm:2.3.4 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | | +--- io.ktor:ktor-http:2.3.4 (*) -| | | | +--- io.ktor:ktor-serialization:2.3.4 -| | | | | \--- io.ktor:ktor-serialization-jvm:2.3.4 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | | | +--- org.slf4j:slf4j-api:1.7.36 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | | | +--- io.ktor:ktor-http:2.3.4 (*) -| | | | | +--- io.ktor:ktor-websockets:2.3.4 -| | | | | | \--- io.ktor:ktor-websockets-jvm:2.3.4 -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | | | | +--- org.slf4j:slf4j-api:1.7.36 -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | | | | +--- io.ktor:ktor-http:2.3.4 (*) -| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.7.2 -> 1.8.1 -| | | +--- org.slf4j:slf4j-api:1.7.32 -> 1.7.36 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| | +--- io.ktor:ktor-client-android:2.3.4 -| | | \--- io.ktor:ktor-client-android-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -| | | +--- io.ktor:ktor-client-core:2.3.4 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | +--- io.ktor:ktor-client-serialization:2.3.4 -| | | \--- io.ktor:ktor-client-serialization-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | +--- io.ktor:ktor-client-core:2.3.4 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1 -> 1.7.1 (*) -| | | +--- io.ktor:ktor-client-json:2.3.4 -| | | | \--- io.ktor:ktor-client-json-jvm:2.3.4 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | | +--- io.ktor:ktor-client-core:2.3.4 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (*) +| | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) +| | +--- io.ktor:ktor-client-json:2.3.4 +| | | \--- io.ktor:ktor-client-json-jvm:2.3.4 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | \--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) | | +--- io.ktor:ktor-client-logging:2.3.4 | | | \--- io.ktor:ktor-client-logging-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | +--- io.ktor:ktor-client-core:2.3.4 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | \--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) +| | +--- io.ktor:ktor-client-serialization:2.3.4 +| | | \--- io.ktor:ktor-client-serialization-jvm:2.3.4 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1 -> 1.7.2 (*) +| | | \--- io.ktor:ktor-client-json:2.3.4 (*) | | +--- io.ktor:ktor-client-content-negotiation:2.3.4 | | | \--- io.ktor:ktor-client-content-negotiation-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | +--- io.ktor:ktor-client-core:2.3.4 (*) -| | | +--- io.ktor:ktor-serialization:2.3.4 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | +--- io.ktor:ktor-client-json:2.3.4 (*) -| | +--- io.ktor:ktor-client-websockets:2.3.4 -| | | \--- io.ktor:ktor-client-websockets-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | +--- io.ktor:ktor-client-core:2.3.4 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) +| | | \--- io.ktor:ktor-serialization:2.3.4 -> 3.0.0-beta-2 (*) | | +--- io.ktor:ktor-serialization-kotlinx-json:2.3.4 | | | \--- io.ktor:ktor-serialization-kotlinx-json-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | +--- io.ktor:ktor-http:2.3.4 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | +--- io.ktor:ktor-http:2.3.4 -> 3.0.0-beta-2 (*) | | | +--- io.ktor:ktor-serialization-kotlinx:2.3.4 | | | | \--- io.ktor:ktor-serialization-kotlinx-jvm:2.3.4 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 1.9.20 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 1.9.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.8.1 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.8.1 (*) -| | | | +--- io.ktor:ktor-http:2.3.4 (*) -| | | | +--- io.ktor:ktor-serialization:2.3.4 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1 -> 1.7.1 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1 -> 1.7.1 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | \--- ch.qos.logback:logback-classic:1.2.3 -| | +--- ch.qos.logback:logback-core:1.2.3 -| | \--- org.slf4j:slf4j-api:1.7.25 -> 1.7.36 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-http:2.3.4 -> 3.0.0-beta-2 (*) +| | | | +--- io.ktor:ktor-serialization:2.3.4 -> 3.0.0-beta-2 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1 -> 1.7.2 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1 -> 1.7.2 (*) +| | +--- de.jensklingenberg.ktorfit:ktorfit-lib:2.1.0 +| | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-android:2.1.0 +| | | +--- io.ktor:ktor-client-cio-jvm:2.3.12 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:2.3.12 -> 3.0.0-beta-2 (*) +| | | | +--- io.ktor:ktor-http-cio:2.3.12 +| | | | | \--- io.ktor:ktor-http-cio-jvm:2.3.12 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | | | +--- io.ktor:ktor-network:2.3.12 +| | | | | | \--- io.ktor:ktor-network-jvm:2.3.12 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | | | | \--- io.ktor:ktor-utils:2.3.12 -> 3.0.0-beta-2 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | | | \--- io.ktor:ktor-http:2.3.12 -> 3.0.0-beta-2 (*) +| | | | +--- io.ktor:ktor-websockets:2.3.12 -> 3.0.0-beta-2 (*) +| | | | \--- io.ktor:ktor-network-tls:2.3.12 +| | | | \--- io.ktor:ktor-network-tls-jvm:2.3.12 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-http:2.3.12 -> 3.0.0-beta-2 (*) +| | | | +--- io.ktor:ktor-network:2.3.12 (*) +| | | | \--- io.ktor:ktor-utils:2.3.12 -> 3.0.0-beta-2 (*) +| | | +--- de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 +| | | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light-android:2.1.0 +| | | | +--- de.jensklingenberg.ktorfit:ktorfit-annotations:2.1.0 +| | | | | \--- de.jensklingenberg.ktorfit:ktorfit-annotations-android:2.1.0 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- io.ktor:ktor-client-core:2.3.12 -> 3.0.0-beta-2 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | +--- de.jensklingenberg.ktorfit:ktorfit-converters-call:2.1.0 +| | | \--- de.jensklingenberg.ktorfit:ktorfit-converters-call-android:2.1.0 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 (*) +| | \--- de.jensklingenberg.ktorfit:ktorfit-converters-flow:2.1.0 +| | \--- de.jensklingenberg.ktorfit:ktorfit-converters-flow-android:2.1.0 +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 (*) +| +--- project :core:model (*) | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) -| +--- com.squareup.retrofit2:retrofit:2.11.0 (*) -| +--- com.squareup.retrofit2:adapter-rxjava:2.11.0 (*) -| +--- com.squareup.retrofit2:converter-gson:2.11.0 (*) -| +--- com.squareup.okhttp3:okhttp:4.12.0 (*) -| +--- com.squareup.okhttp3:logging-interceptor:4.12.0 (*) -| +--- io.reactivex:rxandroid:1.1.0 (*) -| +--- io.reactivex:rxjava:1.3.8 +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| +--- project :core:analytics +| | +--- com.google.firebase:firebase-bom:33.3.0 (*) +| | +--- com.google.firebase:firebase-analytics-ktx -> 22.1.0 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | \--- org.jetbrains.compose.runtime:runtime:1.6.11 +| | \--- androidx.compose.runtime:runtime:1.6.7 -> 1.7.2 (*) | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) +--- project :core:ui -| +--- project :core:designsystem -| | +--- androidx.compose.ui:ui:1.6.8 -> 1.7.0-rc01 (*) -| | +--- androidx.compose.foundation:foundation -> 1.7.0-rc01 (*) -| | +--- androidx.compose.foundation:foundation-layout -> 1.7.0-rc01 (*) -| | +--- androidx.compose.material:material-icons-extended -> 1.6.8 -| | | \--- androidx.compose.material:material-icons-extended-android:1.6.8 -| | | +--- androidx.compose.material:material-icons-core:1.6.8 (*) -| | | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.material:material-icons-core:1.6.8 (c) -| | | \--- androidx.compose.material:material-ripple:1.6.8 (c) -| | +--- androidx.compose.material3:material3 -> 1.2.1 (*) -| | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (*) -| | +--- androidx.compose.ui:ui-util:1.6.8 -> 1.7.0-rc01 (*) -| | +--- androidx.activity:activity-compose:1.9.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | +--- androidx.compose:compose-bom:2024.08.00 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| | \--- project :core:model (*) -| +--- project :core:model (*) -| +--- project :core:common (*) | +--- androidx.metrics:metrics-performance:1.0.0-beta01 -| | +--- androidx.collection:collection:1.1.0 -> 1.4.2 (*) +| | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) | | +--- androidx.core:core:1.5.0 -> 1.13.1 (*) | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- project :core:analytics -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | +--- androidx.compose:compose-bom:2024.08.00 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| | +--- com.google.dagger:hilt-android:2.52 (*) -| | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (*) -| | +--- com.google.firebase:firebase-bom:33.1.2 (*) -| | \--- com.google.firebase:firebase-analytics-ktx -> 22.0.2 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (*) -| +--- com.google.accompanist:accompanist-pager:0.34.0 -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.8.1 (*) -| | +--- androidx.compose.foundation:foundation:1.6.0 -> 1.7.0-rc01 (*) -| | +--- dev.chrisbanes.snapper:snapper:0.2.2 -> 0.3.0 -| | | +--- androidx.compose.foundation:foundation:1.2.1 -> 1.7.0-rc01 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21 -> 1.9.20 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) | +--- androidx.browser:browser:1.8.0 | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | +--- androidx.collection:collection:1.1.0 -> 1.4.2 (*) +| | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) | | +--- androidx.interpolator:interpolator:1.0.0 (*) | | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| +--- io.coil-kt:coil:2.6.0 -| | +--- io.coil-kt:coil-base:2.6.0 -| | | +--- androidx.annotation:annotation:1.7.1 -> 1.8.1 (*) -| | | +--- androidx.appcompat:appcompat-resources:1.6.1 -> 1.7.0 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | | +--- androidx.core:core-ktx:1.12.0 -> 1.13.1 (*) -| | | +--- androidx.exifinterface:exifinterface:1.3.7 -| | | | \--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | +--- androidx.profileinstaller:profileinstaller:1.3.1 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.7.0 -> 2.8.4 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.8.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) -| | | +--- com.squareup.okhttp3:okhttp:4.12.0 (*) -| | | \--- com.squareup.okio:okio:3.8.0 -> 3.9.0 (*) +| +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| +--- com.google.accompanist:accompanist-pager:0.34.0 +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.9.0 (*) +| | +--- androidx.compose.foundation:foundation:1.6.0 -> 1.7.2 +| | | \--- androidx.compose.foundation:foundation-android:1.7.2 +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | +--- androidx.compose.animation:animation:1.7.2 +| | | | \--- androidx.compose.animation:animation-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.animation:animation-core:1.7.2 +| | | | | \--- androidx.compose.animation:animation-core-android:1.7.2 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui:1.7.2 +| | | | | | \--- androidx.compose.ui:ui-android:1.7.2 +| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.9.2 (*) +| | | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | | +--- androidx.autofill:autofill:1.0.0 +| | | | | | | \--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 +| | | | | | | \--- androidx.compose.runtime:runtime-saveable-android:1.7.2 +| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | | \--- androidx.compose.runtime:runtime:1.7.2 (c) +| | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 +| | | | | | | \--- androidx.compose.ui:ui-geometry-android:1.7.2 +| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 +| | | | | | | | \--- androidx.compose.ui:ui-util-android:1.7.2 +| | | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | | | | | \--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 +| | | | | | | \--- androidx.compose.ui:ui-graphics-android:1.7.2 +| | | | | | | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 +| | | | | | | | \--- androidx.compose.ui:ui-unit-android:1.7.2 +| | | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | | | | +--- androidx.collection:collection-ktx:1.2.0 -> 1.4.4 (*) +| | | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) +| | | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) +| | | | | | | +--- androidx.graphics:graphics-path:1.0.1 +| | | | | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) +| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | | | | +--- androidx.compose.ui:ui-text:1.7.2 +| | | | | | | \--- androidx.compose.ui:ui-text-android:1.7.2 +| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 (*) +| | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) +| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) +| | | | | | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) +| | | | | | +--- androidx.customview:customview-poolingcontainer:1.0.0 +| | | | | | | +--- androidx.core:core-ktx:1.5.0 -> 1.13.1 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) +| | | | | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.3 -> 2.8.6 +| | | | | | | \--- androidx.lifecycle:lifecycle-runtime-compose-android:2.8.6 +| | | | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.compose.runtime:runtime:1.7.1 -> 1.7.2 (*) +| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) +| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (*) +| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | | | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | | | | \--- androidx.compose.foundation:foundation:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | | | +--- androidx.compose.animation:animation:1.7.2 (c) +| | | | | \--- androidx.compose.animation:animation-graphics:1.7.2 (c) +| | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 +| | | | | \--- androidx.compose.foundation:foundation-layout-android:1.7.2 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | +--- androidx.compose.animation:animation-core:1.2.1 -> 1.7.2 (*) +| | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | \--- androidx.compose.foundation:foundation:1.7.2 (c) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- androidx.compose.animation:animation-core:1.7.2 (c) +| | | | \--- androidx.compose.animation:animation-graphics:1.7.2 (c) +| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) +| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | +--- androidx.compose.ui:ui-text:1.7.2 (*) +| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | +--- androidx.core:core:1.13.1 (*) +| | | +--- androidx.emoji2:emoji2:1.3.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | \--- androidx.compose.foundation:foundation-layout:1.7.2 (c) +| | +--- dev.chrisbanes.snapper:snapper:0.2.2 -> 0.3.0 +| | | +--- androidx.compose.foundation:foundation:1.2.1 -> 1.7.2 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21 -> 2.0.0 (*) | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) -| \--- io.coil-kt:coil-compose:2.6.0 -| +--- io.coil-kt:coil-compose-base:2.6.0 -| | +--- androidx.core:core-ktx:1.12.0 -> 1.13.1 (*) -| | +--- com.google.accompanist:accompanist-drawablepainter:0.32.0 -| | | +--- androidx.compose.ui:ui:1.5.0 -> 1.7.0-rc01 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.8.1 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0 -> 1.9.20 (*) -| | +--- io.coil-kt:coil-base:2.6.0 (*) -| | +--- androidx.compose.foundation:foundation:1.6.1 -> 1.7.0-rc01 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) -| +--- io.coil-kt:coil:2.6.0 (*) -| \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| +--- project :core:analytics (*) +| +--- project :core:designsystem +| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| | +--- androidx.activity:activity-compose:1.9.2 +| | | +--- androidx.activity:activity-ktx:1.9.2 (*) +| | | +--- androidx.compose.runtime:runtime:1.0.1 -> 1.7.2 (*) +| | | +--- androidx.compose.runtime:runtime-saveable:1.0.1 -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui:1.0.1 -> 1.7.2 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.activity:activity:1.9.2 (c) +| | | \--- androidx.activity:activity-ktx:1.9.2 (c) +| | +--- project :core:model (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | +--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 +| | | \--- io.coil-kt.coil3:coil-compose-core-android:3.0.0-alpha10 +| | | +--- com.google.accompanist:accompanist-drawablepainter:0.34.0 +| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.9.0 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | +--- org.jetbrains.compose.foundation:foundation:1.6.11 +| | | | \--- androidx.compose.foundation:foundation:1.6.7 -> 1.7.2 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) +| | +--- org.jetbrains.compose.foundation:foundation:1.6.11 (*) +| | +--- org.jetbrains.compose.material:material:1.6.11 +| | | \--- androidx.compose.material:material:1.6.7 -> 1.7.2 +| | | \--- androidx.compose.material:material-android:1.7.2 +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | +--- androidx.compose.animation:animation:1.7.2 (*) +| | | +--- androidx.compose.animation:animation-core:1.7.2 (*) +| | | +--- androidx.compose.foundation:foundation:1.7.2 (*) +| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) +| | | +--- androidx.compose.material:material-ripple:1.7.2 +| | | | \--- androidx.compose.material:material-ripple-android:1.7.2 +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.animation:animation:1.7.2 (*) +| | | | +--- androidx.compose.foundation:foundation:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | +--- androidx.compose.ui:ui-text:1.7.2 (*) +| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- org.jetbrains.compose.material3:material3:1.6.11 +| | | \--- androidx.compose.material3:material3:1.2.1 -> 1.3.0 +| | | \--- androidx.compose.material3:material3-android:1.3.0 +| | | +--- androidx.activity:activity-compose:1.8.2 -> 1.9.2 (*) +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | +--- androidx.compose.animation:animation-core:1.6.0 -> 1.7.2 (*) +| | | +--- androidx.compose.foundation:foundation:1.7.0 -> 1.7.2 (*) +| | | +--- androidx.compose.foundation:foundation-layout:1.7.0 -> 1.7.2 (*) +| | | +--- androidx.compose.material:material-icons-core:1.6.0 -> 1.7.2 +| | | | \--- androidx.compose.material:material-icons-core-android:1.7.2 +| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.compose.material:material-ripple:1.7.0 -> 1.7.2 (*) +| | | +--- androidx.compose.runtime:runtime:1.7.0 -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui-text:1.6.0 -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.2 (*) +| | | +--- androidx.lifecycle:lifecycle-common-java8:2.6.1 -> 2.8.6 (*) +| | | \--- androidx.compose.material3:material3-window-size-class:1.3.0 (c) +| | +--- org.jetbrains.compose.material:material-icons-extended:1.6.11 +| | | \--- androidx.compose.material:material-icons-extended:1.6.7 -> 1.7.2 +| | | \--- androidx.compose.material:material-icons-extended-android:1.7.2 +| | | \--- androidx.compose.material:material-icons-core:1.7.2 (*) +| | +--- org.jetbrains.compose.ui:ui:1.6.11 +| | | \--- androidx.compose.ui:ui:1.6.7 -> 1.7.2 (*) +| | +--- org.jetbrains.compose.ui:ui-util:1.6.11 +| | | \--- androidx.compose.ui:ui-util:1.6.7 -> 1.7.2 (*) +| | +--- org.jetbrains.compose.components:components-resources:1.6.11 +| | | \--- org.jetbrains.compose.components:components-resources-android:1.6.11 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) +| | | +--- org.jetbrains.compose.foundation:foundation:1.6.11 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | \--- org.jetbrains.compose.components:components-ui-tooling-preview:1.6.11 +| | \--- org.jetbrains.compose.components:components-ui-tooling-preview-android:1.6.11 +| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| +--- project :core:model (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| +--- io.coil-kt.coil3:coil:3.0.0-alpha10 (*) +| +--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) +| +--- org.jetbrains.compose.material3:material3:1.6.11 (*) +| +--- org.jetbrains.compose.components:components-resources:1.6.11 (*) +| \--- org.jetbrains.compose.components:components-ui-tooling-preview:1.6.11 (*) +--- project :core:designsystem (*) +--- project :feature:receipt | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | +--- androidx.compose:compose-bom:2024.08.00 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| | +--- androidx.navigation:navigation-compose:2.8.0-rc01 (*) -| | +--- androidx.compose.material3:material3 -> 1.2.1 (*) -| | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (*) -| | \--- androidx.compose.ui:ui-util:1.6.8 -> 1.7.0-rc01 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 -| | \--- org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.7 +| | +--- androidx.compose:compose-bom:2024.09.02 (*) +| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| | +--- androidx.navigation:navigation-compose:2.8.1 +| | | +--- androidx.activity:activity-compose:1.8.0 -> 1.9.2 (*) +| | | +--- androidx.compose.animation:animation:1.7.2 (*) +| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) +| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 (*) +| | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2 -> 2.8.6 +| | | | \--- androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.6 +| | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | | | +--- androidx.compose.runtime:runtime:1.6.0 -> 1.7.2 (*) +| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 +| | | | | +--- androidx.navigation:navigation-common:2.8.1 +| | | | | | +--- androidx.annotation:annotation:1.8.1 (*) +| | | | | | +--- androidx.collection:collection-ktx:1.4.2 -> 1.4.4 (*) +| | | | | | +--- androidx.core:core-ktx:1.1.0 -> 1.13.1 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) +| | | | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) +| | | | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) +| | | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) +| | | | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) +| | | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) +| | | | | +--- androidx.navigation:navigation-common:2.8.1 (c) +| | | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) +| | | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) +| | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) +| | | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) +| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.1 +| | | | | +--- androidx.activity:activity-ktx:1.7.1 -> 1.9.2 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.4.2 -> 1.4.4 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.6 (*) +| | | | | +--- androidx.navigation:navigation-common:2.8.1 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | | | +--- androidx.navigation:navigation-common:2.8.1 (c) +| | | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) +| | | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) +| | | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) +| | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) +| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) +| | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) +| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) +| | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) +| | | | \--- androidx.navigation:navigation-common:2.8.1 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) +| | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) +| | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) +| | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) +| | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) +| | | \--- androidx.navigation:navigation-common:2.8.1 (c) +| | +--- androidx.compose.material3:material3 -> 1.3.0 (*) +| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| | \--- androidx.compose.ui:ui-util -> 1.7.2 (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 +| | \--- org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.8 | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 -| | +--- androidx.compose.runtime:runtime:1.0.1 -> 1.7.0-rc01 (*) -| | +--- androidx.compose.ui:ui:1.0.1 -> 1.7.0-rc01 (*) -| | +--- androidx.hilt:hilt-navigation:1.2.0 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.navigation:navigation-runtime:2.5.1 -> 2.8.0-rc01 (*) -| | | +--- com.google.dagger:hilt-android:2.49 -> 2.52 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1 -> 2.8.4 (*) -| | +--- androidx.navigation:navigation-compose:2.5.1 -> 2.8.0-rc01 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| +--- com.squareup.okhttp3:okhttp:4.12.0 (*) -| \--- project :core:data (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-compose:4.0.0-RC2 +| | | \--- io.insert-koin:koin-compose-jvm:4.0.0-RC2 +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.2 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 -> 2.8.6 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | +--- androidx.navigation:navigation-fragment-ktx:2.7.7 -> 2.8.1 +| | | +--- androidx.navigation:navigation-fragment:2.8.1 +| | | | +--- androidx.fragment:fragment-ktx:1.6.2 -> 1.8.2 (*) +| | | | +--- androidx.navigation:navigation-runtime:2.8.1 (*) +| | | | +--- androidx.slidingpanelayout:slidingpanelayout:1.2.0 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.customview:customview:1.1.0 (*) +| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | | +--- androidx.window:window:1.0.0 -> 1.3.0 +| | | | | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| | | | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | | | +--- androidx.core:core:1.8.0 -> 1.13.1 (*) +| | | | | | +--- androidx.window.extensions.core:core:1.0.0 +| | | | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.20 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | | | | \--- androidx.window:window-core:1.3.0 (c) +| | | | | \--- androidx.transition:transition:1.4.1 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | | +--- androidx.navigation:navigation-common:2.8.1 (c) +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) +| | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) +| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) +| | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) +| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 (*) +| | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) +| | | +--- androidx.navigation:navigation-compose:2.8.1 (c) +| | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) +| | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) +| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) +| | | \--- androidx.navigation:navigation-common:2.8.1 (c) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| \--- com.squareup.okhttp3:okhttp:4.12.0 (*) +--- project :feature:profile | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) -| +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) | +--- project :core:data (*) +| +--- project :libs:material3-navigation (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | +--- project :libs:country-code-picker | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | +--- androidx.compose:compose-bom:2024.08.00 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| | +--- androidx.compose.foundation:foundation -> 1.7.0-rc01 (*) -| | +--- androidx.compose.foundation:foundation-layout -> 1.7.0-rc01 (*) -| | +--- androidx.compose.material:material-icons-extended -> 1.6.8 (*) -| | +--- androidx.compose.material3:material3 -> 1.2.1 (*) -| | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (*) -| | +--- androidx.compose.ui:ui-util:1.6.8 -> 1.7.0-rc01 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) +| | +--- androidx.compose:compose-bom:2024.09.02 (*) +| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| | +--- androidx.compose.foundation:foundation -> 1.7.2 (*) +| | +--- androidx.compose.foundation:foundation-layout -> 1.7.2 (*) +| | +--- androidx.compose.material:material-icons-extended -> 1.7.2 (*) +| | +--- androidx.compose.material3:material3 -> 1.3.0 (*) +| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| | +--- androidx.compose.ui:ui-util -> 1.7.2 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) | | \--- io.michaelrocks:libphonenumber-android:8.13.35 -| \--- io.coil-kt:coil-compose:2.6.0 (*) +| +--- com.squareup.okhttp3:okhttp:4.12.0 (*) +| \--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) +--- project :feature:auth | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) -| +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) | +--- project :core:data (*) +| +--- project :libs:material3-navigation (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | +--- project :libs:country-code-picker (*) | +--- androidx.credentials:credentials:1.2.2 -> 1.3.0-beta01 | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) | | \--- androidx.credentials:credentials-play-services-auth:1.3.0-beta01 (c) | +--- androidx.credentials:credentials-play-services-auth:1.2.2 -> 1.3.0-beta01 | | +--- androidx.credentials:credentials:1.3.0-beta01 (*) | | +--- com.google.android.gms:play-services-auth:21.1.1 -> 21.2.0 -| | | +--- androidx.fragment:fragment:1.5.7 -> 1.7.1 (*) +| | | +--- androidx.fragment:fragment:1.5.7 -> 1.8.2 (*) | | | +--- androidx.loader:loader:1.1.0 (*) | | | +--- com.google.android.gms:play-services-auth-api-phone:18.0.2 | | | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) | | | | +--- com.google.android.gms:play-services-basement:18.0.2 -> 18.4.0 (*) | | | | \--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) | | | +--- com.google.android.gms:play-services-auth-base:18.0.10 -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.2 (*) +| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) | | | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) | | | | +--- com.google.android.gms:play-services-basement:18.2.0 -> 18.4.0 (*) | | | | \--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) @@ -1567,155 +1676,213 @@ | | | | +--- com.google.android.gms:play-services-base:18.3.0 (*) | | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) | | | | +--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0 -> 1.9.20 (*) -| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.8.1 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0 -> 2.0.0 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) | | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) | | +--- com.google.android.gms:play-services-fido:21.0.0 (*) | | +--- com.google.android.libraries.identity.googleid:googleid:1.1.0 -> 1.1.1 | | | +--- androidx.credentials:credentials:1.3.0-beta01 (*) | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.0 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 1.9.20 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.0.0 (*) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) | | \--- androidx.credentials:credentials:1.3.0-beta01 (c) | +--- com.google.android.libraries.identity.googleid:googleid:1.1.1 (*) | \--- com.google.android.gms:play-services-auth:21.2.0 (*) +--- project :feature:make-transfer | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| \--- project :core:data (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +--- project :feature:faq | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +--- project :feature:editpassword | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| \--- project :core:data (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +--- project :feature:notification | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) -| +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) | +--- project :core:data (*) +| +--- project :libs:material3-navigation (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | \--- project :libs:pullrefresh | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| +--- androidx.compose.animation:animation -> 1.7.0-rc01 (*) -| +--- androidx.compose.material3:material3 -> 1.2.1 (*) -| +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (*) -| \--- androidx.compose.ui:ui-util:1.6.8 -> 1.7.0-rc01 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| +--- androidx.compose.animation:animation -> 1.7.2 (*) +| +--- androidx.compose.material3:material3 -> 1.3.0 (*) +| +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| \--- androidx.compose.ui:ui-util -> 1.7.2 (*) +--- project :feature:request-money | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) -| +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) | +--- project :core:data (*) +| +--- project :libs:material3-navigation (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | +--- com.google.zxing:core:3.5.3 -| \--- io.coil-kt:coil-compose:2.6.0 (*) +| \--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) +--- project :feature:upi-setup | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| \--- project :core:data (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +--- project :feature:settings | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| \--- project :core:data (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +--- project :feature:savedcards | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| \--- project :core:data (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +--- project :feature:qr | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | +--- com.google.zxing:core:3.5.3 -| +--- project :core:data (*) | +--- androidx.camera:camera-view:1.3.4 | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) | | +--- androidx.annotation:annotation-experimental:1.3.1 -> 1.4.1 (*) @@ -1726,8 +1893,8 @@ | | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) | | | +--- androidx.exifinterface:exifinterface:1.3.2 -> 1.3.7 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.1.0 -> 2.8.4 (*) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.1.0 -> 2.8.4 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.1.0 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.1.0 -> 2.8.6 (*) | | | +--- com.google.auto.value:auto-value-annotations:1.6.3 | | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) @@ -1738,7 +1905,7 @@ | | | +--- androidx.camera:camera-core:1.3.4 (*) | | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.1.0 -> 2.8.4 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.1.0 -> 2.8.6 (*) | | | +--- com.google.auto.value:auto-value-annotations:1.6.3 | | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava | | | +--- androidx.camera:camera-core:1.3.4 (c) @@ -1755,7 +1922,7 @@ | | | \--- androidx.camera:camera-view:1.3.4 (c) | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) | | +--- androidx.core:core:1.3.2 -> 1.13.1 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.8.4 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.8.6 (*) | | +--- com.google.auto.value:auto-value-annotations:1.6.3 | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava | | +--- androidx.camera:camera-core:1.3.4 (c) @@ -1765,175 +1932,232 @@ | \--- com.google.guava:guava:27.0.1-android -> 31.1-android (*) +--- project :feature:invoices | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| \--- project :core:data (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +--- project :feature:merchants | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) -| +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) | +--- project :core:data (*) +| +--- project :libs:material3-navigation (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | \--- project :libs:pullrefresh (*) +--- project :feature:history | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| \--- project :core:data (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| \--- project :libs:pullrefresh (*) +--- project :feature:kyc | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) -| +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) | +--- project :core:data (*) +| +--- project :libs:material3-navigation (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | +--- project :libs:country-code-picker (*) | +--- project :libs:pullrefresh (*) | +--- com.maxkeppeler.sheets-compose-dialogs:core:1.3.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.10 -> 1.9.20 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.10 -> 2.0.0 (*) | | +--- androidx.core:core-ktx:1.9.0 -> 1.13.1 (*) -| | +--- androidx.compose:compose-bom:2024.02.00 -> 2024.08.00 (*) -| | +--- androidx.compose.ui:ui -> 1.7.0-rc01 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| | +--- androidx.compose.animation:animation -> 1.7.0-rc01 (*) -| | +--- androidx.compose.animation:animation-graphics -> 1.7.0-rc01 -| | | \--- androidx.compose.animation:animation-graphics-android:1.7.0-rc01 +| | +--- androidx.compose:compose-bom:2024.02.00 -> 2024.09.02 (*) +| | +--- androidx.compose.ui:ui -> 1.7.2 (*) +| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| | +--- androidx.compose.animation:animation -> 1.7.2 (*) +| | +--- androidx.compose.animation:animation-graphics -> 1.7.2 +| | | \--- androidx.compose.animation:animation-graphics-android:1.7.2 | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.2 (*) -| | | +--- androidx.compose.animation:animation:1.7.0-rc01 (*) -| | | +--- androidx.compose.foundation:foundation-layout:1.6.0 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui-geometry:1.6.0 -> 1.7.0-rc01 (*) -| | | +--- androidx.compose.ui:ui-util:1.7.0-rc01 (*) +| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | +--- androidx.compose.animation:animation:1.7.2 (*) +| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) +| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) +| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) | | | +--- androidx.core:core-ktx:1.5.0 -> 1.13.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.compose.animation:animation:1.7.0-rc01 (c) -| | | \--- androidx.compose.animation:animation-core:1.7.0-rc01 (c) -| | +--- androidx.compose.runtime:runtime -> 1.7.0-rc01 (*) -| | \--- androidx.compose.material3:material3 -> 1.2.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.compose.animation:animation:1.7.2 (c) +| | | \--- androidx.compose.animation:animation-core:1.7.2 (c) +| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| | \--- androidx.compose.material3:material3 -> 1.3.0 (*) | +--- com.maxkeppeler.sheets-compose-dialogs:calendar:1.3.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.10 -> 1.9.20 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.10 -> 2.0.0 (*) | | +--- androidx.core:core-ktx:1.9.0 -> 1.13.1 (*) -| | +--- androidx.compose:compose-bom:2024.02.00 -> 2024.08.00 (*) -| | +--- androidx.compose.ui:ui -> 1.7.0-rc01 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| | +--- androidx.compose.animation:animation -> 1.7.0-rc01 (*) -| | +--- androidx.compose.animation:animation-graphics -> 1.7.0-rc01 (*) -| | +--- androidx.compose.runtime:runtime -> 1.7.0-rc01 (*) -| | +--- androidx.compose.material3:material3 -> 1.2.1 (*) +| | +--- androidx.compose:compose-bom:2024.02.00 -> 2024.09.02 (*) +| | +--- androidx.compose.ui:ui -> 1.7.2 (*) +| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| | +--- androidx.compose.animation:animation -> 1.7.2 (*) +| | +--- androidx.compose.animation:animation-graphics -> 1.7.2 (*) +| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| | +--- androidx.compose.material3:material3 -> 1.3.0 (*) | | +--- dev.chrisbanes.snapper:snapper:0.3.0 (*) | | \--- com.maxkeppeler.sheets-compose-dialogs:core:1.3.0 (*) | \--- com.squareup.okhttp3:okhttp:4.12.0 (*) +--- project :feature:home | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| \--- project :core:data (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +--- project :feature:accounts | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) -| +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) | +--- project :core:data (*) -| \--- project :libs:pullrefresh (*) +| +--- project :libs:material3-navigation (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| +--- project :libs:pullrefresh (*) +| \--- com.google.android.gms:play-services-auth:21.2.0 (*) +--- project :feature:finance | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | \--- com.google.accompanist:accompanist-pager:0.34.0 (*) +--- project :feature:payments | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) -| +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) | +--- project :core:data (*) +| +--- project :libs:material3-navigation (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | \--- com.google.accompanist:accompanist-pager:0.34.0 (*) +--- project :feature:send-money | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) -| +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) | +--- project :core:data (*) +| +--- project :libs:material3-navigation (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | +--- project :libs:country-code-picker (*) | \--- com.google.android.gms:play-services-code-scanner:16.1.0 -| +--- androidx.activity:activity:1.3.1 -> 1.9.1 (*) +| +--- androidx.activity:activity:1.3.1 -> 1.9.2 (*) | +--- com.google.android.datatransport:transport-api:2.2.1 -> 3.2.0 (*) | +--- com.google.android.datatransport:transport-backend-cct:2.3.3 -> 3.3.0 (*) | +--- com.google.android.datatransport:transport-runtime:2.2.6 -> 3.3.0 (*) @@ -1971,148 +2195,158 @@ | \--- com.google.mlkit:common:18.9.0 (*) +--- project :feature:standing-instruction | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) -| +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) | +--- project :core:data (*) +| +--- project :libs:material3-navigation (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | \--- com.google.android.gms:play-services-code-scanner:16.1.0 (*) +--- project :feature:search | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) | +--- project :core:ui (*) | +--- project :core:designsystem (*) +| +--- project :core:data (*) | +--- project :libs:material3-navigation (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 (*) -| +--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| \--- project :core:data (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +--- project :libs:mifos-passcode | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- androidx.compose:compose-bom:2024.08.00 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.0-rc01 (*) -| +--- com.google.dagger:hilt-android:2.52 (*) +| +--- androidx.compose:compose-bom:2024.09.02 (*) +| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) | +--- androidx.core:core-ktx:1.13.1 (*) -| +--- androidx.compose.foundation:foundation -> 1.7.0-rc01 (*) -| +--- androidx.compose.foundation:foundation-layout -> 1.7.0-rc01 (*) -| +--- androidx.compose.material:material-icons-extended -> 1.6.8 (*) -| +--- androidx.compose.material3:material3 -> 1.2.1 (*) -| +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (*) -| +--- androidx.compose.ui:ui-util:1.6.8 -> 1.7.0-rc01 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -| +--- androidx.navigation:navigation-compose:2.8.0-rc01 (*) -| \--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) +| +--- androidx.compose.foundation:foundation -> 1.7.2 (*) +| +--- androidx.compose.foundation:foundation-layout -> 1.7.2 (*) +| +--- androidx.compose.material:material-icons-extended -> 1.7.2 (*) +| +--- androidx.compose.material3:material3 -> 1.3.0 (*) +| +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-util -> 1.7.2 (*) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| +--- androidx.navigation:navigation-compose:2.8.1 (*) +| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| \--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +--- project :libs:material3-navigation (*) +--- androidx.core:core-ktx:1.13.1 (*) +--- androidx.appcompat:appcompat:1.7.0 (*) -+--- androidx.activity:activity-compose:1.9.1 (*) -+--- androidx.activity:activity-ktx:1.9.1 (*) ++--- androidx.activity:activity-compose:1.9.2 (*) ++--- androidx.activity:activity-ktx:1.9.2 (*) +--- androidx.core:core-splashscreen:1.0.1 | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) -+--- androidx.compose.material3.adaptive:adaptive:1.0.0-rc01 -| \--- androidx.compose.material3.adaptive:adaptive-android:1.0.0-rc01 ++--- androidx.compose.material3.adaptive:adaptive:1.0.0 +| \--- androidx.compose.material3.adaptive:adaptive-android:1.0.0 | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.0-rc01 (*) -| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.0-rc01 (*) -| +--- androidx.window:window:1.3.0-rc01 -| | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| | +--- androidx.collection:collection:1.1.0 -> 1.4.2 (*) -| | +--- androidx.core:core:1.8.0 -> 1.13.1 (*) -| | +--- androidx.window.extensions.core:core:1.0.0 -| | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.20 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.8.1 (*) -| | \--- androidx.window:window-core:1.3.0-rc01 (c) -| +--- androidx.window:window-core:1.3.0-rc01 -| | \--- androidx.window:window-core-android:1.3.0-rc01 +| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.2 (*) +| +--- androidx.window:window:1.3.0 (*) +| +--- androidx.window:window-core:1.3.0 +| | \--- androidx.window:window-core-android:1.3.0 | | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | \--- androidx.window:window:1.3.0-rc01 (c) +| | \--- androidx.window:window:1.3.0 (c) | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0-rc01 (c) -| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-rc01 (c) -+--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0-rc01 -| \--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0-rc01 +| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) +| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) ++--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 +| \--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.animation:animation:1.7.0-rc01 (*) -| +--- androidx.compose.animation:animation-core:1.7.0-rc01 (*) -| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.0-rc01 (*) -| +--- androidx.compose.foundation:foundation-layout:1.6.5 -> 1.7.0-rc01 (*) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0-rc01 (*) -| +--- androidx.compose.ui:ui:1.7.0-rc01 (*) -| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.0-rc01 (*) -| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.0-rc01 (*) -| +--- androidx.window:window-core:1.3.0-rc01 (*) +| +--- androidx.compose.animation:animation:1.7.0 -> 1.7.2 (*) +| +--- androidx.compose.animation:animation-core:1.7.0 -> 1.7.2 (*) +| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.foundation:foundation-layout:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (*) +| +--- androidx.compose.ui:ui:1.7.0 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.2 (*) +| +--- androidx.window:window-core:1.3.0 (*) | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0-rc01 (c) -| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-rc01 (c) -+--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-rc01 -| \--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0-rc01 -| +--- androidx.activity:activity-compose:1.8.2 -> 1.9.1 (*) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) +| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) ++--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 +| \--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 +| +--- androidx.activity:activity-compose:1.8.2 -> 1.9.2 (*) | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.0-rc01 (*) -| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0-rc01 (*) -| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.0-rc01 (*) +| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (*) +| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.2 (*) | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0-rc01 (c) -| \--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0-rc01 (c) -+--- androidx.compose.material3:material3-window-size-class -> 1.2.1 -| \--- androidx.compose.material3:material3-window-size-class-android:1.2.1 +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) +| \--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) ++--- androidx.compose.material3:material3-window-size-class -> 1.3.0 +| \--- androidx.compose.material3:material3-window-size-class-android:1.3.0 | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.runtime:runtime:1.6.0 -> 1.7.0-rc01 (*) -| +--- androidx.compose.ui:ui:1.6.0 -> 1.7.0-rc01 (*) -| +--- androidx.compose.ui:ui-unit:1.6.0 -> 1.7.0-rc01 (*) -| +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.0-rc01 (*) -| +--- androidx.window:window:1.0.0 -> 1.3.0-rc01 (*) +| +--- androidx.compose.runtime:runtime:1.7.0 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-unit:1.6.0 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.2 (*) +| +--- androidx.window:window:1.0.0 -> 1.3.0 (*) | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| \--- androidx.compose.material3:material3:1.2.1 (c) +| \--- androidx.compose.material3:material3:1.3.0 (c) +--- androidx.compose.runtime:runtime-tracing:1.0.0-beta01 | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| +--- androidx.compose.runtime:runtime:1.3.3 -> 1.7.0-rc01 (*) +| +--- androidx.compose.runtime:runtime:1.3.3 -> 1.7.2 (*) | +--- androidx.startup:startup-runtime:1.1.1 (*) | +--- androidx.tracing:tracing-perfetto:1.0.0 | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) | | +--- androidx.startup:startup-runtime:1.1.1 (*) | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -+--- androidx.hilt:hilt-navigation-compose:1.2.0 (*) -+--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 (*) -+--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 (*) -+--- androidx.lifecycle:lifecycle-runtime-compose:2.8.4 (*) -+--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 (*) -+--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 (*) ++--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) ++--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (*) ++--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) ++--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) ++--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (*) +--- androidx.lifecycle:lifecycle-extensions:2.2.0 -| +--- androidx.lifecycle:lifecycle-runtime:2.2.0 -> 2.8.4 (*) +| +--- androidx.lifecycle:lifecycle-runtime:2.2.0 -> 2.8.6 (*) | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) | +--- androidx.arch.core:core-runtime:2.1.0 -> 2.2.0 (*) -| +--- androidx.fragment:fragment:1.2.0 -> 1.7.1 (*) -| +--- androidx.lifecycle:lifecycle-common:2.2.0 -> 2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-livedata:2.2.0 -> 2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-process:2.2.0 -> 2.8.4 (*) -| +--- androidx.lifecycle:lifecycle-service:2.2.0 -> 2.8.4 (*) -| \--- androidx.lifecycle:lifecycle-viewmodel:2.2.0 -> 2.8.4 (*) -+--- androidx.navigation:navigation-compose:2.8.0-rc01 (*) -+--- androidx.profileinstaller:profileinstaller:1.3.1 (*) +| +--- androidx.fragment:fragment:1.2.0 -> 1.8.2 (*) +| +--- androidx.lifecycle:lifecycle-common:2.2.0 -> 2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-livedata:2.2.0 -> 2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-process:2.2.0 -> 2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-service:2.2.0 -> 2.8.6 (*) +| \--- androidx.lifecycle:lifecycle-viewmodel:2.2.0 -> 2.8.6 (*) ++--- androidx.navigation:navigation-compose:2.8.1 (*) ++--- androidx.profileinstaller:profileinstaller:1.4.0 (*) +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -\--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.0-rc01 (*) ++--- io.insert-koin:koin-android:4.0.0-RC2 (*) ++--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) +\--- androidx.compose.runtime:runtime -> 1.7.2 (*) diff --git a/mifospay/dependencies/prodReleaseRuntimeClasspath.txt b/mifospay/dependencies/prodReleaseRuntimeClasspath.txt index 6dc1ab157..d808c3e69 100644 --- a/mifospay/dependencies/prodReleaseRuntimeClasspath.txt +++ b/mifospay/dependencies/prodReleaseRuntimeClasspath.txt @@ -34,10 +34,9 @@ :libs:material3-navigation :libs:mifos-passcode :libs:pullrefresh -:shared -androidx.activity:activity-compose:1.9.1 -androidx.activity:activity-ktx:1.9.1 -androidx.activity:activity:1.9.1 +androidx.activity:activity-compose:1.9.2 +androidx.activity:activity-ktx:1.9.2 +androidx.activity:activity:1.9.2 androidx.annotation:annotation-experimental:1.4.1 androidx.annotation:annotation-jvm:1.8.1 androidx.annotation:annotation:1.8.1 @@ -51,55 +50,57 @@ androidx.camera:camera-core:1.3.4 androidx.camera:camera-lifecycle:1.3.4 androidx.camera:camera-video:1.3.4 androidx.camera:camera-view:1.3.4 -androidx.collection:collection-jvm:1.4.2 -androidx.collection:collection-ktx:1.4.2 -androidx.collection:collection:1.4.2 -androidx.compose.animation:animation-android:1.7.0-rc01 -androidx.compose.animation:animation-core-android:1.7.0-rc01 -androidx.compose.animation:animation-core:1.7.0-rc01 -androidx.compose.animation:animation-graphics-android:1.7.0-rc01 -androidx.compose.animation:animation-graphics:1.7.0-rc01 -androidx.compose.animation:animation:1.7.0-rc01 -androidx.compose.foundation:foundation-android:1.7.0-rc01 -androidx.compose.foundation:foundation-layout-android:1.7.0-rc01 -androidx.compose.foundation:foundation-layout:1.7.0-rc01 -androidx.compose.foundation:foundation:1.7.0-rc01 -androidx.compose.material3.adaptive:adaptive-android:1.0.0-rc01 -androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0-rc01 -androidx.compose.material3.adaptive:adaptive-layout:1.0.0-rc01 -androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0-rc01 -androidx.compose.material3.adaptive:adaptive-navigation:1.0.0-rc01 -androidx.compose.material3.adaptive:adaptive:1.0.0-rc01 -androidx.compose.material3:material3-android:1.2.1 -androidx.compose.material3:material3-window-size-class-android:1.2.1 -androidx.compose.material3:material3-window-size-class:1.2.1 -androidx.compose.material3:material3:1.2.1 -androidx.compose.material:material-icons-core-android:1.6.8 -androidx.compose.material:material-icons-core:1.6.8 -androidx.compose.material:material-icons-extended-android:1.6.8 -androidx.compose.material:material-icons-extended:1.6.8 -androidx.compose.material:material-ripple-android:1.6.8 -androidx.compose.material:material-ripple:1.6.8 -androidx.compose.runtime:runtime-android:1.7.0-rc01 -androidx.compose.runtime:runtime-saveable-android:1.7.0-rc01 -androidx.compose.runtime:runtime-saveable:1.7.0-rc01 +androidx.collection:collection-jvm:1.4.4 +androidx.collection:collection-ktx:1.4.4 +androidx.collection:collection:1.4.4 +androidx.compose.animation:animation-android:1.7.2 +androidx.compose.animation:animation-core-android:1.7.2 +androidx.compose.animation:animation-core:1.7.2 +androidx.compose.animation:animation-graphics-android:1.7.2 +androidx.compose.animation:animation-graphics:1.7.2 +androidx.compose.animation:animation:1.7.2 +androidx.compose.foundation:foundation-android:1.7.2 +androidx.compose.foundation:foundation-layout-android:1.7.2 +androidx.compose.foundation:foundation-layout:1.7.2 +androidx.compose.foundation:foundation:1.7.2 +androidx.compose.material3.adaptive:adaptive-android:1.0.0 +androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 +androidx.compose.material3.adaptive:adaptive-layout:1.0.0 +androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 +androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 +androidx.compose.material3.adaptive:adaptive:1.0.0 +androidx.compose.material3:material3-android:1.3.0 +androidx.compose.material3:material3-window-size-class-android:1.3.0 +androidx.compose.material3:material3-window-size-class:1.3.0 +androidx.compose.material3:material3:1.3.0 +androidx.compose.material:material-android:1.7.2 +androidx.compose.material:material-icons-core-android:1.7.2 +androidx.compose.material:material-icons-core:1.7.2 +androidx.compose.material:material-icons-extended-android:1.7.2 +androidx.compose.material:material-icons-extended:1.7.2 +androidx.compose.material:material-ripple-android:1.7.2 +androidx.compose.material:material-ripple:1.7.2 +androidx.compose.material:material:1.7.2 +androidx.compose.runtime:runtime-android:1.7.2 +androidx.compose.runtime:runtime-saveable-android:1.7.2 +androidx.compose.runtime:runtime-saveable:1.7.2 androidx.compose.runtime:runtime-tracing:1.0.0-beta01 -androidx.compose.runtime:runtime:1.7.0-rc01 -androidx.compose.ui:ui-android:1.7.0-rc01 -androidx.compose.ui:ui-geometry-android:1.7.0-rc01 -androidx.compose.ui:ui-geometry:1.7.0-rc01 -androidx.compose.ui:ui-graphics-android:1.7.0-rc01 -androidx.compose.ui:ui-graphics:1.7.0-rc01 -androidx.compose.ui:ui-text-android:1.7.0-rc01 -androidx.compose.ui:ui-text:1.7.0-rc01 -androidx.compose.ui:ui-tooling-preview-android:1.7.0-rc01 -androidx.compose.ui:ui-tooling-preview:1.7.0-rc01 -androidx.compose.ui:ui-unit-android:1.7.0-rc01 -androidx.compose.ui:ui-unit:1.7.0-rc01 -androidx.compose.ui:ui-util-android:1.7.0-rc01 -androidx.compose.ui:ui-util:1.7.0-rc01 -androidx.compose.ui:ui:1.7.0-rc01 -androidx.compose:compose-bom:2024.08.00 +androidx.compose.runtime:runtime:1.7.2 +androidx.compose.ui:ui-android:1.7.2 +androidx.compose.ui:ui-geometry-android:1.7.2 +androidx.compose.ui:ui-geometry:1.7.2 +androidx.compose.ui:ui-graphics-android:1.7.2 +androidx.compose.ui:ui-graphics:1.7.2 +androidx.compose.ui:ui-text-android:1.7.2 +androidx.compose.ui:ui-text:1.7.2 +androidx.compose.ui:ui-tooling-preview-android:1.7.2 +androidx.compose.ui:ui-tooling-preview:1.7.2 +androidx.compose.ui:ui-unit-android:1.7.2 +androidx.compose.ui:ui-unit:1.7.2 +androidx.compose.ui:ui-util-android:1.7.2 +androidx.compose.ui:ui-util:1.7.2 +androidx.compose.ui:ui:1.7.2 +androidx.compose:compose-bom:2024.09.02 androidx.concurrent:concurrent-futures:1.1.0 androidx.core:core-ktx:1.13.1 androidx.core:core-splashscreen:1.0.1 @@ -108,91 +109,86 @@ androidx.credentials:credentials-play-services-auth:1.3.0-beta01 androidx.credentials:credentials:1.3.0-beta01 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 -androidx.customview:customview:1.0.0 +androidx.customview:customview:1.1.0 androidx.databinding:databinding-adapters:8.5.2 androidx.databinding:databinding-common:8.5.2 androidx.databinding:databinding-ktx:8.5.2 androidx.databinding:databinding-runtime:8.5.2 androidx.databinding:viewbinding:8.5.2 -androidx.datastore:datastore-android:1.1.1 -androidx.datastore:datastore-core-android:1.1.1 -androidx.datastore:datastore-core-okio-jvm:1.1.1 -androidx.datastore:datastore-core-okio:1.1.1 -androidx.datastore:datastore-core:1.1.1 -androidx.datastore:datastore-preferences-android:1.1.1 -androidx.datastore:datastore-preferences-core-jvm:1.1.1 -androidx.datastore:datastore-preferences-core:1.1.1 -androidx.datastore:datastore-preferences:1.1.1 -androidx.datastore:datastore:1.1.1 +androidx.datastore:datastore-core:1.0.0 +androidx.datastore:datastore-preferences-core:1.0.0 +androidx.datastore:datastore-preferences:1.0.0 +androidx.datastore:datastore:1.0.0 androidx.documentfile:documentfile:1.0.0 androidx.drawerlayout:drawerlayout:1.0.0 androidx.emoji2:emoji2-views-helper:1.3.0 androidx.emoji2:emoji2:1.3.0 androidx.exifinterface:exifinterface:1.3.7 -androidx.fragment:fragment-ktx:1.7.1 -androidx.fragment:fragment:1.7.1 +androidx.fragment:fragment-ktx:1.8.2 +androidx.fragment:fragment:1.8.2 androidx.graphics:graphics-path:1.0.1 -androidx.hilt:hilt-navigation-compose:1.2.0 -androidx.hilt:hilt-navigation:1.2.0 androidx.interpolator:interpolator:1.0.0 androidx.legacy:legacy-support-core-utils:1.0.0 -androidx.lifecycle:lifecycle-common-java8:2.8.4 -androidx.lifecycle:lifecycle-common-jvm:2.8.4 -androidx.lifecycle:lifecycle-common:2.8.4 +androidx.lifecycle:lifecycle-common-java8:2.8.6 +androidx.lifecycle:lifecycle-common-jvm:2.8.6 +androidx.lifecycle:lifecycle-common:2.8.6 androidx.lifecycle:lifecycle-extensions:2.2.0 -androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.4 -androidx.lifecycle:lifecycle-livedata-core:2.8.4 -androidx.lifecycle:lifecycle-livedata:2.8.4 -androidx.lifecycle:lifecycle-process:2.8.4 -androidx.lifecycle:lifecycle-runtime-android:2.8.4 -androidx.lifecycle:lifecycle-runtime-compose-android:2.8.4 -androidx.lifecycle:lifecycle-runtime-compose:2.8.4 -androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.4 -androidx.lifecycle:lifecycle-runtime-ktx:2.8.4 -androidx.lifecycle:lifecycle-runtime:2.8.4 -androidx.lifecycle:lifecycle-service:2.8.4 -androidx.lifecycle:lifecycle-viewmodel-android:2.8.4 -androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.4 -androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 -androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 -androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 -androidx.lifecycle:lifecycle-viewmodel:2.8.4 +androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 +androidx.lifecycle:lifecycle-livedata-core:2.8.6 +androidx.lifecycle:lifecycle-livedata:2.8.6 +androidx.lifecycle:lifecycle-process:2.8.6 +androidx.lifecycle:lifecycle-runtime-android:2.8.6 +androidx.lifecycle:lifecycle-runtime-compose-android:2.8.6 +androidx.lifecycle:lifecycle-runtime-compose:2.8.6 +androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.6 +androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 +androidx.lifecycle:lifecycle-runtime:2.8.6 +androidx.lifecycle:lifecycle-service:2.8.6 +androidx.lifecycle:lifecycle-viewmodel-android:2.8.6 +androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.6 +androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 +androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 +androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 +androidx.lifecycle:lifecycle-viewmodel:2.8.6 androidx.loader:loader:1.1.0 androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 androidx.metrics:metrics-performance:1.0.0-beta01 -androidx.navigation:navigation-common-ktx:2.8.0-rc01 -androidx.navigation:navigation-common:2.8.0-rc01 -androidx.navigation:navigation-compose:2.8.0-rc01 -androidx.navigation:navigation-runtime-ktx:2.8.0-rc01 -androidx.navigation:navigation-runtime:2.8.0-rc01 +androidx.navigation:navigation-common-ktx:2.8.1 +androidx.navigation:navigation-common:2.8.1 +androidx.navigation:navigation-compose:2.8.1 +androidx.navigation:navigation-fragment-ktx:2.8.1 +androidx.navigation:navigation-fragment:2.8.1 +androidx.navigation:navigation-runtime-ktx:2.8.1 +androidx.navigation:navigation-runtime:2.8.1 androidx.print:print:1.0.0 androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 -androidx.profileinstaller:profileinstaller:1.3.1 +androidx.profileinstaller:profileinstaller:1.4.0 androidx.resourceinspection:resourceinspection-annotation:1.0.1 androidx.savedstate:savedstate-ktx:1.2.1 androidx.savedstate:savedstate:1.2.1 +androidx.slidingpanelayout:slidingpanelayout:1.2.0 androidx.startup:startup-runtime:1.1.1 androidx.tracing:tracing-ktx:1.3.0-alpha02 androidx.tracing:tracing-perfetto:1.0.0 androidx.tracing:tracing:1.3.0-alpha02 +androidx.transition:transition:1.4.1 androidx.vectordrawable:vectordrawable-animated:1.1.0 androidx.vectordrawable:vectordrawable:1.1.0 androidx.versionedparcelable:versionedparcelable:1.1.1 androidx.viewpager:viewpager:1.0.0 androidx.window.extensions.core:core:1.0.0 -androidx.window:window-core-android:1.3.0-rc01 -androidx.window:window-core:1.3.0-rc01 -androidx.window:window:1.3.0-rc01 -ch.qos.logback:logback-classic:1.2.3 -ch.qos.logback:logback-core:1.2.3 -co.touchlab:stately-concurrency-jvm:2.0.6 -co.touchlab:stately-concurrency:2.0.6 -co.touchlab:stately-concurrent-collections-jvm:2.0.6 -co.touchlab:stately-concurrent-collections:2.0.6 -co.touchlab:stately-strict-jvm:2.0.6 -co.touchlab:stately-strict:2.0.6 -com.google.accompanist:accompanist-drawablepainter:0.32.0 +androidx.window:window-core-android:1.3.0 +androidx.window:window-core:1.3.0 +androidx.window:window:1.3.0 +co.touchlab:stately-concurrency-jvm:2.0.7 +co.touchlab:stately-concurrency:2.0.7 +co.touchlab:stately-concurrent-collections-jvm:2.0.7 +co.touchlab:stately-concurrent-collections:2.0.7 +co.touchlab:stately-strict-jvm:2.0.7 +co.touchlab:stately-strict:2.0.7 +com.caverock:androidsvg-aar:1.4 +com.google.accompanist:accompanist-drawablepainter:0.34.0 com.google.accompanist:accompanist-pager:0.34.0 com.google.android.datatransport:transport-api:3.2.0 com.google.android.datatransport:transport-backend-cct:3.3.0 @@ -206,12 +202,12 @@ com.google.android.gms:play-services-basement:18.4.0 com.google.android.gms:play-services-cloud-messaging:17.2.0 com.google.android.gms:play-services-code-scanner:16.1.0 com.google.android.gms:play-services-fido:21.0.0 -com.google.android.gms:play-services-measurement-api:22.0.2 -com.google.android.gms:play-services-measurement-base:22.0.2 -com.google.android.gms:play-services-measurement-impl:22.0.2 -com.google.android.gms:play-services-measurement-sdk-api:22.0.2 -com.google.android.gms:play-services-measurement-sdk:22.0.2 -com.google.android.gms:play-services-measurement:22.0.2 +com.google.android.gms:play-services-measurement-api:22.1.0 +com.google.android.gms:play-services-measurement-base:22.1.0 +com.google.android.gms:play-services-measurement-impl:22.1.0 +com.google.android.gms:play-services-measurement-sdk-api:22.1.0 +com.google.android.gms:play-services-measurement-sdk:22.1.0 +com.google.android.gms:play-services-measurement:22.1.0 com.google.android.gms:play-services-stats:17.0.2 com.google.android.gms:play-services-tasks:18.2.0 com.google.android.libraries.identity.googleid:googleid:1.1.1 @@ -219,23 +215,20 @@ com.google.android.odml:image:1.0.0-beta1 com.google.auto.value:auto-value-annotations:1.6.3 com.google.code.findbugs:jsr305:3.0.2 com.google.code.gson:gson:2.10.1 -com.google.dagger:dagger-lint-aar:2.52 -com.google.dagger:dagger:2.52 -com.google.dagger:hilt-android:2.52 -com.google.dagger:hilt-core:2.52 +com.google.dagger:dagger:2.27 com.google.errorprone:error_prone_annotations:2.26.0 com.google.firebase:firebase-abt:21.1.1 -com.google.firebase:firebase-analytics-ktx:22.0.2 -com.google.firebase:firebase-analytics:22.0.2 +com.google.firebase:firebase-analytics-ktx:22.1.0 +com.google.firebase:firebase-analytics:22.1.0 com.google.firebase:firebase-annotations:16.2.0 -com.google.firebase:firebase-bom:33.1.2 +com.google.firebase:firebase-bom:33.3.0 com.google.firebase:firebase-common-ktx:21.0.0 com.google.firebase:firebase-common:21.0.0 com.google.firebase:firebase-components:18.0.0 com.google.firebase:firebase-config-interop:16.0.1 com.google.firebase:firebase-config:22.0.0 -com.google.firebase:firebase-crashlytics-ktx:19.0.3 -com.google.firebase:firebase-crashlytics:19.0.3 +com.google.firebase:firebase-crashlytics-ktx:19.1.0 +com.google.firebase:firebase-crashlytics:19.1.0 com.google.firebase:firebase-datatransport:19.0.0 com.google.firebase:firebase-encoders-json:18.0.1 com.google.firebase:firebase-encoders-proto:16.0.0 @@ -244,11 +237,11 @@ com.google.firebase:firebase-iid-interop:17.1.0 com.google.firebase:firebase-installations-interop:17.2.0 com.google.firebase:firebase-installations:18.0.0 com.google.firebase:firebase-measurement-connector:20.0.1 -com.google.firebase:firebase-messaging-ktx:24.0.0 -com.google.firebase:firebase-messaging:24.0.0 +com.google.firebase:firebase-messaging-ktx:24.0.1 +com.google.firebase:firebase-messaging:24.0.1 com.google.firebase:firebase-perf-ktx:21.0.1 com.google.firebase:firebase-perf:21.0.1 -com.google.firebase:firebase-sessions:2.0.3 +com.google.firebase:firebase-sessions:2.0.4 com.google.firebase:protolite-well-known-types:18.0.0 com.google.guava:failureaccess:1.0.1 com.google.guava:guava:31.1-android @@ -260,101 +253,139 @@ com.google.mlkit:vision-common:17.0.0 com.google.protobuf:protobuf-javalite:4.26.0 com.google.protobuf:protobuf-kotlin-lite:4.26.0 com.google.zxing:core:3.5.3 -com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:1.0.0 com.maxkeppeler.sheets-compose-dialogs:calendar:1.3.0 com.maxkeppeler.sheets-compose-dialogs:core:1.3.0 -com.squareup.okhttp3:logging-interceptor:4.12.0 +com.russhwolf:multiplatform-settings-android:1.2.0 +com.russhwolf:multiplatform-settings-coroutines-android:1.2.0 +com.russhwolf:multiplatform-settings-coroutines:1.2.0 +com.russhwolf:multiplatform-settings-no-arg-android:1.2.0 +com.russhwolf:multiplatform-settings-no-arg:1.2.0 +com.russhwolf:multiplatform-settings-serialization-android:1.2.0 +com.russhwolf:multiplatform-settings-serialization:1.2.0 +com.russhwolf:multiplatform-settings:1.2.0 com.squareup.okhttp3:okhttp:4.12.0 com.squareup.okio:okio-jvm:3.9.0 com.squareup.okio:okio:3.9.0 -com.squareup.retrofit2:adapter-rxjava:2.11.0 com.squareup.retrofit2:converter-gson:2.11.0 com.squareup.retrofit2:retrofit:2.11.0 -com.squareup.wire:wire-runtime-jvm:5.0.0 -com.squareup.wire:wire-runtime:5.0.0 +de.jensklingenberg.ktorfit:ktorfit-annotations-android:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-annotations:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-converters-call-android:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-converters-call:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-converters-flow-android:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-converters-flow:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-lib-android:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-lib-light-android:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-lib:2.1.0 dev.chrisbanes.snapper:snapper:0.3.0 -io.coil-kt:coil-base:2.6.0 -io.coil-kt:coil-compose-base:2.6.0 -io.coil-kt:coil-compose:2.6.0 -io.coil-kt:coil:2.6.0 -io.insert-koin:koin-android:3.6.0-Beta4 -io.insert-koin:koin-androidx-compose:3.6.0-Beta4 -io.insert-koin:koin-compose-jvm:1.2.0-Beta4 -io.insert-koin:koin-compose-viewmodel-jvm:1.2.0-Beta4 -io.insert-koin:koin-compose-viewmodel:1.2.0-Beta4 -io.insert-koin:koin-compose:1.2.0-Beta4 -io.insert-koin:koin-core-jvm:3.6.0-Beta4 -io.insert-koin:koin-core:3.6.0-Beta4 +io.coil-kt.coil3:coil-android:3.0.0-alpha10 +io.coil-kt.coil3:coil-compose-core-android:3.0.0-alpha10 +io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 +io.coil-kt.coil3:coil-core-android:3.0.0-alpha10 +io.coil-kt.coil3:coil-core:3.0.0-alpha10 +io.coil-kt.coil3:coil-network-core-android:3.0.0-alpha10 +io.coil-kt.coil3:coil-network-core:3.0.0-alpha10 +io.coil-kt.coil3:coil-network-ktor3-android:3.0.0-alpha10 +io.coil-kt.coil3:coil-network-ktor3:3.0.0-alpha10 +io.coil-kt.coil3:coil-svg-android:3.0.0-alpha10 +io.coil-kt.coil3:coil-svg:3.0.0-alpha10 +io.coil-kt.coil3:coil:3.0.0-alpha10 +io.insert-koin:koin-android:4.0.0-RC2 +io.insert-koin:koin-androidx-compose:4.0.0-RC2 +io.insert-koin:koin-androidx-navigation:4.0.0-RC2 +io.insert-koin:koin-annotations-jvm:1.4.0-RC4 +io.insert-koin:koin-annotations:1.4.0-RC4 +io.insert-koin:koin-bom:4.0.0-RC2 +io.insert-koin:koin-compose-jvm:4.0.0-RC2 +io.insert-koin:koin-compose:4.0.0-RC2 +io.insert-koin:koin-core-jvm:4.0.0-RC2 +io.insert-koin:koin-core-viewmodel-jvm:4.0.0-RC2 +io.insert-koin:koin-core-viewmodel:4.0.0-RC2 +io.insert-koin:koin-core:4.0.0-RC2 io.ktor:ktor-client-android-jvm:2.3.4 io.ktor:ktor-client-android:2.3.4 +io.ktor:ktor-client-cio-jvm:2.3.12 io.ktor:ktor-client-content-negotiation-jvm:2.3.4 io.ktor:ktor-client-content-negotiation:2.3.4 -io.ktor:ktor-client-core-jvm:2.3.4 -io.ktor:ktor-client-core:2.3.4 +io.ktor:ktor-client-core-jvm:3.0.0-beta-2 +io.ktor:ktor-client-core:3.0.0-beta-2 io.ktor:ktor-client-json-jvm:2.3.4 io.ktor:ktor-client-json:2.3.4 io.ktor:ktor-client-logging-jvm:2.3.4 io.ktor:ktor-client-logging:2.3.4 io.ktor:ktor-client-serialization-jvm:2.3.4 io.ktor:ktor-client-serialization:2.3.4 -io.ktor:ktor-client-websockets-jvm:2.3.4 -io.ktor:ktor-client-websockets:2.3.4 -io.ktor:ktor-events-jvm:2.3.4 -io.ktor:ktor-events:2.3.4 -io.ktor:ktor-http-jvm:2.3.4 -io.ktor:ktor-http:2.3.4 -io.ktor:ktor-io-jvm:2.3.4 -io.ktor:ktor-io:2.3.4 -io.ktor:ktor-serialization-jvm:2.3.4 +io.ktor:ktor-events-jvm:3.0.0-beta-2 +io.ktor:ktor-events:3.0.0-beta-2 +io.ktor:ktor-http-cio-jvm:2.3.12 +io.ktor:ktor-http-cio:2.3.12 +io.ktor:ktor-http-jvm:3.0.0-beta-2 +io.ktor:ktor-http:3.0.0-beta-2 +io.ktor:ktor-io-jvm:3.0.0-beta-2 +io.ktor:ktor-io:3.0.0-beta-2 +io.ktor:ktor-network-jvm:2.3.12 +io.ktor:ktor-network-tls-jvm:2.3.12 +io.ktor:ktor-network-tls:2.3.12 +io.ktor:ktor-network:2.3.12 +io.ktor:ktor-serialization-jvm:3.0.0-beta-2 io.ktor:ktor-serialization-kotlinx-json-jvm:2.3.4 io.ktor:ktor-serialization-kotlinx-json:2.3.4 io.ktor:ktor-serialization-kotlinx-jvm:2.3.4 io.ktor:ktor-serialization-kotlinx:2.3.4 -io.ktor:ktor-serialization:2.3.4 -io.ktor:ktor-utils-jvm:2.3.4 -io.ktor:ktor-utils:2.3.4 -io.ktor:ktor-websocket-serialization-jvm:2.3.4 -io.ktor:ktor-websocket-serialization:2.3.4 -io.ktor:ktor-websockets-jvm:2.3.4 -io.ktor:ktor-websockets:2.3.4 +io.ktor:ktor-serialization:3.0.0-beta-2 +io.ktor:ktor-sse-jvm:3.0.0-beta-2 +io.ktor:ktor-sse:3.0.0-beta-2 +io.ktor:ktor-utils-jvm:3.0.0-beta-2 +io.ktor:ktor-utils:3.0.0-beta-2 +io.ktor:ktor-websocket-serialization-jvm:3.0.0-beta-2 +io.ktor:ktor-websocket-serialization:3.0.0-beta-2 +io.ktor:ktor-websockets-jvm:3.0.0-beta-2 +io.ktor:ktor-websockets:3.0.0-beta-2 io.michaelrocks:libphonenumber-android:8.13.35 -io.reactivex:rxandroid:1.1.0 -io.reactivex:rxjava:1.3.8 -jakarta.inject:jakarta.inject-api:2.0.1 javax.inject:javax.inject:1 org.checkerframework:checker-qual:3.12.0 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0-rc03 -org.jetbrains.androidx.navigation:navigation-compose:2.7.0-alpha06 +org.jetbrains.androidx.core:core-bundle-android:1.0.0 +org.jetbrains.androidx.core:core-bundle:1.0.0 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.0 +org.jetbrains.androidx.savedstate:savedstate:1.2.0 org.jetbrains.compose.components:components-resources-android:1.6.11 org.jetbrains.compose.components:components-resources:1.6.11 org.jetbrains.compose.components:components-ui-tooling-preview-android:1.6.11 org.jetbrains.compose.components:components-ui-tooling-preview:1.6.11 org.jetbrains.compose.foundation:foundation:1.6.11 org.jetbrains.compose.material3:material3:1.6.11 +org.jetbrains.compose.material:material-icons-extended:1.6.11 +org.jetbrains.compose.material:material:1.6.11 org.jetbrains.compose.runtime:runtime:1.6.11 -org.jetbrains.compose.ui:ui-tooling-preview:1.6.11 +org.jetbrains.compose.ui:ui-util:1.6.11 org.jetbrains.compose.ui:ui:1.6.11 org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.20 org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 org.jetbrains.kotlin:kotlin-stdlib-common:2.0.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 org.jetbrains.kotlin:kotlin-stdlib:2.0.20 -org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.7 -org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.7 -org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 -org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.1 -org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.1 -org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.8.1 -org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.8.1 +org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.8 +org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 +org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 +org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 +org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 +org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 +org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.9.0 +org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0 +org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.9.0 org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.0 org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 -org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.1 -org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.1 -org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.1 -org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.1 -org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1 +org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.5.1 +org.jetbrains.kotlinx:kotlinx-io-bytestring:0.5.1 +org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.5.1 +org.jetbrains.kotlinx:kotlinx-io-core:0.5.1 +org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 +org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 +org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 +org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 +org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 org.jetbrains:annotations:23.0.0 -org.slf4j:slf4j-api:1.7.36 +org.slf4j:slf4j-api:2.0.13 diff --git a/mifospay/prodRelease-badging.txt b/mifospay/prodRelease-badging.txt index 8cdf267e8..0b23830ab 100644 --- a/mifospay/prodRelease-badging.txt +++ b/mifospay/prodRelease-badging.txt @@ -1,4 +1,4 @@ -package: name='org.mifospay' versionCode='1' versionName='0.0.1-beta.0.833+20240905T230255Z' platformBuildVersionName='14' platformBuildVersionCode='34' compileSdkVersion='34' compileSdkVersionCodename='14' +package: name='org.mifospay' versionCode='1' versionName='0.0.2-beta.0.2' platformBuildVersionName='14' platformBuildVersionCode='34' compileSdkVersion='34' compileSdkVersionCodename='14' sdkVersion:'26' targetSdkVersion:'34' uses-permission: name='android.permission.INTERNET' diff --git a/mifospay/src/main/java/org/mifospay/MainActivity.kt b/mifospay/src/main/java/org/mifospay/MainActivity.kt index 8416a5d33..e17923bd8 100644 --- a/mifospay/src/main/java/org/mifospay/MainActivity.kt +++ b/mifospay/src/main/java/org/mifospay/MainActivity.kt @@ -10,10 +10,10 @@ package org.mifospay import android.os.Bundle +import android.view.Window import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge -import androidx.activity.viewModels import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass import androidx.compose.runtime.CompositionLocalProvider @@ -27,10 +27,12 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle import androidx.metrics.performance.JankStats import androidx.navigation.compose.rememberNavController -import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import org.koin.android.ext.android.inject +import org.koin.androidx.viewmodel.ext.android.viewModel +import org.koin.core.parameter.parametersOf import org.mifospay.MainActivityUiState.Loading import org.mifospay.MainActivityUiState.Success import org.mifospay.core.analytics.AnalyticsHelper @@ -43,28 +45,25 @@ import org.mifospay.navigation.MifosNavGraph.LOGIN_GRAPH import org.mifospay.navigation.MifosNavGraph.PASSCODE_GRAPH import org.mifospay.navigation.RootNavGraph import org.mifospay.ui.rememberMifosAppState -import javax.inject.Inject @OptIn(ExperimentalMaterial3WindowSizeClassApi::class) -@AndroidEntryPoint class MainActivity : ComponentActivity() { /** * Lazily inject [JankStats], which is used to track jank throughout the app. */ - @Inject - lateinit var lazyStats: dagger.Lazy - @Inject - lateinit var networkMonitor: NetworkMonitor + private val networkMonitor: NetworkMonitor by inject() - @Inject - lateinit var timeZoneMonitor: TimeZoneMonitor + private val timeZoneMonitor: TimeZoneMonitor by inject() - @Inject - lateinit var analyticsHelper: AnalyticsHelper + private val analyticsHelper: AnalyticsHelper by inject() - private val viewModel: MainActivityViewModel by viewModels() + private val viewModel: MainActivityViewModel by viewModel() + + private val myWindow: Window by inject { parametersOf(this) } + + private val lazyStats: JankStats by inject { parametersOf(myWindow) } override fun onCreate(savedInstanceState: Bundle?) { val splashScreen = installSplashScreen() @@ -136,11 +135,11 @@ class MainActivity : ComponentActivity() { override fun onResume() { super.onResume() - lazyStats.get().isTrackingEnabled = true + lazyStats.isTrackingEnabled = true } override fun onPause() { super.onPause() - lazyStats.get().isTrackingEnabled = false + lazyStats.isTrackingEnabled = false } } diff --git a/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt b/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt index 2a3677a51..35ddb856e 100644 --- a/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt +++ b/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt @@ -12,7 +12,6 @@ package org.mifospay import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.mifospay.core.model.UserData -import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map @@ -20,10 +19,8 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import org.mifos.library.passcode.data.PasscodeManager import org.mifospay.core.data.repository.auth.UserDataRepository -import javax.inject.Inject -@HiltViewModel -class MainActivityViewModel @Inject constructor( +class MainActivityViewModel( private val userDataRepository: UserDataRepository, private val passcodeManager: PasscodeManager, ) : ViewModel() { diff --git a/mifospay/src/main/java/org/mifospay/MifosPayApp.kt b/mifospay/src/main/java/org/mifospay/MifosPayApp.kt index 795035371..e7403cf44 100644 --- a/mifospay/src/main/java/org/mifospay/MifosPayApp.kt +++ b/mifospay/src/main/java/org/mifospay/MifosPayApp.kt @@ -10,11 +10,33 @@ package org.mifospay import android.app.Application -import dagger.hilt.android.HiltAndroidApp +import org.koin.android.ext.koin.androidContext +import org.koin.core.context.startKoin +import org.koin.core.logger.Level +import org.mifospay.di.KoinModules -@HiltAndroidApp class MifosPayApp : Application() { override fun onCreate() { super.onCreate() + val koinModules = KoinModules() + + startKoin { + printLogger(Level.ERROR) + androidContext(this@MifosPayApp) + modules( + listOf( + koinModules.dataModules, + koinModules.mifosPayModule, + koinModules + .coreDataStoreModules, + koinModules.featureModules, + koinModules.networkModules, + koinModules + .analyticsModules, + koinModules.commonModules, + koinModules.libsModule, + ), + ) + } } } diff --git a/mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt b/mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt index 3ffdca107..aa1210bf6 100644 --- a/mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt +++ b/mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt @@ -13,30 +13,24 @@ import android.app.Activity import android.util.Log import android.view.Window import androidx.metrics.performance.JankStats -import androidx.metrics.performance.JankStats.OnFrameListener -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ActivityComponent +import org.koin.core.module.dsl.viewModel +import org.koin.dsl.module +import org.mifospay.MainActivityViewModel -@Module -@InstallIn(ActivityComponent::class) -object JankStatsModule { - @Provides - fun providesOnFrameListener(): OnFrameListener = OnFrameListener { frameData -> - // Make sure to only log janky frames. - if (frameData.isJank) { - // We're currently logging this but would better report it to a backend. - Log.v("Mifos Jank", frameData.toString()) +val JankStatsModule = module { + + factory { (activity: Activity) -> activity.window } + factory { (window: Window) -> + JankStats.createAndTrack(window) { frameData -> + // Make sure to only log janky frames. + if (frameData.isJank) { + // We're currently logging this but would better report it to a backend. + Log.v("Mifos Jank", frameData.toString()) + } } } - @Provides - fun providesWindow(activity: Activity): Window = activity.window - - @Provides - fun providesJankStats( - window: Window, - frameListener: OnFrameListener, - ): JankStats = JankStats.createAndTrack(window, frameListener) + viewModel { + MainActivityViewModel(userDataRepository = get(), passcodeManager = get()) + } } diff --git a/mifospay/src/main/java/org/mifospay/di/KoinModules.kt b/mifospay/src/main/java/org/mifospay/di/KoinModules.kt new file mode 100644 index 000000000..c3ad261cb --- /dev/null +++ b/mifospay/src/main/java/org/mifospay/di/KoinModules.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.di + +import org.koin.dsl.module +import org.mifos.library.passcode.di.ApplicationModule +import org.mifospay.core.analytics.di.AnalyticsModule +import org.mifospay.core.data.di.DataModule +import org.mifospay.core.data.di.LocalDataModule +import org.mifospay.core.datastore.di.CoreDataStoreModule +import org.mifospay.core.network.di.CoroutineScopesModule +import org.mifospay.core.network.di.DispatchersModule +import org.mifospay.core.network.di.LocalModule +import org.mifospay.core.network.di.NetworkModule +import org.mifospay.feature.auth.di.AuthModule +import org.mifospay.feature.bank.accounts.di.AccountsModule +import org.mifospay.feature.di.HistoryModule +import org.mifospay.feature.editpassword.di.EditPasswordModule +import org.mifospay.feature.faq.di.FaqModule +import org.mifospay.feature.home.di.HomeModule +import org.mifospay.feature.invoices.di.InvoicesModule +import org.mifospay.feature.kyc.di.KYCModule +import org.mifospay.feature.make.transfer.di.MakeTransferModule +import org.mifospay.feature.merchants.di.MerchantsModule +import org.mifospay.feature.notification.di.NotificationModule +import org.mifospay.feature.payments.di.PaymentsModule +import org.mifospay.feature.profile.di.ProfileModule +import org.mifospay.feature.read.qr.di.QrModule +import org.mifospay.feature.receipt.di.ReceiptModule +import org.mifospay.feature.request.money.di.RequestMoneyModule +import org.mifospay.feature.savedcards.di.SavedCardsModule +import org.mifospay.feature.search.di.SearchModule +import org.mifospay.feature.send.money.di.SendMoneyModule +import org.mifospay.feature.settings.di.SettingsModule +import org.mifospay.feature.standing.instruction.di.StandingInstructionModule +import org.mifospay.feature.upiSetup.di.UpiSetupModule + +class KoinModules { + val analyticsModules = module { + includes(AnalyticsModule) + } + val commonModules = module { + includes(CoroutineScopesModule, DispatchersModule) + } + val dataModules = module { + includes(DataModule, LocalDataModule) + } + val coreDataStoreModules = module { + includes(CoreDataStoreModule) + } + val networkModules = module { + includes(LocalModule, NetworkModule) + } + val featureModules = module { + includes( + AuthModule, AccountsModule, EditPasswordModule, FaqModule, HistoryModule, HomeModule, + InvoicesModule, KYCModule, MakeTransferModule, MerchantsModule, NotificationModule, + PaymentsModule, ProfileModule, QrModule, ReceiptModule, RequestMoneyModule, + SavedCardsModule, SearchModule, SendMoneyModule, SettingsModule, + StandingInstructionModule, UpiSetupModule, + ) + } + val mifosPayModule = module { + includes(JankStatsModule) + } + val libsModule = module { + includes(ApplicationModule) + } +} diff --git a/mifospay/src/test/java/org/mifospay/ExampleUnitTest.kt b/mifospay/src/test/java/org/mifospay/ExampleUnitTest.kt deleted file mode 100644 index 96fcfe7f2..000000000 --- a/mifospay/src/test/java/org/mifospay/ExampleUnitTest.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay - -import org.junit.Assert -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see [Testing documentation](http://d.android.com/tools/testing) - */ -class ExampleUnitTest { - @Test - @Throws(Exception::class) - fun additionIsCorrect() { - Assert.assertEquals(4, (2 + 2).toLong()) - } -} diff --git a/mifospay/src/test/java/org/mifospay/KoinModulesCheck.kt b/mifospay/src/test/java/org/mifospay/KoinModulesCheck.kt new file mode 100644 index 000000000..f9c811a25 --- /dev/null +++ b/mifospay/src/test/java/org/mifospay/KoinModulesCheck.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay + +import android.content.Context +import androidx.lifecycle.SavedStateHandle +import io.ktor.client.HttpClientConfig +import io.ktor.client.engine.HttpClientEngine +import org.koin.test.AutoCloseKoinTest +import org.koin.test.verify.verify +import org.mifos.core.network.services.KtorAuthenticationService +import org.mifos.library.passcode.data.PasscodeManager +import org.mifospay.core.data.repository.auth.UserDataRepository +import org.mifospay.core.datastore.PreferencesHelper +import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.SelfServiceApiManager +import org.mifospay.di.KoinModules +import kotlin.test.Test + +class KoinModulesCheck : AutoCloseKoinTest() { + + @Test + fun checkKoinModules() { + val koinModules = KoinModules() + + koinModules.libsModule.verify( + extraTypes = listOf(Context::class), + ) + koinModules.commonModules.verify() + koinModules.analyticsModules.verify() + koinModules.networkModules.verify( + extraTypes = listOf( + HttpClientEngine::class, + HttpClientConfig::class, + ), + ) + koinModules.featureModules.verify( + extraTypes = listOf( + PreferencesHelper::class, + FineractApiManager::class, + SelfServiceApiManager::class, + KtorAuthenticationService::class, + SavedStateHandle::class, + ), + ) + koinModules.coreDataStoreModules.verify( + extraTypes = listOf( + PreferencesHelper::class, + Context::class, + ), + ) + koinModules.mifosPayModule.verify( + extraTypes = listOf( + UserDataRepository::class, + PasscodeManager::class, + Context::class, + ), + ) + koinModules.dataModules.verify( + extraTypes = listOf( + FineractApiManager::class, + SelfServiceApiManager::class, + KtorAuthenticationService::class, + PreferencesHelper::class, + Map::class, + ), + ) + } +} diff --git a/settings.gradle.kts b/settings.gradle.kts index f43a17c79..9cb771d36 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,7 +17,7 @@ dependencyResolutionManagement { } } -plugins { + plugins { id("org.gradle.toolchains.foojay-resolver-convention") version("0.8.0") id("org.ajoberstar.reckon.settings") version("0.18.3") } diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 5c99a7fef..fec478782 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -71,7 +71,6 @@ kotlin { api(libs.koin.core) implementation(libs.koin.compose) - implementation(libs.koin.compose.viewmodel) implementation(libs.datastore) } From a3b4fd3bc3b9a88ab882c7002c4e0f4a01b97aa4 Mon Sep 17 00:00:00 2001 From: Sk Niyaj Ali Date: Thu, 26 Sep 2024 20:32:43 +0530 Subject: [PATCH 02/31] Feat: [:core:model] - Migrated to KMM (#1770) --- core/model/build.gradle.kts | 3 - core/model/consumer-rules.pro | 0 core/model/proguard-rules.pro | 21 --- .../kotlin/org}/mifospay/core/model/City.kt | 2 +- .../org}/mifospay/core/model/Country.kt | 2 +- .../kotlin/org}/mifospay/core/model/State.kt | 2 +- .../org}/mifospay/core/model/UserData.kt | 2 +- .../mifospay/core/model/domain/Account.kt | 16 +- .../org}/mifospay/core/model/domain/Bank.kt | 4 +- .../core/model/domain/BankAccountDetails.kt | 19 ++- .../mifospay/core/model/domain/Currency.kt | 25 +++ .../mifospay/core/model/domain/NewAccount.kt | 17 +- .../core/model/domain/NotificationPayload.kt} | 14 +- .../core/model/domain/SearchResult.kt | 25 +++ .../mifospay/core/model/domain/Transaction.kt | 40 +++++ .../core/model/domain/TransactionType.kt | 2 +- .../core/model/domain/client/Client.kt | 23 ++- .../core/model/domain/client/NewClient.kt | 24 +-- .../domain/client/UpdateClientEntityMobile.kt | 2 +- .../model/domain/twofactor/AccessToken.kt | 19 +++ .../model/domain/twofactor/DeliveryMethod.kt | 13 +- .../core/model/domain/user/NewUser.kt | 8 +- .../domain/user/UpdateUserEntityClients.kt | 7 +- .../domain/user/UpdateUserEntityEmail.kt | 7 +- .../domain/user/UpdateUserEntityPassword.kt | 5 +- .../mifospay/core/model/domain/user/User.kt | 4 +- .../org/mifospay/core/model/entity/Invoice.kt | 38 +++++ .../org}/mifospay/core/model/entity/Page.kt | 9 +- .../org}/mifospay/core/model/entity/Role.kt | 8 +- .../core/model/entity/SearchedEntity.kt | 22 +++ .../mifospay/core/model/entity/TPTResponse.kt | 13 +- .../mifospay/core/model/entity/Timeline.kt | 43 +++++ .../mifospay/core/model/entity/UserEntity.kt | 5 +- .../core/model/entity/UserWithRole.kt | 14 +- .../accounts/SavingAccountsListResponse.kt | 6 +- .../model/entity/accounts/savings/Currency.kt | 33 ++++ .../accounts/savings/PaymentDetailData.kt | 33 ++++ .../entity/accounts/savings/PaymentType.kt | 11 +- .../entity/accounts/savings/SavingAccount.kt | 54 +++++++ .../savings/SavingsWithAssociations.kt | 67 ++++++++ .../model/entity/accounts/savings/Status.kt | 45 ++++++ .../model/entity/accounts/savings/Summary.kt | 25 +++ .../model/entity/accounts/savings/TimeLine.kt | 43 +++++ .../accounts/savings/TransactionType.kt | 33 ++++ .../entity/accounts/savings/Transactions.kt | 45 ++++++ .../model/entity/accounts/savings/Transfer.kt | 8 +- .../entity/accounts/savings/TransferDetail.kt | 30 ++++ .../authentication/AuthenticationPayload.kt | 18 +++ .../model/entity/beneficary/Beneficiary.kt | 24 +++ .../entity/beneficary/BeneficiaryPayload.kt | 31 ++++ .../beneficary/BeneficiaryUpdatePayload.kt | 12 +- .../core/model/entity/client/Client.kt | 62 ++++++++ .../model/entity/client/ClientAccounts.kt | 4 +- .../core/model/entity/client/Currency.kt | 31 ++++ .../core/model/entity/client/DepositType.kt | 25 ++- .../core/model/entity/client/Status.kt | 21 +++ .../mifospay/core/model/entity/client/Type.kt | 19 +++ .../core/model/entity/kyc/KYCLevel1Details.kt | 23 +++ .../core/model/entity/noncore/Document.kt | 24 +++ .../model/entity/payload/ClientPayload.kt | 33 ++++ .../model/entity/payload/DataTablePayload.kt | 27 ++++ .../core/model/entity/payload/PayPayload.kt | 9 +- .../core/model/entity/payload/PayResponse.kt | 6 +- .../payload/StandingInstructionPayload.kt | 33 ++-- .../model/entity/payload/TransferPayload.kt | 43 +++++ .../model/entity/payload/UpdateVpaPayload.kt | 7 +- .../model/entity/register/RegisterPayload.kt | 24 +++ .../core/model/entity/register/UserVerify.kt | 18 +++ .../core/model/entity/savedcards/Card.kt | 22 +++ .../entity/standinginstruction/SDIResponse.kt | 18 +++ .../StandingInstruction.kt | 31 ++++ .../entity/templates/account/AccountOption.kt | 23 +++ .../account/AccountOptionsTemplate.kt | 18 +++ .../entity/templates/account/AccountType.kt | 19 +++ .../beneficiary/AccountTypeOption.kt | 19 +++ .../beneficiary/BeneficiaryTemplate.kt | 17 ++ .../core/model/signup/PasswordStrength.kt | 2 +- .../mifospay/core/model/signup/SignupData.kt | 9 +- .../mifospay/core/model/utils/DateHelper.kt | 149 ++++++++++++++++++ core/model/src/main/AndroidManifest.xml | 13 -- .../core/model/domain/NotificationPayload.kt | 20 --- .../core/model/domain/SearchResult.kt | 22 --- .../mifospay/core/model/domain/Transaction.kt | 41 ----- .../model/domain/twofactor/AccessToken.kt | 20 --- .../com/mifospay/core/model/entity/Invoice.kt | 49 ------ .../core/model/entity/SearchedEntity.kt | 23 --- .../mifospay/core/model/entity/Timeline.kt | 30 ---- .../model/entity/accounts/savings/Currency.kt | 41 ----- .../accounts/savings/PaymentDetailData.kt | 39 ----- .../entity/accounts/savings/SavingAccount.kt | 69 -------- .../savings/SavingsWithAssociations.kt | 113 ------------- .../model/entity/accounts/savings/Status.kt | 72 --------- .../model/entity/accounts/savings/Summary.kt | 43 ----- .../model/entity/accounts/savings/TimeLine.kt | 67 -------- .../accounts/savings/TransactionType.kt | 69 -------- .../entity/accounts/savings/Transactions.kt | 72 --------- .../entity/accounts/savings/TransferDetail.kt | 39 ----- .../authentication/AuthenticationPayload.kt | 29 ---- .../model/entity/beneficary/Beneficiary.kt | 40 ----- .../entity/beneficary/BeneficiaryPayload.kt | 36 ----- .../core/model/entity/client/Client.kt | 101 ------------ .../core/model/entity/client/Currency.kt | 37 ----- .../core/model/entity/client/Status.kt | 27 ---- .../mifospay/core/model/entity/client/Type.kt | 26 --- .../core/model/entity/kyc/KYCLevel1Details.kt | 38 ----- .../core/model/entity/noncore/Document.kt | 25 --- .../model/entity/payload/ClientPayload.kt | 68 -------- .../model/entity/payload/DataTablePayload.kt | 29 ---- .../model/entity/payload/TransferPayload.kt | 54 ------- .../model/entity/register/RegisterPayload.kt | 38 ----- .../core/model/entity/register/UserVerify.kt | 20 --- .../core/model/entity/savedcards/Card.kt | 35 ---- .../entity/standinginstruction/SDIResponse.kt | 16 -- .../StandingInstruction.kt | 55 ------- .../entity/templates/account/AccountOption.kt | 39 ----- .../account/AccountOptionsTemplate.kt | 22 --- .../entity/templates/account/AccountType.kt | 26 --- .../beneficiary/AccountTypeOption.kt | 26 --- .../beneficiary/BeneficiaryTemplate.kt | 20 --- .../mifospay/core/model/utils/DateHelper.kt | 141 ----------------- .../localAssets/LocalAssetDataSource.kt | 6 +- .../localAssets/MifosLocalAssetDataSource.kt | 6 +- .../network/services/BeneficiaryService.kt | 4 +- .../core/network/services/KYCLevel1Service.kt | 8 +- .../services/ThirdPartyTransferService.kt | 4 +- .../network/services/TwoFactorAuthService.kt | 4 +- .../feature/auth/signup/SignupScreen.kt | 2 +- .../feature/auth/signup/SignupViewModel.kt | 2 +- .../feature/invoices/InvoiceDetailScreen.kt | 4 +- .../feature/kyc/KYCDescriptionScreen.kt | 14 +- .../feature/kyc/KYCDescriptionViewModel.kt | 4 +- .../feature/kyc/KYCLevel1ViewModel.kt | 6 +- .../profile/edit/EditProfileViewModel.kt | 2 +- .../org/mifospay/MainActivityViewModel.kt | 2 +- 134 files changed, 1553 insertions(+), 2017 deletions(-) delete mode 100644 core/model/consumer-rules.pro delete mode 100644 core/model/proguard-rules.pro rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/City.kt (94%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/Country.kt (93%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/State.kt (94%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/UserData.kt (93%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/Account.kt (64%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/Bank.kt (89%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/BankAccountDetails.kt (66%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Currency.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/NewAccount.kt (56%) rename core/model/src/{main/java/com/mifospay/core/model/domain/Currency.kt => commonMain/kotlin/org/mifospay/core/model/domain/NotificationPayload.kt} (67%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/SearchResult.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Transaction.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/TransactionType.kt (90%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/client/Client.kt (51%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/client/NewClient.kt (68%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/client/UpdateClientEntityMobile.kt (89%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/AccessToken.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/twofactor/DeliveryMethod.kt (65%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/user/NewUser.kt (79%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/user/UpdateUserEntityClients.kt (72%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/user/UpdateUserEntityEmail.kt (74%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/user/UpdateUserEntityPassword.kt (80%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/domain/user/User.kt (90%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/Page.kt (65%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/Role.kt (76%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/TPTResponse.kt (63%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Timeline.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/UserEntity.kt (88%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/UserWithRole.kt (61%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/accounts/SavingAccountsListResponse.kt (71%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/accounts/savings/PaymentType.kt (65%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingAccount.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Status.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Summary.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TimeLine.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transactions.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/accounts/savings/Transfer.kt (68%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransferDetail.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/authentication/AuthenticationPayload.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/Beneficiary.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/beneficary/BeneficiaryUpdatePayload.kt (61%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Client.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/client/ClientAccounts.kt (91%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Currency.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/client/DepositType.kt (66%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Status.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Type.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/kyc/KYCLevel1Details.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/noncore/Document.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/ClientPayload.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/DataTablePayload.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/payload/PayPayload.kt (79%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/payload/PayResponse.kt (81%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/payload/StandingInstructionPayload.kt (58%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/TransferPayload.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/entity/payload/UpdateVpaPayload.kt (71%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/RegisterPayload.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/UserVerify.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/savedcards/Card.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/SDIResponse.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOption.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/signup/PasswordStrength.kt (91%) rename core/model/src/{main/java/com => commonMain/kotlin/org}/mifospay/core/model/signup/SignupData.kt (87%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt delete mode 100644 core/model/src/main/AndroidManifest.xml delete mode 100644 core/model/src/main/java/com/mifospay/core/model/domain/NotificationPayload.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/domain/SearchResult.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/domain/Transaction.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/domain/twofactor/AccessToken.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/Invoice.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/SearchedEntity.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/Timeline.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Currency.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/SavingAccount.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Status.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Summary.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TimeLine.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TransactionType.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Transactions.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TransferDetail.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/authentication/AuthenticationPayload.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/beneficary/Beneficiary.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/client/Client.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/client/Currency.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/client/Status.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/client/Type.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/kyc/KYCLevel1Details.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/noncore/Document.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/payload/ClientPayload.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/payload/DataTablePayload.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/payload/TransferPayload.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/register/RegisterPayload.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/register/UserVerify.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/savedcards/Card.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/standinginstruction/SDIResponse.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountOption.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountType.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt delete mode 100644 core/model/src/main/java/com/mifospay/core/model/utils/DateHelper.kt diff --git a/core/model/build.gradle.kts b/core/model/build.gradle.kts index 8cadff653..8862c945a 100644 --- a/core/model/build.gradle.kts +++ b/core/model/build.gradle.kts @@ -23,8 +23,5 @@ kotlin { api(libs.kotlinx.datetime) implementation(libs.kotlinx.serialization.json) } - androidMain.dependencies { - implementation(libs.squareup.retrofit.converter.gson) - } } } \ No newline at end of file diff --git a/core/model/consumer-rules.pro b/core/model/consumer-rules.pro deleted file mode 100644 index e69de29bb..000000000 diff --git a/core/model/proguard-rules.pro b/core/model/proguard-rules.pro deleted file mode 100644 index 481bb4348..000000000 --- a/core/model/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/core/model/src/main/java/com/mifospay/core/model/City.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/City.kt similarity index 94% rename from core/model/src/main/java/com/mifospay/core/model/City.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/City.kt index ab02c68cb..8d3d0cb96 100644 --- a/core/model/src/main/java/com/mifospay/core/model/City.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/City.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model +package org.mifospay.core.model import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/core/model/src/main/java/com/mifospay/core/model/Country.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/Country.kt similarity index 93% rename from core/model/src/main/java/com/mifospay/core/model/Country.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/Country.kt index 8bf05c28d..c1e079fba 100644 --- a/core/model/src/main/java/com/mifospay/core/model/Country.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/Country.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model +package org.mifospay.core.model import kotlinx.serialization.Serializable diff --git a/core/model/src/main/java/com/mifospay/core/model/State.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/State.kt similarity index 94% rename from core/model/src/main/java/com/mifospay/core/model/State.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/State.kt index de96c402b..24b8a4c70 100644 --- a/core/model/src/main/java/com/mifospay/core/model/State.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/State.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model +package org.mifospay.core.model import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/core/model/src/main/java/com/mifospay/core/model/UserData.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt similarity index 93% rename from core/model/src/main/java/com/mifospay/core/model/UserData.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt index dfd447b72..180afee4a 100644 --- a/core/model/src/main/java/com/mifospay/core/model/UserData.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model +package org.mifospay.core.model data class UserData( val isAuthenticated: Boolean, diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/Account.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Account.kt similarity index 64% rename from core/model/src/main/java/com/mifospay/core/model/domain/Account.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Account.kt index 111a68214..a60910d53 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/Account.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Account.kt @@ -7,17 +7,17 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain +package org.mifospay.core.model.domain import kotlinx.serialization.Serializable @Serializable data class Account( - var image: String = "", - var name: String, - var number: String, - var balance: Double = 0.0, - var id: Long = 0L, - var productId: Long = 0L, - var currency: Currency, + val image: String = "", + val name: String, + val number: String, + val balance: Double = 0.0, + val id: Long = 0L, + val productId: Long = 0L, + val currency: Currency, ) diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/Bank.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Bank.kt similarity index 89% rename from core/model/src/main/java/com/mifospay/core/model/domain/Bank.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Bank.kt index 1c2c9a868..90778f5f9 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/Bank.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Bank.kt @@ -7,9 +7,9 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain +package org.mifospay.core.model.domain -class Bank( +data class Bank( val name: String, val image: Int, val bankType: BankType = BankType.OTHER, diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/BankAccountDetails.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/BankAccountDetails.kt similarity index 66% rename from core/model/src/main/java/com/mifospay/core/model/domain/BankAccountDetails.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/BankAccountDetails.kt index 7cfb9064e..9ae668614 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/BankAccountDetails.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/BankAccountDetails.kt @@ -7,12 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain +package org.mifospay.core.model.domain -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable -@Parcelize +@Serializable data class BankAccountDetails( var bankName: String? = null, var accountholderName: String? = null, @@ -21,6 +20,14 @@ data class BankAccountDetails( var type: String? = null, var isUpiEnabled: Boolean = false, var upiPin: String? = null, -) : Parcelable { - constructor() : this("", "", "", "", "", false, "") +) { + constructor() : this( + bankName = "", + accountholderName = "", + branch = "", + ifsc = "", + type = "", + isUpiEnabled = false, + upiPin = "", + ) } diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Currency.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Currency.kt new file mode 100644 index 000000000..d29ae7244 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Currency.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.domain + +import kotlinx.serialization.Serializable + +@Serializable +data class Currency( + val code: String, + val displaySymbol: String, + val displayLabel: String, +) { + constructor() : this( + code = "", + displaySymbol = "", + displayLabel = "", + ) +} diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/NewAccount.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NewAccount.kt similarity index 56% rename from core/model/src/main/java/com/mifospay/core/model/domain/NewAccount.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NewAccount.kt index a276663aa..54ce3f3ab 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/NewAccount.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NewAccount.kt @@ -7,14 +7,15 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain +package org.mifospay.core.model.domain + +import kotlinx.datetime.LocalDate -import java.util.Date data class NewAccount( - var clientId: Int, - var productId: String? = null, - var submittedOnDate: Date? = null, - var accountNo: String, - var locale: String? = null, - var dateFormat: String? = null, + val clientId: Int, + val productId: String? = null, + val submittedOnDate: LocalDate? = null, + val accountNo: String, + val locale: String? = null, + val dateFormat: String? = null, ) diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/Currency.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NotificationPayload.kt similarity index 67% rename from core/model/src/main/java/com/mifospay/core/model/domain/Currency.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NotificationPayload.kt index b17050b84..1520e7413 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/Currency.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NotificationPayload.kt @@ -7,15 +7,13 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain +package org.mifospay.core.model.domain import kotlinx.serialization.Serializable @Serializable -data class Currency( - var code: String, - var displaySymbol: String, - var displayLabel: String, -) { - constructor() : this("", "", "") -} +data class NotificationPayload( + val title: String? = null, + val body: String? = null, + val timestamp: String? = null, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/SearchResult.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/SearchResult.kt new file mode 100644 index 000000000..889084dbc --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/SearchResult.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.domain + +import kotlinx.serialization.Serializable + +@Serializable +data class SearchResult( + val resultId: Int = 0, + val resultName: String, + val resultType: String, +) { + constructor() : this( + resultId = 0, + resultName = "", + resultType = "", + ) +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Transaction.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Transaction.kt new file mode 100644 index 000000000..9ed8063ae --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Transaction.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.domain + +import kotlinx.serialization.Serializable +import org.mifospay.core.model.entity.accounts.savings.TransferDetail + +@Serializable +data class Transaction( + val transactionId: String? = null, + val clientId: Long = 0, + val accountId: Long = 0, + val amount: Double = 0.0, + val date: String? = null, + val currency: Currency = Currency(), + val transactionType: TransactionType = TransactionType.OTHER, + val transferId: Long = 0, + val transferDetail: TransferDetail = TransferDetail(), + val receiptId: String? = null, +) { + constructor() : this( + transactionId = "", + clientId = 0, + accountId = 0, + amount = 0.0, + date = "", + currency = Currency(), + transactionType = TransactionType.OTHER, + transferId = 0, + transferDetail = TransferDetail(), + receiptId = "", + ) +} diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/TransactionType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/TransactionType.kt similarity index 90% rename from core/model/src/main/java/com/mifospay/core/model/domain/TransactionType.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/TransactionType.kt index ad57f69fb..314983835 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/TransactionType.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/TransactionType.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain +package org.mifospay.core.model.domain enum class TransactionType { DEBIT, diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/client/Client.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt similarity index 51% rename from core/model/src/main/java/com/mifospay/core/model/domain/client/Client.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt index 9f8626325..01e0c5e2e 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/client/Client.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt @@ -7,18 +7,25 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain.client +package org.mifospay.core.model.domain.client import kotlinx.serialization.Serializable @Serializable data class Client( - var name: String? = null, - var image: String, - var externalId: String? = null, - var clientId: Long = 0L, - var displayName: String, - var mobileNo: String, + val name: String? = null, + val image: String, + val externalId: String? = null, + val clientId: Long = 0L, + val displayName: String, + val mobileNo: String, ) { - constructor() : this("", "", "", 0L, "", "") + constructor() : this( + name = "", + image = "", + externalId = "", + clientId = 0L, + displayName = "", + mobileNo = "", + ) } diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/client/NewClient.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt similarity index 68% rename from core/model/src/main/java/com/mifospay/core/model/domain/client/NewClient.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt index 2fdb25e29..bf59ce9e5 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/client/NewClient.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt @@ -7,9 +7,9 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain.client +package org.mifospay.core.model.domain.client -import com.mifospay.core.model.utils.DateHelper +import org.mifospay.core.model.utils.DateHelper data class NewClient( val fullname: String?, @@ -23,21 +23,21 @@ data class NewClient( val mobileNo: String?, val mifosSavingsProductId: Int?, ) { - val address: MutableList = mutableListOf() - val activationDate: String = DateHelper.getDateAsStringFromLong(System.currentTimeMillis()) + private val address: MutableList
= mutableListOf() + private val activationDate: String = DateHelper.formattedDate val submittedOnDate: String = activationDate val savingsProductId: Int = mifosSavingsProductId ?: 0 - val externalId: String = userName + "@mifos" + val externalId: String = "$userName@mifos" init { address.add( - com.mifospay.core.model.domain.client.NewClient.Address( - addressLine1, - addressLine2, - city, - postalCode, - stateProvinceId, - countryId, + Address( + addressLine1 = addressLine1, + addressLine2 = addressLine2, + street = city, + postalCode = postalCode, + stateProvinceId = stateProvinceId, + countryId = countryId, ), ) } diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/client/UpdateClientEntityMobile.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/UpdateClientEntityMobile.kt similarity index 89% rename from core/model/src/main/java/com/mifospay/core/model/domain/client/UpdateClientEntityMobile.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/UpdateClientEntityMobile.kt index 9ca0bc770..f7087edd4 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/client/UpdateClientEntityMobile.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/UpdateClientEntityMobile.kt @@ -7,6 +7,6 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain.client +package org.mifospay.core.model.domain.client data class UpdateClientEntityMobile(val mobileNo: String) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/AccessToken.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/AccessToken.kt new file mode 100644 index 000000000..0d24b0b22 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/AccessToken.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.domain.twofactor + +import kotlinx.serialization.Serializable + +@Serializable +data class AccessToken( + val token: String? = null, + val validFrom: Long? = null, + val validTo: Long? = null, +) diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/twofactor/DeliveryMethod.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/DeliveryMethod.kt similarity index 65% rename from core/model/src/main/java/com/mifospay/core/model/domain/twofactor/DeliveryMethod.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/DeliveryMethod.kt index a7381e6f7..320fffdae 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/twofactor/DeliveryMethod.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/DeliveryMethod.kt @@ -7,13 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain.twofactor +package org.mifospay.core.model.domain.twofactor -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable -@Parcelize +@Serializable data class DeliveryMethod( - var name: String?, - var target: String?, -) : Parcelable + val name: String?, + val target: String?, +) diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/user/NewUser.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt similarity index 79% rename from core/model/src/main/java/com/mifospay/core/model/domain/user/NewUser.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt index 12c8de930..72a2aee2a 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/user/NewUser.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt @@ -7,9 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain.user - -import java.util.Collections +package org.mifospay.core.model.domain.user class NewUser( val username: String?, @@ -28,6 +26,4 @@ class NewUser( private const val MOBILE_WALLET_ROLE_ID = 471 private const val SUPER_USER_ROLE_ID = 1 -val NEW_USER_ROLE_IDS: Collection = Collections.unmodifiableList( - listOf(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID), -) +val NEW_USER_ROLE_IDS: Collection = listOf(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID) diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/user/UpdateUserEntityClients.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityClients.kt similarity index 72% rename from core/model/src/main/java/com/mifospay/core/model/domain/user/UpdateUserEntityClients.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityClients.kt index e21861e51..0748b9978 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/user/UpdateUserEntityClients.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityClients.kt @@ -7,8 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain.user +package org.mifospay.core.model.domain.user +import kotlinx.serialization.Serializable + +@Serializable data class UpdateUserEntityClients( - var clients: ArrayList, + val clients: ArrayList, ) diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/user/UpdateUserEntityEmail.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityEmail.kt similarity index 74% rename from core/model/src/main/java/com/mifospay/core/model/domain/user/UpdateUserEntityEmail.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityEmail.kt index b45dfc156..2231efd18 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/user/UpdateUserEntityEmail.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityEmail.kt @@ -7,8 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain.user +package org.mifospay.core.model.domain.user +import kotlinx.serialization.Serializable + +@Serializable data class UpdateUserEntityEmail( - var email: String?, + val email: String?, ) diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/user/UpdateUserEntityPassword.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityPassword.kt similarity index 80% rename from core/model/src/main/java/com/mifospay/core/model/domain/user/UpdateUserEntityPassword.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityPassword.kt index b1fa56521..8a4b3d42f 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/user/UpdateUserEntityPassword.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityPassword.kt @@ -7,8 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain.user +package org.mifospay.core.model.domain.user +import kotlinx.serialization.Serializable + +@Serializable data class UpdateUserEntityPassword(val password: String) { val repeatPassword: String = password } diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/user/User.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt similarity index 90% rename from core/model/src/main/java/com/mifospay/core/model/domain/user/User.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt index dcab74ab4..c1de67fe0 100644 --- a/core/model/src/main/java/com/mifospay/core/model/domain/user/User.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt @@ -7,10 +7,10 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.domain.user +package org.mifospay.core.model.domain.user -import com.mifospay.core.model.entity.Role import kotlinx.serialization.Serializable +import org.mifospay.core.model.entity.Role @Serializable data class User( diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt new file mode 100644 index 000000000..cf0093f03 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity + +import kotlinx.serialization.Serializable + +@Serializable +data class Invoice( + val consumerId: String? = null, + val consumerName: String? = null, + val amount: Double = 0.0, + val itemsBought: String? = null, + val status: Long = 0L, + val transactionId: String? = null, + val id: Long = 0L, + val title: String? = null, + val date: List = ArrayList(), + + ) { + constructor() : this( + consumerId = null, + consumerName = null, + amount = 0.0, + itemsBought = null, + status = 0L, + transactionId = null, + id = 0L, + title = null, + date = ArrayList(), + ) +} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/Page.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Page.kt similarity index 65% rename from core/model/src/main/java/com/mifospay/core/model/entity/Page.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Page.kt index 2cd34f259..4e24e6354 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/Page.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Page.kt @@ -7,9 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity +package org.mifospay.core.model.entity +import kotlinx.serialization.Serializable + +@Serializable data class Page( - var totalFilteredRecords: Int = 0, - var pageItems: MutableList = ArrayList(), + val totalFilteredRecords: Int = 0, + val pageItems: MutableList = ArrayList(), ) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/Role.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Role.kt similarity index 76% rename from core/model/src/main/java/com/mifospay/core/model/entity/Role.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Role.kt index e4678e918..bd22ef392 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/Role.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Role.kt @@ -7,14 +7,14 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity +package org.mifospay.core.model.entity import kotlinx.serialization.Serializable @Serializable data class Role( - var id: String? = null, - var name: String? = null, - var description: String? = null, + val id: String? = null, + val name: String? = null, + val description: String? = null, val disabled: Boolean, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt new file mode 100644 index 000000000..d69b2019f --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity + +import kotlinx.serialization.Serializable + +@Serializable +data class SearchedEntity( + val entityId: Int = 0, + val entityAccountNo: String = " ", + val entityName: String = " ", + val entityType: String = " ", + val parentId: Int = 0, + val parentName: String = " ", +) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/TPTResponse.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/TPTResponse.kt similarity index 63% rename from core/model/src/main/java/com/mifospay/core/model/entity/TPTResponse.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/TPTResponse.kt index 2adb9aaaa..621b95a86 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/TPTResponse.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/TPTResponse.kt @@ -7,13 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity +package org.mifospay.core.model.entity -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable -@Parcelize +@Serializable data class TPTResponse( - var savingsId: String? = null, - var resourceId: String? = null, -) : Parcelable + val savingsId: String? = null, + val resourceId: String? = null, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Timeline.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Timeline.kt new file mode 100644 index 000000000..968d2a3e0 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Timeline.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity + +import kotlinx.serialization.Serializable + +@Serializable +data class Timeline( + val submittedOnDate: List = ArrayList(), + val submittedByUsername: String? = null, + val submittedByFirstname: String? = null, + val submittedByLastname: String? = null, + val activatedOnDate: List = ArrayList(), + val activatedByUsername: String? = null, + val activatedByFirstname: String? = null, + val activatedByLastname: String? = null, + val closedOnDate: List = ArrayList(), + val closedByUsername: String? = null, + val closedByFirstname: String? = null, + val closedByLastname: String? = null, +) { + constructor() : this( + submittedOnDate = ArrayList(), + submittedByUsername = "", + submittedByFirstname = "", + submittedByLastname = "", + activatedOnDate = ArrayList(), + activatedByUsername = "", + activatedByFirstname = "", + activatedByLastname = "", + closedOnDate = ArrayList(), + closedByUsername = "", + closedByFirstname = "", + closedByLastname = "", + ) +} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/UserEntity.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserEntity.kt similarity index 88% rename from core/model/src/main/java/com/mifospay/core/model/entity/UserEntity.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserEntity.kt index 63c6277cd..65ab8bfd6 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/UserEntity.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserEntity.kt @@ -7,8 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity +package org.mifospay.core.model.entity +import kotlinx.serialization.Serializable + +@Serializable data class UserEntity( val username: String, val userId: Long = 0, diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/UserWithRole.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserWithRole.kt similarity index 61% rename from core/model/src/main/java/com/mifospay/core/model/entity/UserWithRole.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserWithRole.kt index e54eb80a8..c5b3404f0 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/UserWithRole.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserWithRole.kt @@ -7,16 +7,16 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity +package org.mifospay.core.model.entity import kotlinx.serialization.Serializable @Serializable data class UserWithRole( - var id: String? = null, - var username: String? = null, - var firstname: String? = null, - var lastname: String? = null, - var email: String? = null, - var selectedRoles: List? = ArrayList(), + val id: String? = null, + val username: String? = null, + val firstname: String? = null, + val lastname: String? = null, + val email: String? = null, + val selectedRoles: List? = ArrayList(), ) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/SavingAccountsListResponse.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/SavingAccountsListResponse.kt similarity index 71% rename from core/model/src/main/java/com/mifospay/core/model/entity/accounts/SavingAccountsListResponse.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/SavingAccountsListResponse.kt index ea86805fe..4887472a2 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/SavingAccountsListResponse.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/SavingAccountsListResponse.kt @@ -7,10 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity.accounts +package org.mifospay.core.model.entity.accounts -import com.mifospay.core.model.entity.accounts.savings.SavingAccount +import kotlinx.serialization.Serializable +import org.mifospay.core.model.entity.accounts.savings.SavingAccount +@Serializable data class SavingAccountsListResponse( var savingsAccounts: List = ArrayList(), ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt new file mode 100644 index 000000000..1d9824bc7 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.accounts.savings + +import kotlinx.serialization.Serializable + +@Serializable +data class Currency( + val code: String = "", + val name: String = "", + val decimalPlaces: Int? = null, + val inMultiplesOf: Int? = null, + val displaySymbol: String = "", + val nameCode: String = "", + val displayLabel: String = "" +) { + constructor() : this( + code = "", + name = "", + decimalPlaces = 0, + inMultiplesOf = 0, + displaySymbol = "", + nameCode = "", + displayLabel = "", + ) +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt new file mode 100644 index 000000000..f8f175073 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.accounts.savings + +import kotlinx.serialization.Serializable + +@Serializable +data class PaymentDetailData( + val id: Int? = null, + val paymentType: PaymentType? = null, + val accountNumber: String? = null, + val checkNumber: String? = null, + val routingCode: String? = null, + val receiptNumber: String? = null, + val bankNumber: String? = null, +) { + constructor() : this( + id = null, + paymentType = null, + accountNumber = null, + checkNumber = null, + routingCode = null, + receiptNumber = null, + bankNumber = null, + ) +} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/PaymentType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentType.kt similarity index 65% rename from core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/PaymentType.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentType.kt index 57e449a09..cd19f5e89 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/PaymentType.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentType.kt @@ -7,17 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.model.entity.accounts.savings -import com.google.gson.annotations.SerializedName import kotlinx.serialization.Serializable @Serializable data class PaymentType( - @SerializedName("id") - var id: Int? = null, - - @SerializedName("name") - var name: String? = null, - + val id: Int? = null, + val name: String? = null, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingAccount.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingAccount.kt new file mode 100644 index 000000000..903579230 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingAccount.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.accounts.savings + +import kotlinx.serialization.Serializable +import org.mifospay.core.model.entity.client.DepositType + +@Serializable +data class SavingAccount( + val id: Long = 0L, + val accountNo: String = "", + val productName: String = "", + val productId: Int = 0, + val overdraftLimit: Long = 0L, + val minRequiredBalance: Long = 0L, + val accountBalance: Double = 0.0, + val totalDeposits: Double = 0.0, + val savingsProductName: String? = null, + val clientName: String? = null, + val savingsProductId: String? = null, + val nominalAnnualInterestRate: Double = 0.0, + val status: Status? = null, + val currency: Currency = Currency(), + val depositType: DepositType? = null, +) { + fun isRecurring(): Boolean { + return this.depositType != null && this.depositType.isRecurring + } + + constructor() : this( + id = 0L, + accountNo = "", + productName = "", + productId = 0, + overdraftLimit = 0L, + minRequiredBalance = 0L, + accountBalance = 0.0, + totalDeposits = 0.0, + savingsProductName = "", + clientName = "", + savingsProductId = "", + nominalAnnualInterestRate = 0.0, + status = Status(), + currency = Currency(), + depositType = DepositType(), + ) +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt new file mode 100644 index 000000000..ae8e2b0fc --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.accounts.savings + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.mifospay.core.model.entity.client.DepositType + +@Serializable +data class SavingsWithAssociations( + val id: Long = 0L, + val accountNo: String? = null, + val depositType: DepositType? = null, + val externalId: String = "", + val clientId: Int = 0, + val clientName: String = "", + val savingsProductId: Int? = null, + val savingsProductName: String? = null, + val fieldOfficerId: Int? = null, + val status: Status? = null, + val timeline: TimeLine? = null, + val currency: Currency? = null, + val nominalAnnualInterestRate: Double? = null, + val minRequiredOpeningBalance: Double? = null, + val lockinPeriodFrequency: Double? = null, + val withdrawalFeeForTransfers: Boolean? = null, + val allowOverdraft: Boolean? = null, + val enforceMinRequiredBalance: Boolean? = null, + val withHoldTax: Boolean? = null, + val lastActiveTransactionDate: List? = null, + @SerialName("isDormancyTrackingActive") + val dormancyTrackingActive: Boolean? = null, + val summary: Summary? = null, + val transactions: List = ArrayList(), +) { + constructor() : this( + id = 0L, + accountNo = null, + depositType = null, + externalId = "", + clientId = 0, + clientName = "", + savingsProductId = null, + savingsProductName = null, + fieldOfficerId = 0, + status = null, + timeline = null, + currency = null, + nominalAnnualInterestRate = null, + minRequiredOpeningBalance = null, + lockinPeriodFrequency = 0.0, + withdrawalFeeForTransfers = false, + allowOverdraft = false, + enforceMinRequiredBalance = false, + withHoldTax = null, + lastActiveTransactionDate = listOf(), + dormancyTrackingActive = null, + summary = null, + ) +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Status.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Status.kt new file mode 100644 index 000000000..cb2fdf8ca --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Status.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.accounts.savings + +import kotlinx.serialization.Serializable + +@Serializable +data class Status( + val id: Int? = null, + val code: String? = null, + val value: String? = null, + val submittedAndPendingApproval: Boolean? = null, + val approved: Boolean? = null, + val rejected: Boolean? = null, + val withdrawnByApplicant: Boolean? = null, + val active: Boolean? = null, + val closed: Boolean? = null, + val prematureClosed: Boolean? = null, + val transferInProgress: Boolean? = null, + val transferOnHold: Boolean? = null, + val matured: Boolean? = null, +) { + constructor() : this( + id = null, + code = null, + value = null, + submittedAndPendingApproval = null, + approved = null, + rejected = null, + withdrawnByApplicant = null, + active = null, + closed = null, + prematureClosed = null, + transferInProgress = null, + transferOnHold = null, + matured = null, + ) +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Summary.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Summary.kt new file mode 100644 index 000000000..96852b986 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Summary.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.accounts.savings + +import kotlinx.serialization.Serializable + +@Serializable +data class Summary( + val currency: Currency? = null, + val totalDeposits: Double? = null, + val totalWithdrawals: Double? = null, + val totalInterestEarned: Double? = null, + val totalInterestPosted: Double? = null, + val accountBalance: Double? = null, + val totalOverdraftInterestDerived: Double? = null, + val interestNotPosted: Double? = null, + val lastInterestCalculationDate: List? = null, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TimeLine.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TimeLine.kt new file mode 100644 index 000000000..3aff25db6 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TimeLine.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.accounts.savings + +import kotlinx.serialization.Serializable + +@Serializable +data class TimeLine( + val submittedOnDate: List = ArrayList(), + val submittedByUsername: String? = null, + val submittedByFirstname: String? = null, + val submittedByLastname: String? = null, + val approvedOnDate: List = ArrayList(), + val approvedByUsername: String? = null, + val approvedByFirstname: String? = null, + val approvedByLastname: String? = null, + val activatedOnDate: List? = null, + val activatedByUsername: String? = null, + val activatedByFirstname: String? = null, + val activatedByLastname: String? = null, +) { + constructor() : this( + submittedOnDate = ArrayList(), + submittedByUsername = null, + submittedByFirstname = null, + submittedByLastname = null, + approvedOnDate = ArrayList(), + approvedByUsername = null, + approvedByFirstname = null, + approvedByLastname = null, + activatedOnDate = null, + activatedByUsername = null, + activatedByFirstname = null, + activatedByLastname = null, + ) +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt new file mode 100644 index 000000000..532a91c42 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.accounts.savings + +import kotlinx.serialization.Serializable + +@Serializable +data class TransactionType( + val id: Int? = null, + val code: String? = null, + val value: String? = null, + val deposit: Boolean = false, + val dividendPayout: Boolean = false, + val withdrawal: Boolean = false, + val interestPosting: Boolean = false, + val feeDeduction: Boolean = false, + val initiateTransfer: Boolean = false, + val approveTransfer: Boolean = false, + val withdrawTransfer: Boolean = false, + val rejectTransfer: Boolean = false, + val overdraftInterest: Boolean = false, + val writtenoff: Boolean = false, + val overdraftFee: Boolean = false, + val withholdTax: Boolean = false, + val escheat: Boolean? = null, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transactions.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transactions.kt new file mode 100644 index 000000000..00db6abea --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transactions.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.accounts.savings + +import kotlinx.serialization.Serializable + +@Serializable +data class Transactions( + val id: Int? = null, + val transactionType: TransactionType = TransactionType(), + val accountId: Int? = null, + val accountNo: String? = null, + val date: List = ArrayList(), + val currency: Currency = Currency(), + val paymentDetailData: PaymentDetailData? = null, + val amount: Double = 0.0, + val transfer: Transfer = Transfer(), + val runningBalance: Double? = null, + val reversed: Boolean? = null, + val submittedOnDate: List = ArrayList(), + val interestedPostedAsOn: Boolean? = null, +) { + constructor() : this( + id = 0, + transactionType = TransactionType(), + accountId = 0, + accountNo = "", + date = ArrayList(), + currency = Currency(), + paymentDetailData = PaymentDetailData(), + amount = 0.0, + transfer = Transfer(), + runningBalance = 0.0, + reversed = false, + submittedOnDate = ArrayList(), + interestedPostedAsOn = false, + ) +} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Transfer.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transfer.kt similarity index 68% rename from core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Transfer.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transfer.kt index 5dce2a848..e5c5a878e 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Transfer.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transfer.kt @@ -7,15 +7,13 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.model.entity.accounts.savings -import com.google.gson.annotations.SerializedName import kotlinx.serialization.Serializable @Serializable data class Transfer( - @SerializedName("id") - var id: Long = 0L, + val id: Long = 0L, ) { - constructor() : this(0L) + constructor() : this(id = 0L) } diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransferDetail.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransferDetail.kt new file mode 100644 index 000000000..b236e99cc --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransferDetail.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.accounts.savings + +import kotlinx.serialization.Serializable +import org.mifospay.core.model.domain.client.Client + +@Serializable +data class TransferDetail( + val id: Long = 0L, + val fromClient: Client = Client(), + val fromAccount: SavingAccount = SavingAccount(), + val toClient: Client = Client(), + val toAccount: SavingAccount = SavingAccount(), +) { + constructor() : this( + id = 0L, + fromClient = Client(), + fromAccount = SavingAccount(), + toClient = Client(), + toAccount = SavingAccount(), + ) +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/authentication/AuthenticationPayload.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/authentication/AuthenticationPayload.kt new file mode 100644 index 000000000..c96c77306 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/authentication/AuthenticationPayload.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.authentication + +import kotlinx.serialization.Serializable + +@Serializable +data class AuthenticationPayload( + val username: String, + val password: String, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/Beneficiary.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/Beneficiary.kt new file mode 100644 index 000000000..50a4b3466 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/Beneficiary.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.beneficary + +import kotlinx.serialization.Serializable +import org.mifospay.core.model.entity.templates.account.AccountType + +@Serializable +data class Beneficiary( + val id: Int? = null, + val name: String? = null, + val officeName: String? = null, + val clientName: String? = null, + val accountType: AccountType? = null, + val accountNumber: String? = null, + val transferLimit: Int = 0, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt new file mode 100644 index 000000000..ca8c3ebd7 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.beneficary + +import kotlinx.serialization.Serializable + +@Serializable +data class BeneficiaryPayload( + val locale: String? = "en_GB", + val name: String? = null, + val accountNumber: String? = null, + val accountType: Int = 0, + val transferLimit: Int = 0, + val officeName: String? = null, +) { + constructor() : this( + locale = null, + name = null, + accountNumber = null, + accountType = 0, + transferLimit = 0, + officeName = null, + ) +} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/beneficary/BeneficiaryUpdatePayload.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryUpdatePayload.kt similarity index 61% rename from core/model/src/main/java/com/mifospay/core/model/entity/beneficary/BeneficiaryUpdatePayload.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryUpdatePayload.kt index 36e334e75..35c2e6e1e 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/beneficary/BeneficiaryUpdatePayload.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryUpdatePayload.kt @@ -7,14 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity.beneficary +package org.mifospay.core.model.entity.beneficary -import com.google.gson.annotations.SerializedName +import kotlinx.serialization.Serializable +@Serializable data class BeneficiaryUpdatePayload( - @SerializedName("name") - var name: String? = null, - - @SerializedName("transferLimit") - var transferLimit: Int = 0, + val name: String? = null, + val transferLimit: Int = 0, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Client.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Client.kt new file mode 100644 index 000000000..5d5cd3922 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Client.kt @@ -0,0 +1,62 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.client + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.mifospay.core.model.entity.Timeline + +@Serializable +data class Client( + val id: Int = 0, + val accountNo: String? = null, + val status: Status? = null, + val active: Boolean? = null, + val activationDate: List = ArrayList(), + val dobDate: List = ArrayList(), + val firstname: String? = null, + val middlename: String? = null, + val lastname: String? = null, + val displayName: String? = null, + val fullname: String? = null, + val officeId: Int = 0, + val officeName: String? = null, + val staffId: Int? = null, + val staffName: String? = null, + val timeline: Timeline? = null, + val imageId: Int = 0, + @SerialName("imagePresent") + val isImagePresent: Boolean = false, + val externalId: String = "", + val mobileNo: String = "", +) { + constructor() : this( + id = 0, + accountNo = "", + status = Status(), + active = false, + activationDate = ArrayList(), + dobDate = ArrayList(), + firstname = "", + middlename = "", + lastname = "", + displayName = "", + fullname = "", + officeId = 0, + officeName = "", + staffId = 0, + staffName = "", + timeline = Timeline(), + imageId = 0, + isImagePresent = false, + externalId = "", + mobileNo = "", + ) +} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/client/ClientAccounts.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientAccounts.kt similarity index 91% rename from core/model/src/main/java/com/mifospay/core/model/entity/client/ClientAccounts.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientAccounts.kt index 79c8787b1..355155ab5 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/client/ClientAccounts.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientAccounts.kt @@ -7,10 +7,10 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity.client +package org.mifospay.core.model.entity.client -import com.mifospay.core.model.entity.accounts.savings.SavingAccount import kotlinx.serialization.Serializable +import org.mifospay.core.model.entity.accounts.savings.SavingAccount @Serializable data class ClientAccounts( diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Currency.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Currency.kt new file mode 100644 index 000000000..d1293d618 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Currency.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.client + +import kotlinx.serialization.Serializable + +@Serializable +data class Currency( + val code: String? = null, + val name: String? = null, + val decimalPlaces: Int? = null, + val displaySymbol: String? = null, + val nameCode: String? = null, + val displayLabel: String? = null, +) { + constructor() : this( + code = null, + name = null, + decimalPlaces = null, + displaySymbol = null, + nameCode = null, + displayLabel = null, + ) +} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/client/DepositType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt similarity index 66% rename from core/model/src/main/java/com/mifospay/core/model/entity/client/DepositType.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt index b82c3886a..ed8887621 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/client/DepositType.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt @@ -7,22 +7,15 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity.client +package org.mifospay.core.model.entity.client -import com.google.gson.annotations.SerializedName import kotlinx.serialization.Serializable @Serializable data class DepositType( - @SerializedName("id") - var id: Int? = null, - - @SerializedName("code") - var code: String? = null, - - @SerializedName("value") - var value: String? = null, - + val id: Int? = null, + val code: String? = null, + val value: String? = null, ) { val isRecurring: Boolean get() = ServerTypes.RECURRING.id == id @@ -32,9 +25,13 @@ data class DepositType( get() = ServerTypes.fromId(id!!) enum class ServerTypes(val id: Int, val code: String, val endpoint: String) { - SAVINGS(100, "depositAccountType.savingsDeposit", "savingsaccounts"), - FIXED(200, "depositAccountType.fixedDeposit", "savingsaccounts"), - RECURRING(300, "depositAccountType.recurringDeposit", "recurringdepositaccounts"), + SAVINGS(id = 100, code = "depositAccountType.savingsDeposit", endpoint = "savingsaccounts"), + FIXED(id = 200, code = "depositAccountType.fixedDeposit", endpoint = "savingsaccounts"), + RECURRING( + id = 300, + code = "depositAccountType.recurringDeposit", + endpoint = "recurringdepositaccounts" + ), ; companion object { diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Status.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Status.kt new file mode 100644 index 000000000..ae033b9ff --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Status.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.client + +import kotlinx.serialization.Serializable + +@Serializable +data class Status( + val id: Int? = null, + val code: String? = null, + val value: String? = null, +) { + constructor() : this(id = null, code = null, value = null) +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Type.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Type.kt new file mode 100644 index 000000000..18243c23d --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Type.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.client + +import kotlinx.serialization.Serializable + +@Serializable +data class Type( + val id: Int? = null, + val code: String? = null, + val value: String? = null, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/kyc/KYCLevel1Details.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/kyc/KYCLevel1Details.kt new file mode 100644 index 000000000..4327b2389 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/kyc/KYCLevel1Details.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.kyc + +import kotlinx.serialization.Serializable + +@Serializable +data class KYCLevel1Details( + val firstName: String? = null, + val lastName: String? = null, + val addressLine1: String? = null, + val addressLine2: String? = null, + val mobileNo: String? = null, + val dob: String? = null, + val currentLevel: String = "", +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/noncore/Document.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/noncore/Document.kt new file mode 100644 index 000000000..1f2d63b78 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/noncore/Document.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.noncore + +import kotlinx.serialization.Serializable + +@Serializable +data class Document( + val id: Int = 0, + val parentEntityType: String? = null, + val parentEntityId: Int = 0, + val name: String? = null, + val fileName: String? = null, + val size: Long = 0, + val type: String? = null, + val description: String? = null, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/ClientPayload.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/ClientPayload.kt new file mode 100644 index 000000000..5fbc50c73 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/ClientPayload.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.payload + +import kotlinx.serialization.Serializable + +@Serializable +data class ClientPayload( + val firstname: String? = null, + val lastname: String? = null, + val middlename: String? = null, + val officeId: Int? = null, + val staffId: Int? = null, + val genderId: Int? = null, + val active: Boolean? = null, + val activationDate: String? = null, + val submittedOnDate: String? = null, + val dateOfBirth: String? = null, + val mobileNo: String? = null, + val externalId: String? = null, + val clientTypeId: Int? = null, + val clientClassificationId: Int? = null, + val dateFormat: String? = "DD_MMMM_YYYY", + val locale: String? = "en", + val datatables: List = ArrayList(), +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/DataTablePayload.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/DataTablePayload.kt new file mode 100644 index 000000000..427258782 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/DataTablePayload.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.payload + +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +import kotlinx.serialization.json.JsonElement + +@Serializable +data class DataTablePayload( + @Transient + val id: Int? = null, + @Transient + val clientCreationTime: Long? = null, + @Transient + val dataTableString: String? = null, + val registeredTableName: String? = null, + val applicationTableName: String? = null, + val data: HashMap? = null, +) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/payload/PayPayload.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayPayload.kt similarity index 79% rename from core/model/src/main/java/com/mifospay/core/model/entity/payload/PayPayload.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayPayload.kt index 93abfca12..6bd61d55c 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/payload/PayPayload.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayPayload.kt @@ -7,12 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity.payload +package org.mifospay.core.model.entity.payload -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable -@Parcelize +@Serializable data class PayPayload( val transactionDate: String, val transactionAmount: Int, @@ -20,4 +19,4 @@ data class PayPayload( val dateFormat: String, val paymentTypeId: Int = 1, val locale: String = "en", -) : Parcelable +) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/payload/PayResponse.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayResponse.kt similarity index 81% rename from core/model/src/main/java/com/mifospay/core/model/entity/payload/PayResponse.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayResponse.kt index d1998737e..11ce8f688 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/payload/PayResponse.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayResponse.kt @@ -7,8 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity.payload +package org.mifospay.core.model.entity.payload +import kotlinx.serialization.Serializable + +@Serializable data class PayResponse( val officeId: Int, val clientId: Int, @@ -17,6 +20,7 @@ data class PayResponse( val changes: Change, ) +@Serializable data class Change( val paymentTypeId: Int, ) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/payload/StandingInstructionPayload.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/StandingInstructionPayload.kt similarity index 58% rename from core/model/src/main/java/com/mifospay/core/model/entity/payload/StandingInstructionPayload.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/StandingInstructionPayload.kt index aab5fe44c..cf568f61f 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/payload/StandingInstructionPayload.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/StandingInstructionPayload.kt @@ -7,34 +7,33 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity.payload +package org.mifospay.core.model.entity.payload -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable -@Parcelize +@Serializable data class StandingInstructionPayload( - var fromOfficeId: Int, - var fromClientId: Int, - var fromAccountType: Int, + val fromOfficeId: Int, + val fromClientId: Int, + val fromAccountType: Int, val name: String?, val transferType: Int, val priority: Int, val status: Int, - var fromAccountId: Long, - var toOfficeId: Int, - var toClientId: Int, - var toAccountType: Int, - var toAccountId: Long, + val fromAccountId: Long, + val toOfficeId: Int, + val toClientId: Int, + val toAccountType: Int, + val toAccountId: Long, val instructionType: Int, - var amount: Double, - var validFrom: String?, + val amount: Double, + val validFrom: String?, val recurrenceType: Int, val recurrenceInterval: Int, val recurrenceFrequency: Int, val locale: String?, val dateFormat: String?, - var validTill: String?, - var recurrenceOnMonthDay: String?, + val validTill: String?, + val recurrenceOnMonthDay: String?, val monthDayFormat: String?, -) : Parcelable +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/TransferPayload.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/TransferPayload.kt new file mode 100644 index 000000000..f10e40638 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/TransferPayload.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.payload + +import kotlinx.serialization.Serializable + +@Serializable +data class TransferPayload( + val fromOfficeId: Int? = null, + val fromClientId: Long? = null, + val fromAccountType: Int? = null, + val fromAccountId: Int? = null, + val toOfficeId: Int? = null, + val toClientId: Long? = null, + val toAccountType: Int? = null, + val toAccountId: Int? = null, + val transferDate: String? = null, + val transferAmount: Double? = null, + val transferDescription: String? = null, + val dateFormat: String? = "dd MMMM yyyy", + val locale: String? = "en", +) { + constructor() : this( + fromOfficeId = null, + fromClientId = null, + fromAccountType = null, + fromAccountId = null, + toOfficeId = null, + toClientId = null, + toAccountType = null, + toAccountId = null, + transferDate = null, + transferAmount = null, + transferDescription = null, + ) +} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/payload/UpdateVpaPayload.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/UpdateVpaPayload.kt similarity index 71% rename from core/model/src/main/java/com/mifospay/core/model/entity/payload/UpdateVpaPayload.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/UpdateVpaPayload.kt index 10fc54e41..1bb8e906f 100644 --- a/core/model/src/main/java/com/mifospay/core/model/entity/payload/UpdateVpaPayload.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/UpdateVpaPayload.kt @@ -7,8 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.entity.payload +package org.mifospay.core.model.entity.payload +import kotlinx.serialization.Serializable + +@Serializable data class UpdateVpaPayload( - var externalId: String? = null, + val externalId: String? = null, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/RegisterPayload.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/RegisterPayload.kt new file mode 100644 index 000000000..11c8ad663 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/RegisterPayload.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.register + +import kotlinx.serialization.Serializable + +@Serializable +data class RegisterPayload( + val username: String? = null, + val firstName: String? = null, + val lastName: String? = null, + val email: String? = null, + val mobileNumber: String? = null, + val accountNumber: String? = null, + val password: String? = null, + val authenticationMode: String? = null, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/UserVerify.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/UserVerify.kt new file mode 100644 index 000000000..8e97fffe0 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/UserVerify.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.register + +import kotlinx.serialization.Serializable + +@Serializable +data class UserVerify( + val requestId: String? = null, + val authenticationToken: String? = null, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/savedcards/Card.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/savedcards/Card.kt new file mode 100644 index 000000000..094749765 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/savedcards/Card.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.savedcards + +import kotlinx.serialization.Serializable + +@Serializable +data class Card( + val cardNumber: String = "", + val cvv: String = "", + val expiryDate: String = "", + val firstName: String = "", + val lastName: String = "", + val id: Int = 0, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/SDIResponse.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/SDIResponse.kt new file mode 100644 index 000000000..a10d64f2f --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/SDIResponse.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.standinginstruction + +import kotlinx.serialization.Serializable + +@Serializable +data class SDIResponse( + val clientId: Int, + val resourceId: String?, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt new file mode 100644 index 000000000..6d9edad60 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.standinginstruction + +import kotlinx.serialization.Serializable +import org.mifospay.core.model.entity.accounts.savings.SavingAccount +import org.mifospay.core.model.entity.client.Client +import org.mifospay.core.model.entity.client.Status + +@Serializable +data class StandingInstruction( + val id: Long, + val name: String, + val fromClient: Client, + val fromAccount: SavingAccount, + val toClient: Client, + val toAccount: SavingAccount, + val status: Status, + val amount: Double, + val validFrom: List, + val validTill: List?, + val recurrenceInterval: Int, + val recurrenceOnMonthDay: List, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOption.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOption.kt new file mode 100644 index 000000000..1bbf350ed --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOption.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.templates.account + +import kotlinx.serialization.Serializable + +@Serializable +data class AccountOption( + val accountId: Int? = null, + val accountNo: String? = null, + val accountType: AccountType? = null, + val clientId: Long? = null, + val clientName: String? = null, + val officeId: Int? = null, + val officeName: String? = null, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt new file mode 100644 index 000000000..17afff35c --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.templates.account + +import kotlinx.serialization.Serializable + +@Serializable +data class AccountOptionsTemplate( + val fromAccountOptions: List? = listOf(), + val toAccountOptions: List? = listOf(), +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt new file mode 100644 index 000000000..5eaaa3da7 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.templates.account + +import kotlinx.serialization.Serializable + +@Serializable +data class AccountType( + val id: Int? = null, + val code: String? = null, + val value: String? = null, +) \ No newline at end of file diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt new file mode 100644 index 000000000..bd537a5a0 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.templates.beneficiary + +import kotlinx.serialization.Serializable + +@Serializable +data class AccountTypeOption( + val id: Int? = null, + val code: String? = null, + val value: String? = null, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt new file mode 100644 index 000000000..962bebc05 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.entity.templates.beneficiary + +import kotlinx.serialization.Serializable + +@Serializable +data class BeneficiaryTemplate( + val accountTypeOptions: List? = null, +) diff --git a/core/model/src/main/java/com/mifospay/core/model/signup/PasswordStrength.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/PasswordStrength.kt similarity index 91% rename from core/model/src/main/java/com/mifospay/core/model/signup/PasswordStrength.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/PasswordStrength.kt index c14ecab3e..b8c6ebd33 100644 --- a/core/model/src/main/java/com/mifospay/core/model/signup/PasswordStrength.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/PasswordStrength.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.signup +package org.mifospay.core.model.signup enum class PasswordStrength { WEAK, diff --git a/core/model/src/main/java/com/mifospay/core/model/signup/SignupData.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/SignupData.kt similarity index 87% rename from core/model/src/main/java/com/mifospay/core/model/signup/SignupData.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/SignupData.kt index 6ccc012d6..9307c399a 100644 --- a/core/model/src/main/java/com/mifospay/core/model/signup/SignupData.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/SignupData.kt @@ -7,12 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package com.mifospay.core.model.signup +package org.mifospay.core.model.signup -import android.os.Parcelable -import kotlinx.parcelize.Parcelize +import kotlinx.serialization.Serializable -@Parcelize +@Serializable data class SignupData( val firstName: String? = null, val lastName: String? = null, @@ -29,4 +28,4 @@ data class SignupData( val countryName: String? = null, val countryId: String? = null, val mifosSavingsProductId: Int = 0, -) : Parcelable +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt new file mode 100644 index 000000000..a5d0b223b --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt @@ -0,0 +1,149 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.utils + +import kotlinx.datetime.Clock +import kotlinx.datetime.DateTimeUnit +import kotlinx.datetime.LocalDateTime +import kotlinx.datetime.TimeZone +import kotlinx.datetime.atStartOfDayIn +import kotlinx.datetime.format +import kotlinx.datetime.format.FormatStringsInDatetimeFormats +import kotlinx.datetime.format.byUnicodePattern +import kotlinx.datetime.minus +import kotlinx.datetime.toInstant +import kotlinx.datetime.toLocalDateTime +import kotlin.time.Duration.Companion.days + +@OptIn(FormatStringsInDatetimeFormats::class) +object DateHelper { + private const val LOG_TAG = "DateHelper" + private const val FULL_MONTH = "dd MMM yyyy" + private const val SHORT_MONTH = "dd-MM-yyyy" + + private val fullMonthFormat = LocalDateTime.Format { + byUnicodePattern(FULL_MONTH) + } + + private val shortMonthFormat = LocalDateTime.Format { + byUnicodePattern(SHORT_MONTH) + } + + /** + * the result string uses the list given in a reverse order ([x, y, z] results in "z y x") + * + * @param integersOfDate [year-month-day] (ex [2016, 4, 14]) + * @return date in the format day month year (ex 14 Apr 2016) + */ + fun getDateAsString(integersOfDate: List): String { + val stringBuilder = StringBuilder() + stringBuilder.append(integersOfDate[2]) + .append(' ') + .append(getMonthName(integersOfDate[1])) + .append(' ') + .append(integersOfDate[0]) + return stringBuilder.toString() + } + + fun getDateAsString(integersOfDate: List, pattern: String): String { + return getFormatConverter(FULL_MONTH, pattern, getDateAsString(integersOfDate)) + } + + /** + * This Method converting the dd-MM-yyyy format type date string into dd MMMM yyyy + * + * @param format Final Format of date string + * @param dateString date string + * @return dd MMMM yyyy format date string. + */ + fun getSpecificFormat(format: String, dateString: String): String { + val pickerFormat = shortMonthFormat + val finalFormat = LocalDateTime.Format { byUnicodePattern(format) } + + return finalFormat.format(pickerFormat.parse(dateString)) + } + + fun getFormatConverter( + currentFormat: String, + requiredFormat: String, + dateString: String, + ): String { + val pickerFormat = LocalDateTime.Format { byUnicodePattern(currentFormat) } + val finalFormat = LocalDateTime.Format { byUnicodePattern(requiredFormat) } + + return pickerFormat.parse(dateString).format(finalFormat) + } + + /** + * @param month an integer from 1 to 12 + * @return string representation of the month like Jan or Feb..etc + */ + private fun getMonthName(month: Int): String { + var monthName = "" + when (month) { + 1 -> monthName = "Jan" + 2 -> monthName = "Feb" + 3 -> monthName = "Mar" + 4 -> monthName = "Apr" + 5 -> monthName = "May" + 6 -> monthName = "Jun" + 7 -> monthName = "Jul" + 8 -> monthName = "Aug" + 9 -> monthName = "Sep" + 10 -> monthName = "Oct" + 11 -> monthName = "Nov" + 12 -> monthName = "Dec" + } + return monthName + } + + private fun getDateAsLongFromString(dateStr: String, pattern: String): Long { + return try { + // Create a DateTimeFormatter with the given pattern + val formatter = LocalDateTime.Format { byUnicodePattern(pattern) } + + // Parse the string to a LocalDateTime + val localDateTime = LocalDateTime.parse(dateStr, formatter) + + // Convert LocalDateTime to Instant (assuming the date is in the system's time zone) + val instant = localDateTime.toInstant(TimeZone.currentSystemDefault()) + + // Convert Instant to milliseconds since epoch + instant.toEpochMilliseconds() + } catch (e: Exception) { + 0L + } + } + + fun getDateAsLongFromList(integersOfDate: List): Long { + val dateStr = getDateAsString(integersOfDate) + return getDateAsLongFromString(dateStr, FULL_MONTH) + } + + fun subtractWeeks(number: Int): Long { + val now = Clock.System.now() + val subtracted = now.minus(number.times(7).days) + return subtracted.toEpochMilliseconds() + } + + fun subtractMonths(number: Int): Long { + val now = Clock.System.now() + val currentDate = now.toLocalDateTime(TimeZone.currentSystemDefault()).date + val subtractedDate = currentDate.minus(number, DateTimeUnit.MONTH) + return subtractedDate.atStartOfDayIn(TimeZone.currentSystemDefault()).toEpochMilliseconds() + } + + fun getDateAsStringFromLong(timeInMillis: Long): String { + return fullMonthFormat.parse(timeInMillis.toString()).toString() + } + + val currentDate = Clock.System.now().toEpochMilliseconds().toString() + val formattedDate = fullMonthFormat.parse(currentDate).toString() +} \ No newline at end of file diff --git a/core/model/src/main/AndroidManifest.xml b/core/model/src/main/AndroidManifest.xml deleted file mode 100644 index 961389810..000000000 --- a/core/model/src/main/AndroidManifest.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - \ No newline at end of file diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/NotificationPayload.kt b/core/model/src/main/java/com/mifospay/core/model/domain/NotificationPayload.kt deleted file mode 100644 index f89982818..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/domain/NotificationPayload.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.domain - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -@Parcelize -data class NotificationPayload( - var title: String? = null, - var body: String? = null, - var timestamp: String? = null, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/SearchResult.kt b/core/model/src/main/java/com/mifospay/core/model/domain/SearchResult.kt deleted file mode 100644 index 94d31b09b..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/domain/SearchResult.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.domain - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -@Parcelize -data class SearchResult( - var resultId: Int = 0, - var resultName: String, - var resultType: String, -) : Parcelable { - constructor() : this(0, "", "") -} diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/Transaction.kt b/core/model/src/main/java/com/mifospay/core/model/domain/Transaction.kt deleted file mode 100644 index 48a73f7f5..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/domain/Transaction.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.domain - -import com.mifospay.core.model.entity.accounts.savings.TransferDetail -import kotlinx.serialization.Serializable - -@Suppress("MaxLineLength") -@Serializable -data class Transaction( - var transactionId: String? = null, - var clientId: Long = 0, - var accountId: Long = 0, - var amount: Double = 0.0, - var date: String? = null, - var currency: Currency = Currency(), - var transactionType: TransactionType = TransactionType.OTHER, - var transferId: Long = 0, - var transferDetail: TransferDetail = TransferDetail(), - var receiptId: String? = null, -) { - constructor() : this( - "", - 0, - 0, - 0.0, - "", - Currency(), - TransactionType.OTHER, - 0, - TransferDetail(), - "", - ) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/domain/twofactor/AccessToken.kt b/core/model/src/main/java/com/mifospay/core/model/domain/twofactor/AccessToken.kt deleted file mode 100644 index 1af3aec06..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/domain/twofactor/AccessToken.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.domain.twofactor - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -@Parcelize -data class AccessToken( - var token: String? = null, - var validFrom: Long? = null, - var validTo: Long? = null, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/Invoice.kt b/core/model/src/main/java/com/mifospay/core/model/entity/Invoice.kt deleted file mode 100644 index 12fd3d9f0..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/Invoice.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize -import kotlinx.parcelize.RawValue - -@Parcelize -data class Invoice( - - @SerializedName("consumerId") - var consumerId: String? = null, - - @SerializedName("consumerName") - var consumerName: String? = null, - - @SerializedName("amount") - var amount: Double = 0.0, - - @SerializedName("itemsBought") - var itemsBought: String? = null, - - @SerializedName("status") - var status: Long = 0L, - - @SerializedName("transactionId") - var transactionId: String? = null, - - @SerializedName("id") - var id: Long = 0L, - - @SerializedName("title") - var title: String? = null, - - @SerializedName("date") - var date: @RawValue MutableList = ArrayList(), - -) : Parcelable { - constructor() : this(null, null, 0.0, null, 0L, null, 0L, null, ArrayList()) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/SearchedEntity.kt b/core/model/src/main/java/com/mifospay/core/model/entity/SearchedEntity.kt deleted file mode 100644 index 6ce6d00a7..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/SearchedEntity.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -@Parcelize -data class SearchedEntity( - var entityId: Int = 0, - var entityAccountNo: String = " ", - var entityName: String = " ", - var entityType: String = " ", - var parentId: Int = 0, - var parentName: String = " ", -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/Timeline.kt b/core/model/src/main/java/com/mifospay/core/model/entity/Timeline.kt deleted file mode 100644 index cbc1e3418..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/Timeline.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity - -import kotlinx.serialization.Serializable - -@Serializable -data class Timeline( - var submittedOnDate: List = ArrayList(), - var submittedByUsername: String? = null, - var submittedByFirstname: String? = null, - var submittedByLastname: String? = null, - var activatedOnDate: List = ArrayList(), - var activatedByUsername: String? = null, - var activatedByFirstname: String? = null, - var activatedByLastname: String? = null, - var closedOnDate: List = ArrayList(), - var closedByUsername: String? = null, - var closedByFirstname: String? = null, - var closedByLastname: String? = null, -) { - constructor() : this(ArrayList(), "", "", "", ArrayList(), "", "", "", ArrayList(), "", "", "") -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Currency.kt b/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Currency.kt deleted file mode 100644 index a6156f0d3..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Currency.kt +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.accounts.savings - -import com.google.gson.annotations.SerializedName -import kotlinx.serialization.Serializable - -@Serializable -data class Currency( - - @SerializedName("code") - var code: String = " ", - - @SerializedName("name") - var name: String = " ", - - @SerializedName("decimalPlaces") - var decimalPlaces: Int? = null, - - @SerializedName("inMultiplesOf") - var inMultiplesOf: Int? = null, - - @SerializedName("displaySymbol") - var displaySymbol: String = " ", - - @SerializedName("nameCode") - var nameCode: String = " ", - - @SerializedName("displayLabel") - var displayLabel: String = " ", - -) { - constructor() : this("", "", 0, 0, "", "", "") -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt b/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt deleted file mode 100644 index 3cca8dfa6..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.accounts.savings - -import com.google.gson.annotations.SerializedName -import kotlinx.serialization.Serializable - -@Serializable -data class PaymentDetailData( - @SerializedName("id") - var id: Int? = null, - - @SerializedName("paymentType") - var paymentType: PaymentType? = null, - - @SerializedName("accountNumber") - var accountNumber: String? = null, - - @SerializedName("checkNumber") - var checkNumber: String? = null, - - @SerializedName("routingCode") - var routingCode: String? = null, - - @SerializedName("receiptNumber") - var receiptNumber: String? = null, - - @SerializedName("bankNumber") - var bankNumber: String? = null, -) { - constructor() : this(null, null, null, null, null, null, null) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/SavingAccount.kt b/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/SavingAccount.kt deleted file mode 100644 index 5d3336b15..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/SavingAccount.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.accounts.savings - -import com.google.gson.annotations.SerializedName -import com.mifospay.core.model.entity.client.DepositType -import kotlinx.serialization.Serializable - -@Serializable -data class SavingAccount( - - @SerializedName("id") - var id: Long = 0L, - - @SerializedName("accountNo") - var accountNo: String = " ", - - @SerializedName("productName") - var productName: String = " ", - - @SerializedName("productId") - var productId: Int = 0, - - @SerializedName("overdraftLimit") - var overdraftLimit: Long = 0L, - - @SerializedName("minRequiredBalance") - var minRequiredBalance: Long = 0L, - - @SerializedName("accountBalance") - var accountBalance: Double = 0.0, - - @SerializedName("totalDeposits") - var totalDeposits: Double = 0.0, - - @SerializedName("savingsProductName") - var savingsProductName: String? = null, - - @SerializedName("clientName") - var clientName: String? = null, - - @SerializedName("savingsProductId") - var savingsProductId: String? = null, - - @SerializedName("nominalAnnualInterestRate") - var nominalAnnualInterestRate: Double = 0.0, - - @SerializedName("status") - var status: Status? = null, - - @SerializedName("currency") - var currency: Currency = Currency(), - - @SerializedName("depositType") - var depositType: DepositType? = null, - -) { - fun isRecurring(): Boolean { - return this.depositType != null && this.depositType!!.isRecurring - } - constructor() : this(0L, "", "", 0, 0L, 0L, 0.0, 0.0, "", "", "", 0.0, Status(), Currency(), DepositType()) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt b/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt deleted file mode 100644 index 5e5304f22..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.accounts.savings - -import com.google.gson.annotations.SerializedName -import com.mifospay.core.model.entity.client.DepositType -import kotlinx.serialization.Serializable - -@Serializable -data class SavingsWithAssociations( - - @SerializedName("id") - var id: Long = 0L, - - @SerializedName("accountNo") - var accountNo: String? = null, - - @SerializedName("depositType") - var depositType: DepositType? = null, - - @SerializedName("externalId") - var externalId: String = " ", - - @SerializedName("clientId") - var clientId: Int = 0, - - @SerializedName("clientName") - var clientName: String = " ", - - @SerializedName("savingsProductId") - var savingsProductId: Int? = null, - - @SerializedName("savingsProductName") - var savingsProductName: String? = null, - - @SerializedName("fieldOfficerId") - var fieldOfficerId: Int? = null, - - @SerializedName("status") - var status: Status? = null, - - @SerializedName("timeline") - var timeline: TimeLine? = null, - - @SerializedName("currency") - var currency: Currency? = null, - - @SerializedName("nominalAnnualInterestRate") - var nominalAnnualInterestRate: Double? = null, - - @SerializedName("minRequiredOpeningBalance") - var minRequiredOpeningBalance: Double? = null, - - @SerializedName("lockinPeriodFrequency") - var lockinPeriodFrequency: Double? = null, - - @SerializedName("withdrawalFeeForTransfers") - var withdrawalFeeForTransfers: Boolean? = null, - - @SerializedName("allowOverdraft") - var allowOverdraft: Boolean? = null, - - @SerializedName("enforceMinRequiredBalance") - var enforceMinRequiredBalance: Boolean? = null, - - @SerializedName("withHoldTax") - var withHoldTax: Boolean? = null, - - @SerializedName("lastActiveTransactionDate") - var lastActiveTransactionDate: List? = null, - - @SerializedName("isDormancyTrackingActive") - var dormancyTrackingActive: Boolean? = null, - - @SerializedName("summary") - var summary: Summary? = null, - - @SerializedName("transactions") - var transactions: List = ArrayList(), - -) { - constructor() : this( - 0L, - null, - null, - " ", - 0, - " ", - null, - null, - 0, - null, - null, - null, - null, - null, - 0.0, - false, - false, - false, - null, - listOf(), - null, - null, - ) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Status.kt b/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Status.kt deleted file mode 100644 index 580034a32..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Status.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.accounts.savings - -import com.google.gson.annotations.SerializedName -import kotlinx.serialization.Serializable - -@Serializable -data class Status( - - @SerializedName("id") - var id: Int? = null, - - @SerializedName("code") - var code: String? = null, - - @SerializedName("value") - var value: String? = null, - - @SerializedName("submittedAndPendingApproval") - var submittedAndPendingApproval: Boolean? = null, - - @SerializedName("approved") - var approved: Boolean? = null, - - @SerializedName("rejected") - var rejected: Boolean? = null, - - @SerializedName("withdrawnByApplicant") - var withdrawnByApplicant: Boolean? = null, - - @SerializedName("active") - var active: Boolean? = null, - - @SerializedName("closed") - var closed: Boolean? = null, - - @SerializedName("prematureClosed") - var prematureClosed: Boolean? = null, - - @SerializedName("transferInProgress") - var transferInProgress: Boolean? = null, - - @SerializedName("transferOnHold") - var transferOnHold: Boolean? = null, - - @SerializedName("matured") - var matured: Boolean? = null, -) { - constructor() : this( - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - null, - ) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Summary.kt b/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Summary.kt deleted file mode 100644 index 4107908ab..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Summary.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.accounts.savings - -import com.google.gson.annotations.SerializedName -import kotlinx.serialization.Serializable - -@Serializable -data class Summary( - @SerializedName("currency") - var currency: Currency? = null, - - @SerializedName("totalDeposits") - var totalDeposits: Double? = null, - - @SerializedName("totalWithdrawals") - var totalWithdrawals: Double? = null, - - @SerializedName("totalInterestEarned") - var totalInterestEarned: Double? = null, - - @SerializedName("totalInterestPosted") - var totalInterestPosted: Double? = null, - - @SerializedName("accountBalance") - var accountBalance: Double? = null, - - @SerializedName("totalOverdraftInterestDerived") - var totalOverdraftInterestDerived: Double? = null, - - @SerializedName("interestNotPosted") - var interestNotPosted: Double? = null, - - @SerializedName("lastInterestCalculationDate") - var lastInterestCalculationDate: List? = null, -) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TimeLine.kt b/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TimeLine.kt deleted file mode 100644 index 033935f16..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TimeLine.kt +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.accounts.savings - -import com.google.gson.annotations.SerializedName -import kotlinx.serialization.Serializable - -@Serializable -data class TimeLine( - @SerializedName("submittedOnDate") - var submittedOnDate: List = ArrayList(), - - @SerializedName("submittedByUsername") - var submittedByUsername: String? = null, - - @SerializedName("submittedByFirstname") - var submittedByFirstname: String? = null, - - @SerializedName("submittedByLastname") - var submittedByLastname: String? = null, - - @SerializedName("approvedOnDate") - var approvedOnDate: List = ArrayList(), - - @SerializedName("approvedByUsername") - var approvedByUsername: String? = null, - - @SerializedName("approvedByFirstname") - var approvedByFirstname: String? = null, - - @SerializedName("approvedByLastname") - var approvedByLastname: String? = null, - - @SerializedName("activatedOnDate") - var activatedOnDate: List? = null, - - @SerializedName("activatedByUsername") - var activatedByUsername: String? = null, - - @SerializedName("activatedByFirstname") - var activatedByFirstname: String? = null, - - @SerializedName("activatedByLastname") - var activatedByLastname: String? = null, -) { - constructor() : this( - ArrayList(), - null, - null, - null, - ArrayList(), - null, - null, - null, - null, - null, - null, - null, - ) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TransactionType.kt b/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TransactionType.kt deleted file mode 100644 index 886a5492c..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TransactionType.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.accounts.savings - -import com.google.gson.annotations.SerializedName -import kotlinx.serialization.Serializable - -@Serializable -data class TransactionType( - @SerializedName("id") - var id: Int? = null, - - @SerializedName("code") - var code: String? = null, - - @SerializedName("value") - var value: String? = null, - - @JvmField - @SerializedName("deposit") - var deposit: Boolean = false, - - @SerializedName("dividendPayout") - var dividendPayout: Boolean = false, - - @JvmField - @SerializedName("withdrawal") - var withdrawal: Boolean = false, - - @SerializedName("interestPosting") - var interestPosting: Boolean = false, - - @SerializedName("feeDeduction") - var feeDeduction: Boolean = false, - - @SerializedName("initiateTransfer") - var initiateTransfer: Boolean = false, - - @SerializedName("approveTransfer") - var approveTransfer: Boolean = false, - - @SerializedName("withdrawTransfer") - var withdrawTransfer: Boolean = false, - - @SerializedName("rejectTransfer") - var rejectTransfer: Boolean = false, - - @SerializedName("overdraftInterest") - var overdraftInterest: Boolean = false, - - @SerializedName("writtenoff") - var writtenoff: Boolean = false, - - @SerializedName("overdraftFee") - var overdraftFee: Boolean = false, - - @SerializedName("withholdTax") - var withholdTax: Boolean = false, - - @SerializedName("escheat") - var escheat: Boolean? = null, -) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Transactions.kt b/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Transactions.kt deleted file mode 100644 index b5d7dab26..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/Transactions.kt +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.accounts.savings - -import com.google.gson.annotations.SerializedName -import kotlinx.serialization.Serializable - -@Serializable -data class Transactions( - - @SerializedName("id") - var id: Int? = null, - - @SerializedName("transactionType") - var transactionType: TransactionType = TransactionType(), - - @SerializedName("accountId") - var accountId: Int? = null, - - @SerializedName("accountNo") - var accountNo: String? = null, - - @SerializedName("date") - var date: List = ArrayList(), - - @SerializedName("currency") - var currency: Currency = Currency(), - - @SerializedName("paymentDetailData") - var paymentDetailData: PaymentDetailData? = null, - - @SerializedName("amount") - var amount: Double = 0.0, - - @SerializedName("transfer") - var transfer: Transfer = Transfer(), - - @SerializedName("runningBalance") - var runningBalance: Double? = null, - - @SerializedName("reversed") - var reversed: Boolean? = null, - - @SerializedName("submittedOnDate") - var submittedOnDate: List = ArrayList(), - - @SerializedName("interestedPostedAsOn") - var interestedPostedAsOn: Boolean? = null, -) { - constructor() : this( - 0, - TransactionType(), - 0, - "", - ArrayList(), - Currency(), - PaymentDetailData(), - 0.0, - Transfer(), - 0.0, - false, - ArrayList(), - false, - ) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TransferDetail.kt b/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TransferDetail.kt deleted file mode 100644 index 57c156b6a..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/accounts/savings/TransferDetail.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.accounts.savings - -import com.google.gson.annotations.SerializedName -import kotlinx.serialization.Serializable - -@Serializable -data class TransferDetail( - @SerializedName("id") - var id: Long = 0L, - - @SerializedName("fromClient") - var fromClient: com.mifospay.core.model.domain.client.Client = com.mifospay.core.model.domain.client.Client(), - - @SerializedName("fromAccount") - var fromAccount: SavingAccount = SavingAccount(), - - @SerializedName("toClient") - var toClient: com.mifospay.core.model.domain.client.Client = com.mifospay.core.model.domain.client.Client(), - - @SerializedName("toAccount") - var toAccount: SavingAccount = SavingAccount(), -) { - constructor() : this( - 0L, - com.mifospay.core.model.domain.client.Client(), - SavingAccount(), - com.mifospay.core.model.domain.client.Client(), - SavingAccount(), - ) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/authentication/AuthenticationPayload.kt b/core/model/src/main/java/com/mifospay/core/model/entity/authentication/AuthenticationPayload.kt deleted file mode 100644 index 5fbda092e..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/authentication/AuthenticationPayload.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.authentication - -import com.google.gson.annotations.SerializedName -import kotlinx.serialization.Serializable - -// @Parcelize -// class AuthenticationPayload( -// @SerializedName("username") -// val userName: String, -// @SerializedName("password") -// val password: String, -// ) : Parcelable - -@Serializable -data class AuthenticationPayload( - @SerializedName("username") - val username: String, - @SerializedName("password") - val password: String, -) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/beneficary/Beneficiary.kt b/core/model/src/main/java/com/mifospay/core/model/entity/beneficary/Beneficiary.kt deleted file mode 100644 index 4e7fe3b95..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/beneficary/Beneficiary.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.beneficary - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import com.mifospay.core.model.entity.templates.account.AccountType -import kotlinx.parcelize.Parcelize - -@Parcelize -data class Beneficiary( - - @SerializedName("id") - var id: Int? = null, - - @SerializedName("name") - var name: String? = null, - - @SerializedName("officeName") - var officeName: String? = null, - - @SerializedName("clientName") - var clientName: String? = null, - - @SerializedName("accountType") - var accountType: AccountType? = null, - - @SerializedName("accountNumber") - var accountNumber: String? = null, - - @SerializedName("transferLimit") - var transferLimit: Int = 0, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt b/core/model/src/main/java/com/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt deleted file mode 100644 index 4fa428cd2..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.beneficary - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class BeneficiaryPayload( - var locale: String? = "en_GB", - - @SerializedName("name") - var name: String? = null, - - @SerializedName("accountNumber") - var accountNumber: String? = null, - - @SerializedName("accountType") - var accountType: Int = 0, - - @SerializedName("transferLimit") - var transferLimit: Int = 0, - - @SerializedName("officeName") - var officeName: String? = null, -) : Parcelable { - constructor() : this(null, null, null, 0, 0, null) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/client/Client.kt b/core/model/src/main/java/com/mifospay/core/model/entity/client/Client.kt deleted file mode 100644 index 621915b64..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/client/Client.kt +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.client - -import com.google.gson.annotations.SerializedName -import com.mifospay.core.model.entity.Timeline -import kotlinx.serialization.Serializable - -@Serializable -data class Client( - - @SerializedName("id") - var id: Int = 0, - - @SerializedName("accountNo") - var accountNo: String? = null, - - @SerializedName("status") - private var status: Status? = null, - - @SerializedName("active") - private var active: Boolean? = null, - - @SerializedName("activationDate") - var activationDate: List = ArrayList(), - - @SerializedName("dobDate") - var dobDate: List = ArrayList(), - - @SerializedName("firstname") - var firstname: String? = null, - - @SerializedName("middlename") - var middlename: String? = null, - - @SerializedName("lastname") - var lastname: String? = null, - - @SerializedName("displayName") - var displayName: String? = null, - - @SerializedName("fullname") - var fullname: String? = null, - - @SerializedName("officeId") - var officeId: Int = 0, - - @SerializedName("officeName") - var officeName: String? = null, - - @SerializedName("staffId") - private var staffId: Int? = null, - - @SerializedName("staffName") - private var staffName: String? = null, - - @SerializedName("timeline") - private var timeline: Timeline? = null, - - @SerializedName("imageId") - var imageId: Int = 0, - - @SerializedName("imagePresent") - var isImagePresent: Boolean = false, - - @SerializedName("externalId") - var externalId: String = "", - - @SerializedName("mobileNo") - var mobileNo: String = "", -) { - constructor() : this( - 0, - "", - Status(), - false, - ArrayList(), - ArrayList(), - "", - "", - "", - "", - "", - 0, - "", - 0, - "", - Timeline(), - 0, - false, - "", - "", - ) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/client/Currency.kt b/core/model/src/main/java/com/mifospay/core/model/entity/client/Currency.kt deleted file mode 100644 index 7ebf60fb1..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/client/Currency.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.client - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class Currency( - @SerializedName("code") - var code: String? = null, - - @SerializedName("name") - var name: String? = null, - - @SerializedName("decimalPlaces") - var decimalPlaces: Int? = null, - - @SerializedName("displaySymbol") - var displaySymbol: String? = null, - - @SerializedName("nameCode") - var nameCode: String? = null, - - @SerializedName("displayLabel") - var displayLabel: String? = null, -) : Parcelable { - constructor() : this(null, null, null, null, null, null) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/client/Status.kt b/core/model/src/main/java/com/mifospay/core/model/entity/client/Status.kt deleted file mode 100644 index a8d079182..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/client/Status.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.client - -import com.google.gson.annotations.SerializedName -import kotlinx.serialization.Serializable - -@Serializable -data class Status( - @SerializedName("id") - var id: Int? = null, - - @SerializedName("code") - var code: String? = null, - - @SerializedName("value") - var value: String? = null, -) { - constructor() : this(null, null, null) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/client/Type.kt b/core/model/src/main/java/com/mifospay/core/model/entity/client/Type.kt deleted file mode 100644 index e30c7e3fe..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/client/Type.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.client - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class Type( - @SerializedName("id") - var id: Int? = null, - - @SerializedName("code") - var code: String? = null, - - @SerializedName("value") - var value: String? = null, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/kyc/KYCLevel1Details.kt b/core/model/src/main/java/com/mifospay/core/model/entity/kyc/KYCLevel1Details.kt deleted file mode 100644 index 507dd276a..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/kyc/KYCLevel1Details.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.kyc - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class KYCLevel1Details( - @SerializedName("firstName") - var firstName: String? = null, - - @SerializedName("lastName") - var lastName: String? = null, - - @SerializedName("addressLine1") - var addressLine1: String? = null, - - @SerializedName("addressLine2") - var addressLine2: String? = null, - - @SerializedName("mobileNo") - var mobileNo: String? = null, - - @SerializedName("dob") - var dob: String? = null, - - @SerializedName("currentLevel") - var currentLevel: String = " ", -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/noncore/Document.kt b/core/model/src/main/java/com/mifospay/core/model/entity/noncore/Document.kt deleted file mode 100644 index eb371c4da..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/noncore/Document.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.noncore - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -@Parcelize -data class Document( - var id: Int = 0, - var parentEntityType: String? = null, - var parentEntityId: Int = 0, - var name: String? = null, - var fileName: String? = null, - var size: Long = 0, - var type: String? = null, - var description: String? = null, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/payload/ClientPayload.kt b/core/model/src/main/java/com/mifospay/core/model/entity/payload/ClientPayload.kt deleted file mode 100644 index 0fc7e0b7d..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/payload/ClientPayload.kt +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.payload - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class ClientPayload( - @SerializedName("firstname") - var firstname: String? = null, - - @SerializedName("lastname") - var lastname: String? = null, - - @SerializedName("middlename") - var middlename: String? = null, - - @SerializedName("officeId") - var officeId: Int? = null, - - @SerializedName("staffId") - var staffId: Int? = null, - - @SerializedName("genderId") - var genderId: Int? = null, - - @SerializedName("active") - var active: Boolean? = null, - - @SerializedName("activationDate") - var activationDate: String? = null, - - @SerializedName("submittedOnDate") - var submittedOnDate: String? = null, - - @SerializedName("dateOfBirth") - var dateOfBirth: String? = null, - - @SerializedName("mobileNo") - var mobileNo: String? = null, - - @SerializedName("externalId") - var externalId: String? = null, - - @SerializedName("clientTypeId") - var clientTypeId: Int? = null, - - @SerializedName("clientClassificationId") - var clientClassificationId: Int? = null, - - @SerializedName("dateFormat") - var dateFormat: String? = "DD_MMMM_YYYY", - - @SerializedName("locale") - var locale: String? = "en", - - @SerializedName("datatables") - var datatables: List = ArrayList(), -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/payload/DataTablePayload.kt b/core/model/src/main/java/com/mifospay/core/model/entity/payload/DataTablePayload.kt deleted file mode 100644 index e7d62cc13..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/payload/DataTablePayload.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.payload - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize -import kotlinx.parcelize.RawValue - -@Parcelize -data class DataTablePayload( - @Transient - var id: Int? = null, - - @Transient - var clientCreationTime: Long? = null, - - @Transient - var dataTableString: String? = null, - var registeredTableName: String? = null, - var applicationTableName: String? = null, - var data: @RawValue HashMap? = null, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/payload/TransferPayload.kt b/core/model/src/main/java/com/mifospay/core/model/entity/payload/TransferPayload.kt deleted file mode 100644 index a6194e91c..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/payload/TransferPayload.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.payload - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class TransferPayload( - @SerializedName("fromOfficeId") - var fromOfficeId: Int? = null, - - @SerializedName("fromClientId") - var fromClientId: Long? = null, - - @SerializedName("fromAccountType") - var fromAccountType: Int? = null, - - @SerializedName("fromAccountId") - var fromAccountId: Int? = null, - - @SerializedName("toOfficeId") - var toOfficeId: Int? = null, - - @SerializedName("toClientId") - var toClientId: Long? = null, - - @SerializedName("toAccountType") - var toAccountType: Int? = null, - - @SerializedName("toAccountId") - var toAccountId: Int? = null, - - @SerializedName("transferDate") - var transferDate: String? = null, - - @SerializedName("transferAmount") - var transferAmount: Double? = null, - - @SerializedName("transferDescription") - var transferDescription: String? = null, - var dateFormat: String? = "dd MMMM yyyy", - var locale: String? = "en", -) : Parcelable { - constructor() : this(null, null, null, null, null, null, null, null, null, null, null) -} diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/register/RegisterPayload.kt b/core/model/src/main/java/com/mifospay/core/model/entity/register/RegisterPayload.kt deleted file mode 100644 index 80ed5ffb7..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/register/RegisterPayload.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.register - -import com.google.gson.annotations.SerializedName - -data class RegisterPayload( - @SerializedName("username") - var username: String? = null, - - @SerializedName("firstName") - var firstName: String? = null, - - @SerializedName("lastName") - var lastName: String? = null, - - @SerializedName("email") - var email: String? = null, - - @SerializedName("mobileNumber") - var mobileNumber: String? = null, - - @SerializedName("accountNumber") - var accountNumber: String? = null, - - @SerializedName("password") - var password: String? = null, - - @SerializedName("authenticationMode") - var authenticationMode: String? = null, -) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/register/UserVerify.kt b/core/model/src/main/java/com/mifospay/core/model/entity/register/UserVerify.kt deleted file mode 100644 index 3fee2f9de..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/register/UserVerify.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.register - -import com.google.gson.annotations.SerializedName - -data class UserVerify( - @SerializedName("requestId") - var requestId: String? = null, - - @SerializedName("authenticationToken") - var authenticationToken: String? = null, -) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/savedcards/Card.kt b/core/model/src/main/java/com/mifospay/core/model/entity/savedcards/Card.kt deleted file mode 100644 index 25d08479e..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/savedcards/Card.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.savedcards - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class Card( - @SerializedName("cardNumber") - var cardNumber: String = " ", - - @SerializedName("cvv") - var cvv: String = " ", - - @SerializedName("expiryDate") - var expiryDate: String = " ", - - @SerializedName("firstName") - var firstName: String = " ", - - @SerializedName("lastName") - var lastName: String = " ", - - @SerializedName("id") - var id: Int = 0, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/standinginstruction/SDIResponse.kt b/core/model/src/main/java/com/mifospay/core/model/entity/standinginstruction/SDIResponse.kt deleted file mode 100644 index f3a320406..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/standinginstruction/SDIResponse.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.standinginstruction - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -@Parcelize -data class SDIResponse(val clientId: Int, val resourceId: String?) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt b/core/model/src/main/java/com/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt deleted file mode 100644 index 84242a7f4..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.standinginstruction - -import com.google.gson.annotations.SerializedName -import com.mifospay.core.model.entity.accounts.savings.SavingAccount -import com.mifospay.core.model.entity.client.Client -import com.mifospay.core.model.entity.client.Status -import kotlinx.serialization.Serializable - -@Serializable -data class StandingInstruction( - - val id: Long, - - @SerializedName("name") - val name: String, - - @SerializedName("fromClient") - val fromClient: Client, - - @SerializedName("fromAccount") - val fromAccount: SavingAccount, - - @SerializedName("toClient") - val toClient: Client, - - @SerializedName("toAccount") - val toAccount: SavingAccount, - - @SerializedName("status") - val status: Status, - - @SerializedName("amount") - var amount: Double, - - @SerializedName("validFrom") - val validFrom: List, - - @SerializedName("validTill") - var validTill: List?, - - @SerializedName("recurrenceInterval") - var recurrenceInterval: Int, - - @SerializedName("recurrenceOnMonthDay") - val recurrenceOnMonthDay: List, -) diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountOption.kt b/core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountOption.kt deleted file mode 100644 index ca3e6434b..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountOption.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.templates.account - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class AccountOption( - - @SerializedName("accountId") - var accountId: Int? = null, - - @SerializedName("accountNo") - var accountNo: String? = null, - - @SerializedName("accountType") - var accountType: AccountType? = null, - - @SerializedName("clientId") - var clientId: Long? = null, - - @SerializedName("clientName") - var clientName: String? = null, - - @SerializedName("officeId") - var officeId: Int? = null, - - @SerializedName("officeName") - var officeName: String? = null, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt b/core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt deleted file mode 100644 index 6f6e068a3..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.templates.account - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class AccountOptionsTemplate( - var fromAccountOptions: List? = ArrayList(), - - @SerializedName("toAccountOptions") - var toAccountOptions: List? = ArrayList(), -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountType.kt b/core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountType.kt deleted file mode 100644 index 0df94a88d..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/templates/account/AccountType.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.templates.account - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class AccountType( - @SerializedName("id") - var id: Int? = null, - - @SerializedName("code") - var code: String? = null, - - @SerializedName("value") - var value: String? = null, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt b/core/model/src/main/java/com/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt deleted file mode 100644 index 54467b5fa..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.templates.beneficiary - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class AccountTypeOption( - @SerializedName("id") - var id: Int? = null, - - @SerializedName("code") - var code: String? = null, - - @SerializedName("value") - var value: String? = null, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt b/core/model/src/main/java/com/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt deleted file mode 100644 index 4468f9756..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.entity.templates.beneficiary - -import android.os.Parcelable -import com.google.gson.annotations.SerializedName -import kotlinx.parcelize.Parcelize - -@Parcelize -data class BeneficiaryTemplate( - @SerializedName("accountTypeOptions") - var accountTypeOptions: List? = null, -) : Parcelable diff --git a/core/model/src/main/java/com/mifospay/core/model/utils/DateHelper.kt b/core/model/src/main/java/com/mifospay/core/model/utils/DateHelper.kt deleted file mode 100644 index da39fd6ab..000000000 --- a/core/model/src/main/java/com/mifospay/core/model/utils/DateHelper.kt +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package com.mifospay.core.model.utils - -import android.util.Log -import java.text.ParseException -import java.text.SimpleDateFormat -import java.util.Calendar -import java.util.Date -import java.util.Locale - -object DateHelper { - private val LOG_TAG = DateHelper::class.java.simpleName - private const val DD_MMM_YYYY = "dd MMM yyyy" - private const val DD_MM_YYYY = "dd-MM-yyyy" - - /** - * the result string uses the list given in a reverse order ([x, y, z] results in "z y x") - * - * @param integersOfDate [year-month-day] (ex [2016, 4, 14]) - * @return date in the format day month year (ex 14 Apr 2016) - */ - - @JvmStatic - fun getDateAsString(integersOfDate: List): String { - val stringBuilder = StringBuilder() - stringBuilder.append(integersOfDate[2]) - .append(' ') - .append(getMonthName(integersOfDate[1])) - .append(' ') - .append(integersOfDate[0]) - return stringBuilder.toString() - } - - fun getDateAsString(integersOfDate: List, pattern: String?): String { - return getFormatConverter( - DD_MMM_YYYY, - pattern, - getDateAsString(integersOfDate), - ) - } - - /** - * This Method converting the dd-MM-yyyy format type date string into dd MMMM yyyy - * - * @param format Final Format of date string - * @param dateString date string - * @return dd MMMM yyyy format date string. - */ - fun getSpecificFormat(format: String, dateString: String): String { - val pickerFormat = SimpleDateFormat(DD_MM_YYYY, Locale.ENGLISH) - val finalFormat = SimpleDateFormat(format, Locale.ENGLISH) - var date: Date? = null - try { - date = pickerFormat.parse(dateString) - } catch (e: ParseException) { - Log.d(LOG_TAG, e.message.toString()) - } - return finalFormat.format(date) - } - - fun getFormatConverter( - currentFormat: String?, - requiredFormat: String?, - dateString: String?, - ): String { - val pickerFormat = SimpleDateFormat(currentFormat, Locale.ENGLISH) - val finalFormat = SimpleDateFormat(requiredFormat, Locale.ENGLISH) - var date: Date? = null - try { - date = pickerFormat.parse(dateString) - } catch (e: ParseException) { - Log.d(LOG_TAG, e.localizedMessage) - } - return finalFormat.format(date) - } - - /** - * @param month an integer from 1 to 12 - * @return string representation of the month like Jan or Feb..etc - */ - private fun getMonthName(month: Int): String { - var monthName = "" - when (month) { - 1 -> monthName = "Jan" - 2 -> monthName = "Feb" - 3 -> monthName = "Mar" - 4 -> monthName = "Apr" - 5 -> monthName = "May" - 6 -> monthName = "Jun" - 7 -> monthName = "Jul" - 8 -> monthName = "Aug" - 9 -> monthName = "Sep" - 10 -> monthName = "Oct" - 11 -> monthName = "Nov" - 12 -> monthName = "Dec" - } - return monthName - } - - private fun getDateAsLongFromString(dateStr: String?, pattern: String?): Long { - val sdf = SimpleDateFormat(pattern, Locale.getDefault()) - var date: Date? = null - try { - date = sdf.parse(dateStr) - } catch (e: ParseException) { - Log.d("TAG", e.message!!) - } - return date!!.time - } - - fun getDateAsLongFromList(integersOfDate: List): Long { - val dateStr = getDateAsString(integersOfDate) - return getDateAsLongFromString(dateStr, DD_MMM_YYYY) - } - - fun subtractWeeks(number: Int): Long { - val calendar = Calendar.getInstance() - calendar.add(Calendar.WEEK_OF_YEAR, -number) - return calendar.timeInMillis - } - - fun subtractMonths(number: Int): Long { - val calendar = Calendar.getInstance() - calendar.add(Calendar.MONTH, -number) - return calendar.timeInMillis - } - - @JvmStatic - fun getDateAsStringFromLong(timeInMillis: Long): String { - val sdf = SimpleDateFormat(DD_MMM_YYYY, Locale.getDefault()) - return sdf.format(Date(timeInMillis)) - } -} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt index 351a54ba9..d884d5157 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt @@ -9,9 +9,9 @@ */ package org.mifospay.core.network.localAssets -import com.mifospay.core.model.City -import com.mifospay.core.model.Country -import com.mifospay.core.model.State +import org.mifospay.core.model.City +import org.mifospay.core.model.Country +import org.mifospay.core.model.State interface LocalAssetDataSource { diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt index 1bb530e4d..f14662124 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt @@ -9,9 +9,9 @@ */ package org.mifospay.core.network.localAssets -import com.mifospay.core.model.City -import com.mifospay.core.model.Country -import com.mifospay.core.model.State +import org.mifospay.core.model.City +import org.mifospay.core.model.Country +import org.mifospay.core.model.State import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt index e9b074a1a..198e3bcd4 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt @@ -10,7 +10,7 @@ package org.mifospay.core.network.services import com.mifospay.core.model.entity.beneficary.Beneficiary -import com.mifospay.core.model.entity.beneficary.BeneficiaryPayload +import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload import com.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload import com.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate import okhttp3.ResponseBody @@ -34,7 +34,7 @@ interface BeneficiaryService { val beneficiaryTemplate: Observable @POST(ApiEndPoints.BENEFICIARIES + "/tpt") - fun createBeneficiary(@Body beneficiaryPayload: BeneficiaryPayload): Observable + fun createBeneficiary(@Body beneficiaryPayload: org.mifospay.core.model.entity.beneficary.BeneficiaryPayload): Observable @PUT(ApiEndPoints.BENEFICIARIES + "/tpt/{beneficiaryId}") fun updateBeneficiary( diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt index 444b72cb6..1066b8e7e 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt @@ -9,7 +9,7 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.entity.kyc.KYCLevel1Details +import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.GenericResponse import retrofit2.http.Body @@ -23,15 +23,15 @@ interface KYCLevel1Service { @POST(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}") fun addKYCLevel1Details( @Path("clientId") clientId: Int, - @Body kycLevel1Details: KYCLevel1Details, + @Body kycLevel1Details: org.mifospay.core.model.entity.kyc.KYCLevel1Details, ): Observable @GET(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}") - fun fetchKYCLevel1Details(@Path("clientId") clientId: Int): Observable> + fun fetchKYCLevel1Details(@Path("clientId") clientId: Int): Observable> @PUT(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}/") fun updateKYCLevel1Details( @Path("clientId") clientId: Int, - @Body kycLevel1Details: KYCLevel1Details, + @Body kycLevel1Details: org.mifospay.core.model.entity.kyc.KYCLevel1Details, ): Observable } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt index 2e6d73f6d..a05074da1 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt @@ -11,7 +11,7 @@ package org.mifospay.core.network.services import com.mifospay.core.model.entity.TPTResponse import com.mifospay.core.model.entity.payload.TransferPayload -import com.mifospay.core.model.entity.templates.account.AccountOptionsTemplate +import org.mifospay.core.model.entity.templates.account.AccountOptionsTemplate import org.mifospay.core.network.ApiEndPoints import retrofit2.http.Body import retrofit2.http.GET @@ -23,7 +23,7 @@ import rx.Observable */ interface ThirdPartyTransferService { @get:GET(ApiEndPoints.ACCOUNT_TRANSFER + "/template?type=tpt") - val accountTransferTemplate: Observable + val accountTransferTemplate: Observable @POST(ApiEndPoints.ACCOUNT_TRANSFER + "?type=\"tpt\"") fun makeTransfer(@Body transferPayload: TransferPayload): Observable diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt index 8a4b53ec4..968c5a6b9 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt @@ -10,7 +10,7 @@ package org.mifospay.core.network.services import com.mifospay.core.model.domain.twofactor.AccessToken -import com.mifospay.core.model.domain.twofactor.DeliveryMethod +import org.mifospay.core.model.domain.twofactor.DeliveryMethod import org.mifospay.core.network.ApiEndPoints import retrofit2.http.GET import retrofit2.http.POST @@ -22,7 +22,7 @@ import rx.Observable */ interface TwoFactorAuthService { @get:GET(ApiEndPoints.TWOFACTOR) - val deliveryMethods: Observable> + val deliveryMethods: Observable> @POST(ApiEndPoints.TWOFACTOR) fun requestOTP(@Query("deliveryMethod") deliveryMethod: String): Observable diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt index d52642be0..91525c17a 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt @@ -43,7 +43,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.mifospay.core.model.State +import org.mifospay.core.model.State import com.mifospay.core.model.signup.PasswordStrength import com.mifospay.core.model.signup.SignupData import org.koin.androidx.compose.koinViewModel diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt index c9e3aeb77..4fd21843f 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt @@ -14,7 +14,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.mifospay.core.model.State +import org.mifospay.core.model.State import com.mifospay.core.model.domain.user.NewUser import com.mifospay.core.model.domain.user.UpdateUserEntityClients import com.mifospay.core.model.domain.user.User diff --git a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt index 5abca0b6d..5655614e6 100644 --- a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt +++ b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt @@ -37,7 +37,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifospay.core.model.entity.Invoice -import com.mifospay.core.model.utils.DateHelper +import org.mifospay.core.model.utils.DateHelper import org.koin.androidx.compose.koinViewModel import org.mifospay.common.Constants import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel @@ -263,7 +263,7 @@ private fun InvoiceDetailsContent( modifier = Modifier.padding(top = 10.dp), ) Text( - text = DateHelper.getDateAsString(invoice!!.date), + text = org.mifospay.core.model.utils.DateHelper.getDateAsString(invoice!!.date), modifier = Modifier.padding(top = 10.dp), ) } diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt index b8d30baad..45db65ee7 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt @@ -45,7 +45,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifos.library.pullrefresh.PullRefreshIndicator import com.mifos.library.pullrefresh.pullRefresh import com.mifos.library.pullrefresh.rememberPullRefreshState -import com.mifospay.core.model.entity.kyc.KYCLevel1Details +import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosOverlayLoadingWheel @@ -137,7 +137,7 @@ private fun KYCDescriptionScreen( @Composable private fun KYCDescriptionScreen( - kyc: KYCLevel1Details, + kyc: org.mifospay.core.model.entity.kyc.KYCLevel1Details, onLevel1Clicked: () -> Unit, onLevel2Clicked: () -> Unit, onLevel3Clicked: () -> Unit, @@ -285,7 +285,7 @@ private fun KYCDescriptionPreview() { val onLevel2Clicked: () -> Unit = { } val onLevel3Clicked: () -> Unit = { } KYCDescriptionScreen( - kyc = KYCLevel1Details(), + kyc = org.mifospay.core.model.entity.kyc.KYCLevel1Details(), onLevel1Clicked, onLevel2Clicked, onLevel3Clicked, @@ -298,22 +298,22 @@ internal class KYCDescriptionUiStatePreviewProvider : KYCDescriptionUiState.Loading, KYCDescriptionUiState.Error, KYCDescriptionUiState.KYCDescription( - KYCLevel1Details().apply { + org.mifospay.core.model.entity.kyc.KYCLevel1Details().apply { currentLevel = "0" }, ), KYCDescriptionUiState.KYCDescription( - KYCLevel1Details().apply { + org.mifospay.core.model.entity.kyc.KYCLevel1Details().apply { currentLevel = "1" }, ), KYCDescriptionUiState.KYCDescription( - KYCLevel1Details().apply { + org.mifospay.core.model.entity.kyc.KYCLevel1Details().apply { currentLevel = "2" }, ), KYCDescriptionUiState.KYCDescription( - KYCLevel1Details().apply { + org.mifospay.core.model.entity.kyc.KYCLevel1Details().apply { currentLevel = "3" }, ), diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt index a2f9fd98b..2fafcf592 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt @@ -11,7 +11,7 @@ package org.mifospay.feature.kyc import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.mifospay.core.model.entity.kyc.KYCLevel1Details +import org.mifospay.core.model.entity.kyc.KYCLevel1Details import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -74,7 +74,7 @@ class KYCDescriptionViewModel( } sealed interface KYCDescriptionUiState { - data class KYCDescription(val kycLevel1Details: KYCLevel1Details?) : KYCDescriptionUiState + data class KYCDescription(val kycLevel1Details: org.mifospay.core.model.entity.kyc.KYCLevel1Details?) : KYCDescriptionUiState data object Error : KYCDescriptionUiState data object Loading : KYCDescriptionUiState } diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt index 3e7f282d1..e55a6d61b 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt @@ -10,7 +10,7 @@ package org.mifospay.feature.kyc import androidx.lifecycle.ViewModel -import com.mifospay.core.model.entity.kyc.KYCLevel1Details +import org.mifospay.core.model.entity.kyc.KYCLevel1Details import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCase @@ -72,8 +72,8 @@ data class KYCLevel1DetailsState( val currentLevel: String = "1", ) -internal fun KYCLevel1DetailsState.toModel(): KYCLevel1Details { - return KYCLevel1Details( +internal fun KYCLevel1DetailsState.toModel(): org.mifospay.core.model.entity.kyc.KYCLevel1Details { + return org.mifospay.core.model.entity.kyc.KYCLevel1Details( firstName = firstName.trim(), lastName = lastName.trim(), addressLine1 = addressLine1.trim(), diff --git a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileViewModel.kt b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileViewModel.kt index 2e2cac8e1..f621ef4e4 100644 --- a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileViewModel.kt +++ b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/edit/EditProfileViewModel.kt @@ -81,7 +81,7 @@ class EditProfileViewModel( mUseCaseHandler.execute( updateClientUseCase, UpdateClient.RequestValues( - com.mifospay.core.model.domain.client.UpdateClientEntityMobile( + org.mifospay.core.model.domain.client.UpdateClientEntityMobile( fullNumber!!, ), mPreferencesHelper.clientId.toInt().toLong(), diff --git a/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt b/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt index 35ddb856e..165bf0451 100644 --- a/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt +++ b/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt @@ -11,7 +11,7 @@ package org.mifospay import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.mifospay.core.model.UserData +import org.mifospay.core.model.UserData import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map From d6623f83493a81afee0ddbd5dd4a59ac0deb901d Mon Sep 17 00:00:00 2001 From: Sk Niyaj Ali Date: Thu, 26 Sep 2024 20:46:55 +0530 Subject: [PATCH 03/31] Feat: [:core:common] KMP Migration (#1768) * Feat: [:core:common] KMP Migration * Updated Usage Declaration --- core/common/build.gradle.kts | 17 ++++++++ .../kotlin/org/mifospay/common/DebugUtil.kt | 26 ------------- .../kotlin/org/mifospay/common/FileUtils.kt | 36 ----------------- .../kotlin/org/mifospay/common/Utils.kt | 34 ---------------- .../mifospay/core/common/FileUtils.android.kt | 5 +++ .../org/mifospay/core/common/Utils.android.kt | 17 ++++++++ .../core/network/di/CoroutineScopesModule.kt | 23 ----------- .../org/mifospay/core}/common/Constants.kt | 2 +- .../mifospay/core}/common/CreditCardUtils.kt | 2 +- .../org/mifospay/core/common/DebugUtil.kt | 23 +++++++++++ .../org/mifospay/core/common/FileUtils.kt | 39 +++++++++++++++++++ .../mifospay/core/common}/MifosDispatchers.kt | 2 +- .../mifospay/core}/common/NavArgsConstants.kt | 2 +- .../kotlin/org/mifospay/core/common/Utils.kt | 9 +++++ .../core/common}/di/DispatchersModule.kt | 10 ++++- .../org/mifospay/core/common/FileUtils.jvm.kt | 5 +++ .../org/mifospay/core/common/Utils.jvm.kt | 17 ++++++++ .../mifospay/core/common/FileUtils.native.kt | 24 ++++++++++++ .../org/mifospay/core/common/Utils.native.kt | 17 ++++++++ .../navigation/BankAccountDetailNavigation.kt | 2 +- .../mobileVerify/MobileVerificationScreen.kt | 2 +- .../MobileVerificationScreenNavigation.kt | 2 +- .../feature/auth/signup/SignupViewModel.kt | 4 +- .../socialSignup/SocialSignupMethodScreen.kt | 2 +- .../editpassword/EditPasswordViewModel.kt | 2 +- .../SpecificTransactionsViewModel.kt | 6 +-- .../detail/TransactionDetailScreen.kt | 2 +- .../org/mifospay/feature/home/HomeScreen.kt | 10 +++-- .../feature/invoices/InvoiceDetailScreen.kt | 2 +- .../feature/invoices/InvoicesViewModel.kt | 2 +- .../feature/kyc/KYCLevel2ViewModel.kt | 2 +- .../make/transfer/MakeTransferScreen.kt | 2 +- .../make/transfer/MakeTransferViewModel.kt | 4 +- .../navigation/MakeTransferNavigation.kt | 16 ++++---- .../merchants/MerchantTransferViewModel.kt | 2 +- .../feature/profile/ProfileViewModel.kt | 2 +- .../mifospay/feature/receipt/ReceiptScreen.kt | 2 +- .../feature/receipt/ReceiptViewModel.kt | 33 ++++++++++------ .../feature/request/money/GenerateQr.kt | 2 +- .../feature/savedcards/AddCardDialogSheet.kt | 2 +- .../navigation/SetupUpiPinNavigation.kt | 2 +- .../upiSetup/screens/SetUpUPiPinScreen.kt | 2 +- .../upiSetup/screens/SetUpUpiScreenContent.kt | 2 +- gradle/libs.versions.toml | 5 +++ .../main/java/org/mifospay/di/KoinModules.kt | 4 +- .../org/mifospay/navigation/LoginNavGraph.kt | 2 +- .../org/mifospay/navigation/MifosNavHost.kt | 2 +- .../org/mifospay/utils/NotificationUtils.kt | 2 +- 48 files changed, 255 insertions(+), 179 deletions(-) delete mode 100644 core/common/src/androidMain/kotlin/org/mifospay/common/DebugUtil.kt delete mode 100644 core/common/src/androidMain/kotlin/org/mifospay/common/FileUtils.kt delete mode 100644 core/common/src/androidMain/kotlin/org/mifospay/common/Utils.kt create mode 100644 core/common/src/androidMain/kotlin/org/mifospay/core/common/FileUtils.android.kt create mode 100644 core/common/src/androidMain/kotlin/org/mifospay/core/common/Utils.android.kt delete mode 100644 core/common/src/androidMain/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt rename core/common/src/{androidMain/kotlin/org/mifospay => commonMain/kotlin/org/mifospay/core}/common/Constants.kt (99%) rename core/common/src/{androidMain/kotlin/org/mifospay => commonMain/kotlin/org/mifospay/core}/common/CreditCardUtils.kt (96%) create mode 100644 core/common/src/commonMain/kotlin/org/mifospay/core/common/DebugUtil.kt create mode 100644 core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt rename core/common/src/{androidMain/kotlin/org/mifospay/core/network => commonMain/kotlin/org/mifospay/core/common}/MifosDispatchers.kt (94%) rename core/common/src/{androidMain/kotlin/org/mifospay => commonMain/kotlin/org/mifospay/core}/common/NavArgsConstants.kt (92%) create mode 100644 core/common/src/commonMain/kotlin/org/mifospay/core/common/Utils.kt rename core/common/src/{androidMain/kotlin/org/mifospay/core/network => commonMain/kotlin/org/mifospay/core/common}/di/DispatchersModule.kt (68%) create mode 100644 core/common/src/jvmMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt create mode 100644 core/common/src/jvmMain/kotlin/org/mifospay/core/common/Utils.jvm.kt create mode 100644 core/common/src/nativeMain/kotlin/org/mifospay/core/common/FileUtils.native.kt create mode 100644 core/common/src/nativeMain/kotlin/org/mifospay/core/common/Utils.native.kt diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index 20720cc5f..bc93c368a 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -16,6 +16,18 @@ android { } kotlin { + + listOf( + iosX64(), + iosArm64(), + iosSimulatorArm64() + ).forEach { + it.binaries.framework { + isStatic = false + export(libs.kermit.simple) + } + } + sourceSets { commonMain.dependencies { implementation(libs.kotlinx.coroutines.core) @@ -23,6 +35,8 @@ kotlin { api(libs.coil.core) api(libs.coil.svg) api(libs.coil.network.ktor) + api(libs.kermit.logging) + api(libs.squareup.okio) } androidMain.dependencies { implementation(libs.kotlinx.coroutines.android) @@ -30,5 +44,8 @@ kotlin { commonTest.dependencies { implementation(libs.kotlinx.coroutines.test) } + iosMain.dependencies { + api(libs.kermit.simple) + } } } \ No newline at end of file diff --git a/core/common/src/androidMain/kotlin/org/mifospay/common/DebugUtil.kt b/core/common/src/androidMain/kotlin/org/mifospay/common/DebugUtil.kt deleted file mode 100644 index 685662541..000000000 --- a/core/common/src/androidMain/kotlin/org/mifospay/common/DebugUtil.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.common - -import android.util.Log - -// TODO Move into separate module -object DebugUtil { - - fun log(vararg objects: Any): Array { - var stringToPrint = "" - for (`object` in objects) { - stringToPrint += "$`object`, " - } - stringToPrint = stringToPrint.substring(0, stringToPrint.lastIndexOf(',')) - Log.d("QXZ:: ", stringToPrint) - return objects as Array - } -} diff --git a/core/common/src/androidMain/kotlin/org/mifospay/common/FileUtils.kt b/core/common/src/androidMain/kotlin/org/mifospay/common/FileUtils.kt deleted file mode 100644 index d3725d562..000000000 --- a/core/common/src/androidMain/kotlin/org/mifospay/common/FileUtils.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.common - -import android.util.Log -import java.io.File -import java.io.FileOutputStream -import java.io.InputStream -import java.io.OutputStream - -object FileUtils { - - fun writeInputStreamDataToFile(inputStream: InputStream, file: File?): Boolean { - return try { - val out: OutputStream = FileOutputStream(file) - val buf = ByteArray(1024) - var len: Int - while (inputStream.read(buf).also { len = it } > 0) { - out.write(buf, 0, len) - } - out.close() - inputStream.close() - true - } catch (e: Exception) { - Log.e("Message", e.message.toString()) - false - } - } -} diff --git a/core/common/src/androidMain/kotlin/org/mifospay/common/Utils.kt b/core/common/src/androidMain/kotlin/org/mifospay/common/Utils.kt deleted file mode 100644 index 5b18a303d..000000000 --- a/core/common/src/androidMain/kotlin/org/mifospay/common/Utils.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.common - -import java.text.NumberFormat -import java.util.Currency - -object Utils { - - @JvmStatic - fun getFormattedAccountBalance( - balance: Double?, - currencyCode: String?, - maximumFractionDigits: Int? = 0, - ): String { - val accountBalanceFormatter = NumberFormat.getCurrencyInstance() - accountBalanceFormatter.maximumFractionDigits = maximumFractionDigits ?: 0 - accountBalanceFormatter.currency = Currency.getInstance(currencyCode) - return accountBalanceFormatter.format(balance) - } - - fun List.toArrayList(): ArrayList { - val array: ArrayList = ArrayList() - for (index in this) array.add(index) - return array - } -} diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/common/FileUtils.android.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/common/FileUtils.android.kt new file mode 100644 index 000000000..53d528d60 --- /dev/null +++ b/core/common/src/androidMain/kotlin/org/mifospay/core/common/FileUtils.android.kt @@ -0,0 +1,5 @@ +package org.mifospay.core.common + + +// JVM and Android implementation +actual fun createPlatformFileUtils(): FileUtils = CommonFileUtils() \ No newline at end of file diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/common/Utils.android.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/common/Utils.android.kt new file mode 100644 index 000000000..9ece3cb54 --- /dev/null +++ b/core/common/src/androidMain/kotlin/org/mifospay/core/common/Utils.android.kt @@ -0,0 +1,17 @@ +package org.mifospay.core.common + +import java.text.NumberFormat +import java.util.Currency + +actual class CurrencyFormatter { + actual fun format( + balance: Double?, + currencyCode: String?, + maximumFractionDigits: Int?, + ): String { + val balanceFormatter = NumberFormat.getCurrencyInstance() + balanceFormatter.maximumFractionDigits = maximumFractionDigits ?: 0 + balanceFormatter.currency = Currency.getInstance(currencyCode) + return balanceFormatter.format(balance) + } +} \ No newline at end of file diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt deleted file mode 100644 index 501cf3b80..000000000 --- a/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/CoroutineScopesModule.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.di - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob -import org.koin.core.qualifier.named -import org.koin.dsl.module - -val CoroutineScopesModule = module { - - single(named("ApplicationScope")) { - CoroutineScope(SupervisorJob() + Dispatchers.Default) - } -} diff --git a/core/common/src/androidMain/kotlin/org/mifospay/common/Constants.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Constants.kt similarity index 99% rename from core/common/src/androidMain/kotlin/org/mifospay/common/Constants.kt rename to core/common/src/commonMain/kotlin/org/mifospay/core/common/Constants.kt index 83371ea82..8dbd49a63 100644 --- a/core/common/src/androidMain/kotlin/org/mifospay/common/Constants.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Constants.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.common +package org.mifospay.core.common /** * Created by naman on 17/6/17. diff --git a/core/common/src/androidMain/kotlin/org/mifospay/common/CreditCardUtils.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/CreditCardUtils.kt similarity index 96% rename from core/common/src/androidMain/kotlin/org/mifospay/common/CreditCardUtils.kt rename to core/common/src/commonMain/kotlin/org/mifospay/core/common/CreditCardUtils.kt index 9f114eb32..87a60bc4e 100644 --- a/core/common/src/androidMain/kotlin/org/mifospay/common/CreditCardUtils.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/CreditCardUtils.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.common +package org.mifospay.core.common object CreditCardUtils { fun validateCreditCardNumber(str: String): Boolean { diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/DebugUtil.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/DebugUtil.kt new file mode 100644 index 000000000..2611aab15 --- /dev/null +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/DebugUtil.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +import co.touchlab.kermit.Logger + +object DebugUtil { + + private val logger = Logger.withTag("QXZ") + + fun log(vararg objects: Any): Array { + val stringToPrint = objects.joinToString(", ") + logger.d { stringToPrint } + return objects + } +} diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt new file mode 100644 index 000000000..1c664646e --- /dev/null +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt @@ -0,0 +1,39 @@ +package org.mifospay.core.common + +import co.touchlab.kermit.Logger +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import okio.FileSystem +import okio.Path.Companion.toPath +import okio.SYSTEM + + +interface FileUtils { + suspend fun writeInputStreamDataToFile(inputStream: ByteArray, filePath: String): Boolean + + companion object { + val logger = Logger.withTag("FileUtils") + } +} + +expect fun createPlatformFileUtils(): FileUtils + +class CommonFileUtils : FileUtils { + override suspend fun writeInputStreamDataToFile( + inputStream: ByteArray, + filePath: String, + ): Boolean = + withContext(Dispatchers.Default) { + try { + val path = filePath.toPath() + FileSystem.SYSTEM.write(path) { + write(inputStream) + } + + true + } catch (e: Exception) { + FileUtils.logger.e { "Error writing file: ${e.message}" } + false + } + } +} \ No newline at end of file diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/network/MifosDispatchers.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/MifosDispatchers.kt similarity index 94% rename from core/common/src/androidMain/kotlin/org/mifospay/core/network/MifosDispatchers.kt rename to core/common/src/commonMain/kotlin/org/mifospay/core/common/MifosDispatchers.kt index 3122bf45b..c692ec1bc 100644 --- a/core/common/src/androidMain/kotlin/org/mifospay/core/network/MifosDispatchers.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/MifosDispatchers.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.network +package org.mifospay.core.common import org.koin.core.annotation.Qualifier diff --git a/core/common/src/androidMain/kotlin/org/mifospay/common/NavArgsConstants.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/NavArgsConstants.kt similarity index 92% rename from core/common/src/androidMain/kotlin/org/mifospay/common/NavArgsConstants.kt rename to core/common/src/commonMain/kotlin/org/mifospay/core/common/NavArgsConstants.kt index 0dcb73540..f243d5cee 100644 --- a/core/common/src/androidMain/kotlin/org/mifospay/common/NavArgsConstants.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/NavArgsConstants.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.common +package org.mifospay.core.common const val PAYEE_EXTERNAL_ID_ARG = "payeeExternalId" const val TRANSFER_AMOUNT_ARG = "transferAmount" diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/Utils.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Utils.kt new file mode 100644 index 000000000..faa6d8f50 --- /dev/null +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Utils.kt @@ -0,0 +1,9 @@ +package org.mifospay.core.common + +expect class CurrencyFormatter { + fun format(balance: Double?, currencyCode: String?, maximumFractionDigits: Int?): String +} + +fun List.toArrayList(): ArrayList { + return ArrayList(this) +} \ No newline at end of file diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/DispatchersModule.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/di/DispatchersModule.kt similarity index 68% rename from core/common/src/androidMain/kotlin/org/mifospay/core/network/di/DispatchersModule.kt rename to core/common/src/commonMain/kotlin/org/mifospay/core/common/di/DispatchersModule.kt index 9ad058f96..a41d60920 100644 --- a/core/common/src/androidMain/kotlin/org/mifospay/core/network/di/DispatchersModule.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/di/DispatchersModule.kt @@ -7,15 +7,21 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.network.di +package org.mifospay.core.common.di import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.SupervisorJob import org.koin.core.qualifier.named import org.koin.dsl.module -import org.mifospay.core.network.MifosDispatchers +import org.mifospay.core.common.MifosDispatchers val DispatchersModule = module { single(named(MifosDispatchers.IO.name)) { Dispatchers.IO } single(named(MifosDispatchers.Default.name)) { Dispatchers.Default } + single(named("ApplicationScope")) { + CoroutineScope(SupervisorJob() + Dispatchers.Default) + } } diff --git a/core/common/src/jvmMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt b/core/common/src/jvmMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt new file mode 100644 index 000000000..a619afac0 --- /dev/null +++ b/core/common/src/jvmMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt @@ -0,0 +1,5 @@ +package org.mifospay.core.common + +// JVM and Android implementation +actual fun createPlatformFileUtils(): FileUtils = CommonFileUtils() + diff --git a/core/common/src/jvmMain/kotlin/org/mifospay/core/common/Utils.jvm.kt b/core/common/src/jvmMain/kotlin/org/mifospay/core/common/Utils.jvm.kt new file mode 100644 index 000000000..806fd7af7 --- /dev/null +++ b/core/common/src/jvmMain/kotlin/org/mifospay/core/common/Utils.jvm.kt @@ -0,0 +1,17 @@ +package org.mifospay.core.common + +import java.text.NumberFormat +import java.util.Currency + +actual class CurrencyFormatter { + actual fun format( + balance: Double?, + currencyCode: String?, + maximumFractionDigits: Int?, + ): String { + val numberFormat = NumberFormat.getCurrencyInstance() + numberFormat.maximumFractionDigits = maximumFractionDigits ?: 0 + numberFormat.currency = Currency.getInstance(currencyCode) + return numberFormat.format(balance) + } +} \ No newline at end of file diff --git a/core/common/src/nativeMain/kotlin/org/mifospay/core/common/FileUtils.native.kt b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/FileUtils.native.kt new file mode 100644 index 000000000..d60f3b49e --- /dev/null +++ b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/FileUtils.native.kt @@ -0,0 +1,24 @@ +package org.mifospay.core.common + +import kotlinx.cinterop.ExperimentalForeignApi +import kotlinx.cinterop.refTo +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext + +// iOS implementation +@OptIn(ExperimentalForeignApi::class) +actual fun createPlatformFileUtils(): FileUtils = object : FileUtils { + override suspend fun writeInputStreamDataToFile(inputStream: ByteArray, filePath: String): Boolean = + withContext(Dispatchers.Default) { + try { + val nsData = inputStream.toNSData() + nsData.writeToFile(filePath, true) + true + } catch (e: Exception) { + FileUtils.logger.e { "Error writing file: ${e.message}" } + false + } + } + + private fun ByteArray.toNSData(): NSData = NSData.create(bytes = this.refTo(0), length = this.size.toULong()) +} \ No newline at end of file diff --git a/core/common/src/nativeMain/kotlin/org/mifospay/core/common/Utils.native.kt b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/Utils.native.kt new file mode 100644 index 000000000..a7c68ea45 --- /dev/null +++ b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/Utils.native.kt @@ -0,0 +1,17 @@ +package org.mifospay.core.common + +import platform.Foundation.NSNumberFormatter + +actual class CurrencyFormatter { + actual fun format( + balance: Double?, + currencyCode: String?, + maximumFractionDigits: Int?, + ): String { + val numberFormatter = NSNumberFormatter() + numberFormatter.numberStyle = NSNumberFormatterCurrencyStyle + numberFormatter.currencyCode = currencyCode + numberFormatter.maximumFractionDigits = maximumFractionDigits ?: 0 + return numberFormatter.stringFromNumber(balance ?: 0.0) ?: "" + } +} \ No newline at end of file diff --git a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/navigation/BankAccountDetailNavigation.kt b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/navigation/BankAccountDetailNavigation.kt index 369495ee9..43c2f723b 100644 --- a/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/navigation/BankAccountDetailNavigation.kt +++ b/feature/accounts/src/main/kotlin/org/mifospay/feature/bank/accounts/navigation/BankAccountDetailNavigation.kt @@ -16,7 +16,7 @@ import androidx.navigation.NavType import androidx.navigation.compose.composable import androidx.navigation.navArgument import com.mifospay.core.model.domain.BankAccountDetails -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.feature.bank.accounts.details.BankAccountDetailScreen const val BANK_ACCOUNT_DETAIL_ROUTE = "bank_account_detail_route" diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt index db9ec6611..31cc30a7d 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt @@ -42,7 +42,7 @@ import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifos.library.countrycodepicker.CountryCodePicker import org.koin.androidx.compose.koinViewModel -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosLoadingWheel import org.mifospay.core.designsystem.component.MifosOutlinedTextField diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt index 112dd145a..2eb75757b 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt @@ -16,7 +16,7 @@ import androidx.navigation.NavGraphBuilder import androidx.navigation.NavType import androidx.navigation.compose.composable import androidx.navigation.navArgument -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.feature.auth.mobileVerify.MobileVerificationScreen const val MOBILE_VERIFICATION_ROUTE = "mobile_verification_route" diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt index 4fd21843f..284d93cb4 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt @@ -25,8 +25,8 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -import org.mifospay.common.Constants -import org.mifospay.common.DebugUtil +import org.mifospay.core.common.Constants +import org.mifospay.core.common.DebugUtil import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.client.CreateClient diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt index f7bc19203..87c377b69 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt +++ b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt @@ -58,7 +58,7 @@ import com.google.android.libraries.identity.googleid.GetGoogleIdOption import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException import kotlinx.coroutines.launch -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.data.util.Constants.MIFOS_CONSUMER_SAVINGS_PRODUCT_ID import org.mifospay.core.data.util.Constants.MIFOS_MERCHANT_SAVINGS_PRODUCT_ID import org.mifospay.core.designsystem.component.MifosBottomSheet diff --git a/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordViewModel.kt b/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordViewModel.kt index f905b6e28..99f780494 100644 --- a/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordViewModel.kt +++ b/feature/editpassword/src/main/kotlin/org/mifospay/feature/editpassword/EditPasswordViewModel.kt @@ -13,7 +13,7 @@ import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.user.UpdateUserEntityPassword import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.user.AuthenticateUser diff --git a/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsViewModel.kt b/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsViewModel.kt index ad53eef1d..d44c95e9e 100644 --- a/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsViewModel.kt +++ b/feature/history/src/main/kotlin/org/mifospay/feature/specific/transactions/SpecificTransactionsViewModel.kt @@ -14,11 +14,11 @@ import androidx.lifecycle.ViewModel import com.mifospay.core.model.domain.Transaction import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import org.mifospay.core.common.Constants import org.mifospay.core.data.base.TaskLooper import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseFactory import org.mifospay.core.data.domain.usecase.account.FetchAccountTransfer -import org.mifospay.core.data.util.Constants import org.mifospay.feature.specific.transactions.SpecificTransactionsUiState.Loading import org.mifospay.feature.specific.transactions.navigation.ACCOUNT_NUMBER_ARG import org.mifospay.feature.specific.transactions.navigation.TRANSACTIONS_ARG @@ -54,7 +54,7 @@ class SpecificTransactionsViewModel( as UseCase, values = FetchAccountTransfer.RequestValues(transferId), taskData = TaskLooper.TaskData( - org.mifospay.common.Constants.TRANSFER_DETAILS, + Constants.TRANSFER_DETAILS, i, ), ) @@ -66,7 +66,7 @@ class SpecificTransactionsViewModel( response: R, ) { when (taskData.taskName) { - org.mifospay.common.Constants.TRANSFER_DETAILS -> { + Constants.TRANSFER_DETAILS -> { val responseValue = response as FetchAccountTransfer.ResponseValue val index = taskData.taskId transactions[index].transferDetail = responseValue.transferDetail diff --git a/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailScreen.kt b/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailScreen.kt index d57010eb1..948e38205 100644 --- a/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailScreen.kt +++ b/feature/history/src/main/kotlin/org/mifospay/feature/transaction/detail/TransactionDetailScreen.kt @@ -38,7 +38,7 @@ import com.mifospay.core.model.domain.Transaction import com.mifospay.core.model.domain.TransactionType import com.mifospay.core.model.entity.accounts.savings.TransferDetail import org.koin.androidx.compose.koinViewModel -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.theme.MifosTheme import org.mifospay.core.ui.ErrorScreenContent diff --git a/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeScreen.kt b/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeScreen.kt index 847d509ce..717029f2e 100644 --- a/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeScreen.kt +++ b/feature/home/src/main/kotlin/org/mifospay/feature/home/HomeScreen.kt @@ -51,7 +51,7 @@ import com.mifospay.core.model.domain.Currency import com.mifospay.core.model.domain.Transaction import com.mifospay.core.model.domain.TransactionType import org.koin.androidx.compose.koinViewModel -import org.mifospay.common.Utils +import org.mifospay.core.common.CurrencyFormatter import org.mifospay.core.designsystem.component.MfLoadingWheel import org.mifospay.core.designsystem.theme.border import org.mifospay.core.designsystem.theme.lightGrey @@ -174,9 +174,11 @@ private fun MifosWalletCardScreen( Spacer(modifier = Modifier.height(10.dp)) val accountBalance = if (account != null) { - Utils.getFormattedAccountBalance( - account.balance, - account.currency.code, + val currencyFormatter = CurrencyFormatter() + currencyFormatter.format( + balance = account.balance, + currencyCode = account.currency.code, + maximumFractionDigits = null, ) } else { "0" diff --git a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt index 5655614e6..eec164824 100644 --- a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt +++ b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt @@ -39,7 +39,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifospay.core.model.entity.Invoice import org.mifospay.core.model.utils.DateHelper import org.koin.androidx.compose.koinViewModel -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel import org.mifospay.core.designsystem.component.MifosScaffold import org.mifospay.core.designsystem.theme.MifosTheme diff --git a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoicesViewModel.kt b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoicesViewModel.kt index 5ef00c24c..be692fc83 100644 --- a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoicesViewModel.kt +++ b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoicesViewModel.kt @@ -14,7 +14,7 @@ import androidx.lifecycle.ViewModel import com.mifospay.core.model.entity.Invoice import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import org.mifospay.common.Constants.INVOICE_DOMAIN +import org.mifospay.core.common.Constants.INVOICE_DOMAIN import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.invoice.FetchInvoices diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2ViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2ViewModel.kt index 185589b27..6452e6dc0 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2ViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel2ViewModel.kt @@ -16,7 +16,7 @@ import kotlinx.coroutines.flow.StateFlow import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MultipartBody import okhttp3.RequestBody.Companion.asRequestBody -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.kyc.UploadKYCDocs diff --git a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt index 4a6bf03cd..361136ddf 100644 --- a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt +++ b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferScreen.kt @@ -43,7 +43,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle import org.koin.androidx.compose.koinViewModel -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosLoadingWheel diff --git a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferViewModel.kt b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferViewModel.kt index 1a1ed3df1..73021510a 100644 --- a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferViewModel.kt +++ b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/MakeTransferViewModel.kt @@ -19,8 +19,8 @@ import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -import org.mifospay.common.PAYEE_EXTERNAL_ID_ARG -import org.mifospay.common.TRANSFER_AMOUNT_ARG +import org.mifospay.core.common.PAYEE_EXTERNAL_ID_ARG +import org.mifospay.core.common.TRANSFER_AMOUNT_ARG import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.account.TransferFunds diff --git a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/navigation/MakeTransferNavigation.kt b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/navigation/MakeTransferNavigation.kt index 3aa3c0b78..af079ba7b 100644 --- a/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/navigation/MakeTransferNavigation.kt +++ b/feature/make-transfer/src/main/kotlin/org/mifospay/feature/make/transfer/navigation/MakeTransferNavigation.kt @@ -15,14 +15,14 @@ import androidx.navigation.NavOptions import androidx.navigation.NavType import androidx.navigation.navArgument import com.mifos.library.material3.navigation.bottomSheet -import org.mifospay.common.PAYEE_EXTERNAL_ID_ARG -import org.mifospay.common.TRANSFER_AMOUNT_ARG +import org.mifospay.core.common.PAYEE_EXTERNAL_ID_ARG +import org.mifospay.core.common.TRANSFER_AMOUNT_ARG import org.mifospay.feature.make.transfer.MakeTransferScreenRoute const val MAKE_TRANSFER_ROUTE_BASE = "make_transfer_route" const val MAKE_TRANSFER_ROUTE = MAKE_TRANSFER_ROUTE_BASE + - "?${PAYEE_EXTERNAL_ID_ARG}={$PAYEE_EXTERNAL_ID_ARG}" + - "&${TRANSFER_AMOUNT_ARG}={$TRANSFER_AMOUNT_ARG}" + "?$PAYEE_EXTERNAL_ID_ARG={$PAYEE_EXTERNAL_ID_ARG}" + + "&$TRANSFER_AMOUNT_ARG={$TRANSFER_AMOUNT_ARG}" fun NavController.navigateToMakeTransferScreen( externalId: String? = null, @@ -30,11 +30,11 @@ fun NavController.navigateToMakeTransferScreen( navOptions: NavOptions? = null, ) { val route = MAKE_TRANSFER_ROUTE_BASE + if (transferAmount != null) { - "?${PAYEE_EXTERNAL_ID_ARG}=$externalId" + - "&${TRANSFER_AMOUNT_ARG}=$transferAmount" + "?$PAYEE_EXTERNAL_ID_ARG=$externalId" + + "&$TRANSFER_AMOUNT_ARG=$transferAmount" } else { - "?${PAYEE_EXTERNAL_ID_ARG}=$externalId" + - "&${TRANSFER_AMOUNT_ARG}=${"0.0"}" + "?$PAYEE_EXTERNAL_ID_ARG=$externalId" + + "&$TRANSFER_AMOUNT_ARG=${"0.0"}" } navigate(route, navOptions) } diff --git a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantTransferViewModel.kt b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantTransferViewModel.kt index 8141528ca..4407bcfe7 100644 --- a/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantTransferViewModel.kt +++ b/feature/merchants/src/main/kotlin/org/mifospay/feature/merchants/MerchantTransferViewModel.kt @@ -15,7 +15,7 @@ import com.mifospay.core.model.domain.Transaction import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.data.base.TaskLooper import org.mifospay.core.data.base.TaskLooper.TaskData import org.mifospay.core.data.base.UseCase diff --git a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileViewModel.kt b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileViewModel.kt index dd6d71855..e6c24ded3 100644 --- a/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileViewModel.kt +++ b/feature/profile/src/main/kotlin/org/mifospay/feature/profile/ProfileViewModel.kt @@ -17,7 +17,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch import okhttp3.ResponseBody -import org.mifospay.common.DebugUtil +import org.mifospay.core.common.DebugUtil import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.client.FetchClientImage diff --git a/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptScreen.kt b/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptScreen.kt index 16c18febd..faa322c2a 100644 --- a/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptScreen.kt +++ b/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptScreen.kt @@ -60,7 +60,7 @@ import com.mifospay.core.model.domain.TransactionType import com.mifospay.core.model.entity.accounts.savings.TransferDetail import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.designsystem.component.FloatingActionButtonContent import org.mifospay.core.designsystem.component.MifosOverlayLoadingWheel import org.mifospay.core.designsystem.component.MifosScaffold diff --git a/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptViewModel.kt b/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptViewModel.kt index 6769ac271..991bfc1c4 100644 --- a/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptViewModel.kt +++ b/feature/receipt/src/main/kotlin/org/mifospay/feature/receipt/ReceiptViewModel.kt @@ -13,14 +13,16 @@ import android.net.Uri import android.os.Environment import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.mifospay.core.model.domain.Transaction import com.mifospay.core.model.entity.accounts.savings.TransferDetail import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch import okhttp3.ResponseBody -import org.mifospay.common.Constants -import org.mifospay.common.FileUtils +import org.mifospay.core.common.Constants +import org.mifospay.core.common.createPlatformFileUtils import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.account.DownloadTransactionReceipt @@ -67,16 +69,23 @@ class ReceiptViewModel( } fun writeReceiptToPDF(responseBody: ResponseBody?, filename: String) { - val mifosDirectory = File( - Environment.getExternalStorageDirectory(), - Constants.MIFOSPAY, - ) - if (!mifosDirectory.exists()) { - mifosDirectory.mkdirs() - } - val documentFile = File(mifosDirectory.path, filename) - if (FileUtils.writeInputStreamDataToFile(responseBody!!.byteStream(), documentFile)) { - mFileState.value = PassFileState(documentFile) + viewModelScope.launch { + val mifosDirectory = File( + Environment.getExternalStorageDirectory(), + Constants.MIFOSPAY, + ) + if (!mifosDirectory.exists()) { + mifosDirectory.mkdirs() + } + val documentFile = File(mifosDirectory.path, filename) + val fileUtils = createPlatformFileUtils() + val result = fileUtils.writeInputStreamDataToFile( + responseBody!!.bytes(), + documentFile.path, + ) + if (result) { + mFileState.value = PassFileState(documentFile) + } } } diff --git a/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/GenerateQr.kt b/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/GenerateQr.kt index 30457707a..67a3fa6ad 100644 --- a/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/GenerateQr.kt +++ b/feature/request-money/src/main/kotlin/org/mifospay/feature/request/money/GenerateQr.kt @@ -14,7 +14,7 @@ import com.google.zxing.BarcodeFormat import com.google.zxing.MultiFormatWriter import com.google.zxing.WriterException import com.google.zxing.common.BitMatrix -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.data.base.UseCase import java.util.Base64 diff --git a/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/AddCardDialogSheet.kt b/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/AddCardDialogSheet.kt index 773768448..13a12ed8a 100644 --- a/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/AddCardDialogSheet.kt +++ b/feature/savedcards/src/main/kotlin/org/mifospay/feature/savedcards/AddCardDialogSheet.kt @@ -33,7 +33,7 @@ import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.mifospay.core.model.entity.savedcards.Card -import org.mifospay.common.CreditCardUtils +import org.mifospay.core.common.CreditCardUtils import org.mifospay.core.designsystem.component.MifosBottomSheet import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosOutlinedTextField diff --git a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/navigation/SetupUpiPinNavigation.kt b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/navigation/SetupUpiPinNavigation.kt index 132a8402f..f50648fde 100644 --- a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/navigation/SetupUpiPinNavigation.kt +++ b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/navigation/SetupUpiPinNavigation.kt @@ -16,7 +16,7 @@ import androidx.navigation.NavType import androidx.navigation.compose.composable import androidx.navigation.navArgument import com.mifospay.core.model.domain.BankAccountDetails -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.feature.upiSetup.screens.SetupUpiPinScreenRoute const val SETUP_UPI_PIN_ROUTE = "setup_upi_pin_route" diff --git a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUPiPinScreen.kt b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUPiPinScreen.kt index 02e57efc5..069323459 100644 --- a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUPiPinScreen.kt +++ b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUPiPinScreen.kt @@ -30,7 +30,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import com.mifospay.core.model.domain.BankAccountDetails import org.koin.androidx.compose.koinViewModel -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.feature.upiSetup.viewmodel.SetUpUpiViewModal import org.mifospay.feature.upi_setup.R diff --git a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUpiScreenContent.kt b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUpiScreenContent.kt index d0f331957..7cac75544 100644 --- a/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUpiScreenContent.kt +++ b/feature/upi-setup/src/main/kotlin/org/mifospay/feature/upiSetup/screens/SetUpUpiScreenContent.kt @@ -19,7 +19,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.designsystem.theme.MifosTheme @Composable diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9b9c19999..1f7d9e375 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,6 +39,7 @@ googleOss = "17.1.0" googleOssPlugin = "0.10.6" googleidVersion = "1.1.1" junitVersion = "4.13.2" +kermit = "2.0.4" koin = "4.0.0-RC2" koinAnnotationsVersion = "1.4.0-RC4" koinComposeMultiplatform = "1.2.0-Beta4" @@ -63,6 +64,7 @@ minSdk = "24" moduleGraph = "2.5.0" multiplatformSettings = "1.2.0" okHttp3Version = "4.12.0" +okioVersion = "3.9.1" playServicesAuthVersion = "21.2.0" playServicesCodeScanner = "16.1.0" protobuf = "4.26.0" @@ -155,6 +157,8 @@ google-play-services-code-scanner = { group = "com.google.android.gms", name = " googleid = { group = "com.google.android.libraries.identity.googleid", name = "googleid", version.ref = "googleidVersion" } jetbrains-kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlinStdlibVersion" } junit = { group = "junit", name = "junit", version.ref = "junitVersion" } +kermit-logging = { group = "co.touchlab", name = "kermit", version.ref = "kermit" } +kermit-simple = { group = "co.touchlab", name = "kermit-simple", version.ref = "kermit" } koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } koin-androidx-compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } koin-androidx-navigation = { group = "io.insert-koin", name = "koin-androidx-navigation", version.ref = "koin" } @@ -215,6 +219,7 @@ reactivex-rxjava = { group = "io.reactivex", name = "rxjava", version.ref = "rxj reactivex-rxjava-android = { group = "io.reactivex", name = "rxandroid", version.ref = "rxandroidVersion" } retrofit-kotlin-serialization = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofitKotlinxSerializationJson" } room-gradlePlugin = { group = "androidx.room", name = "room-gradle-plugin", version.ref = "room" } +squareup-okio = { group = "com.squareup.okio", name = "okio", version.ref = "okioVersion" } sheets-compose-dialogs-calender = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "calendar", version.ref = "sheets_compose_dialogs_core" } sheets-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "core", version.ref = "sheets_compose_dialogs_core" } spotless-gradle = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version.ref = "spotlessVersion" } diff --git a/mifospay/src/main/java/org/mifospay/di/KoinModules.kt b/mifospay/src/main/java/org/mifospay/di/KoinModules.kt index c3ad261cb..72e1d3422 100644 --- a/mifospay/src/main/java/org/mifospay/di/KoinModules.kt +++ b/mifospay/src/main/java/org/mifospay/di/KoinModules.kt @@ -15,8 +15,8 @@ import org.mifospay.core.analytics.di.AnalyticsModule import org.mifospay.core.data.di.DataModule import org.mifospay.core.data.di.LocalDataModule import org.mifospay.core.datastore.di.CoreDataStoreModule -import org.mifospay.core.network.di.CoroutineScopesModule -import org.mifospay.core.network.di.DispatchersModule +import org.mifospay.core.common.di.CoroutineScopesModule +import org.mifospay.core.common.di.DispatchersModule import org.mifospay.core.network.di.LocalModule import org.mifospay.core.network.di.NetworkModule import org.mifospay.feature.auth.di.AuthModule diff --git a/mifospay/src/main/java/org/mifospay/navigation/LoginNavGraph.kt b/mifospay/src/main/java/org/mifospay/navigation/LoginNavGraph.kt index c80043848..4daf2ca6b 100644 --- a/mifospay/src/main/java/org/mifospay/navigation/LoginNavGraph.kt +++ b/mifospay/src/main/java/org/mifospay/navigation/LoginNavGraph.kt @@ -13,7 +13,7 @@ import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.navigation import org.mifos.library.passcode.navigateToPasscodeScreen -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.feature.auth.navigation.LOGIN_ROUTE import org.mifospay.feature.auth.navigation.loginScreen import org.mifospay.feature.auth.navigation.mobileVerificationScreen diff --git a/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt b/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt index 4b84c3e6b..dc2a4acc5 100644 --- a/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt +++ b/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt @@ -16,7 +16,7 @@ import androidx.compose.ui.Modifier import androidx.core.content.FileProvider import androidx.navigation.compose.NavHost import com.mifos.library.material3.navigation.ModalBottomSheetLayout -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import org.mifospay.core.ui.utility.TabContent import org.mifospay.feature.bank.accounts.AccountsScreen import org.mifospay.feature.bank.accounts.navigation.bankAccountDetailScreen diff --git a/mifospay/src/main/java/org/mifospay/utils/NotificationUtils.kt b/mifospay/src/main/java/org/mifospay/utils/NotificationUtils.kt index 2bdb7c4bd..0e9c596dc 100644 --- a/mifospay/src/main/java/org/mifospay/utils/NotificationUtils.kt +++ b/mifospay/src/main/java/org/mifospay/utils/NotificationUtils.kt @@ -27,7 +27,7 @@ import android.util.Log import android.util.Patterns import androidx.core.app.NotificationCompat import org.mifospay.R -import org.mifospay.common.Constants +import org.mifospay.core.common.Constants import java.io.IOException import java.net.HttpURLConnection import java.net.URL From f03a2a029735ac201567e4b7794b4f1d6c329b15 Mon Sep 17 00:00:00 2001 From: Sk Niyaj Ali Date: Thu, 26 Sep 2024 20:55:25 +0530 Subject: [PATCH 04/31] Feat: [:core:datastore] - Migrated to KMP (#1769) --- .../src/androidMain/AndroidManifest.xml | 13 -- .../user_preferences.proto | 13 -- .../core/datastore/proto/ClientPreferences.kt | 24 +++ .../core/datastore/proto/RolePreferences.kt | 20 +++ .../datastore/proto/UserInfoPreferences.kt | 34 ++++ .../core/datastore/proto/UserPreferences.kt | 36 +++++ .../core/datastore/proto/client_info.proto | 13 ++ .../core/datastore/proto/role_info.proto | 11 ++ .../core/datastore/proto/user_info.proto | 20 +++ .../datastore/proto/user_preference.proto | 22 +++ .../core/datastore/PreferencesMapper.kt | 116 ++++++++++++++ .../datastore/UserPreferencesDataSource.kt | 150 ++++++++++++++++++ .../core/datastore/di/PreferenceModule.kt | 12 ++ .../core/datastore/ExampleUnitTest.kt | 25 --- .../org/mifospay/core/model/ClientInfo.kt | 10 ++ .../org/mifospay/core/model/RoleInfo.kt | 8 + .../org/mifospay/core/model/UserData.kt | 15 +- .../org/mifospay/core/model/UserInfo.kt | 15 ++ 18 files changed, 503 insertions(+), 54 deletions(-) delete mode 100644 core/datastore-proto/src/androidMain/AndroidManifest.xml delete mode 100644 core/datastore-proto/src/androidMain/proto/org.mifospay.core.data/user_preferences.proto create mode 100644 core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt create mode 100644 core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt create mode 100644 core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt create mode 100644 core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt create mode 100644 core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/client_info.proto create mode 100644 core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/role_info.proto create mode 100644 core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_info.proto create mode 100644 core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto create mode 100644 core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt delete mode 100644 core/datastore/src/test/java/org/mifospay/core/datastore/ExampleUnitTest.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt diff --git a/core/datastore-proto/src/androidMain/AndroidManifest.xml b/core/datastore-proto/src/androidMain/AndroidManifest.xml deleted file mode 100644 index 961389810..000000000 --- a/core/datastore-proto/src/androidMain/AndroidManifest.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - \ No newline at end of file diff --git a/core/datastore-proto/src/androidMain/proto/org.mifospay.core.data/user_preferences.proto b/core/datastore-proto/src/androidMain/proto/org.mifospay.core.data/user_preferences.proto deleted file mode 100644 index 03791d71b..000000000 --- a/core/datastore-proto/src/androidMain/proto/org.mifospay.core.data/user_preferences.proto +++ /dev/null @@ -1,13 +0,0 @@ -syntax = "proto3"; - -option java_package = "org.mifospay.core.datastore.proto"; -option java_multiple_files = true; - -message UserPreferences { - string auth_token = 1; - string user = 2; - string user_email = 3; - string client = 4; - - // NEXT AVAILABLE ID: 5 -} diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt new file mode 100644 index 000000000..f3d4a9bf3 --- /dev/null +++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt @@ -0,0 +1,24 @@ +package org.mifospay.core.datastore.proto + +import kotlinx.serialization.Serializable + +@Serializable +data class ClientPreferences( + val name: String, + val image: String, + val externalId: String, + val clientId: Long, + val displayName: String, + val mobileNo: String, +) { + companion object { + val DEFAULT = ClientPreferences( + name = "", + image = "", + externalId = "", + clientId = 0, + displayName = "", + mobileNo = "", + ) + } +} \ No newline at end of file diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt new file mode 100644 index 000000000..5568d8e46 --- /dev/null +++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt @@ -0,0 +1,20 @@ +package org.mifospay.core.datastore.proto + +import kotlinx.serialization.Serializable + +@Serializable +data class RolePreferences( + val id: String, + val name: String, + val description: String, + val disabled: Boolean +) { + companion object { + val DEFAULT = RolePreferences( + id = "", + name = "", + description = "", + disabled = false + ) + } +} diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt new file mode 100644 index 000000000..179ca3c3b --- /dev/null +++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt @@ -0,0 +1,34 @@ +package org.mifospay.core.datastore.proto + +import kotlinx.serialization.Serializable + +@Serializable +data class UserInfoPreferences( + val username: String, + val userId: Int, + val base64EncodedAuthenticationKey: String, + val authenticated: Boolean, + val officeId: Int, + val officeName: String, + val roles: List, + val permissions: List, + val clients: List, + val shouldRenewPassword: Boolean, + val isTwoFactorAuthenticationRequired: Boolean +) { + companion object { + val DEFAULT = UserInfoPreferences( + username = "", + userId = 0, + base64EncodedAuthenticationKey = "", + authenticated = false, + officeId = 0, + officeName = "", + roles = emptyList(), + permissions = emptyList(), + clients = emptyList(), + shouldRenewPassword = false, + isTwoFactorAuthenticationRequired = false + ) + } +} diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt new file mode 100644 index 000000000..07113fc78 --- /dev/null +++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt @@ -0,0 +1,36 @@ +package org.mifospay.core.datastore.proto + +import kotlinx.serialization.Serializable + +@Serializable +data class UserPreferences( + val token: String, + val name: String, + val username: String, + val email: String, + val mobileNo: String, + val userId: Int, + val clientId: Int, + val clientVpa: String, + val accountId: Int, + val firebaseRegId: String, + val client: ClientPreferences, + val user: UserInfoPreferences, +) { + companion object { + val DEFAULT = UserPreferences( + token = "", + name = "", + username = "", + email = "", + mobileNo = "", + userId = 0, + clientId = 0, + clientVpa = "", + accountId = 0, + firebaseRegId = "", + client = ClientPreferences.DEFAULT, + user = UserInfoPreferences.DEFAULT, + ) + } +} diff --git a/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/client_info.proto b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/client_info.proto new file mode 100644 index 000000000..f845e980c --- /dev/null +++ b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/client_info.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +option java_package = "org.mifospay.core.datastore.proto"; +option java_multiple_files = true; + +message Client { + string name = 1; + string image = 2; + string external_id = 3; + int64 client_id = 4; + string display_name = 5; + string mobile_no = 6; +} \ No newline at end of file diff --git a/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/role_info.proto b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/role_info.proto new file mode 100644 index 000000000..b9756aa52 --- /dev/null +++ b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/role_info.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +option java_package = "org.mifospay.core.datastore.proto"; +option java_multiple_files = true; + +message Role { + string id = 1; + string name = 2; + string description = 3; + bool disabled = 4; +} \ No newline at end of file diff --git a/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_info.proto b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_info.proto new file mode 100644 index 000000000..9d38f3d91 --- /dev/null +++ b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_info.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +import "proto/org/mifospay/core/datastore/proto/role_info.proto"; + +option java_package = "org.mifospay.core.datastore.proto"; +option java_multiple_files = true; + +message User { + string username = 1; + int64 userId = 2; + string base64EncodedAuthenticationKey = 3; + bool authenticated = 4; + int32 officeId = 5; + string officeName = 6; + repeated Role roles = 7; + repeated string permissions = 8; + repeated int64 clients = 9; + bool shouldRenewPassword = 10; + bool isTwoFactorAuthenticationRequired = 11; +} \ No newline at end of file diff --git a/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto new file mode 100644 index 000000000..762a78145 --- /dev/null +++ b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto @@ -0,0 +1,22 @@ +syntax = "proto3"; + +import "org.mifospay.core.datastore.proto.client_info.proto"; +import "org.mifospay.core.datastore.proto.user_info.proto"; + +option java_package = "org.mifospay.core.datastore.proto"; +option java_multiple_files = true; + +message UserPreferences { + string token = 1; + string name = 2; + string username = 3; + string email = 4; + string mobile_no = 5; + int32 user_id = 6; + int32 client_id = 7; + string client_vpa = 8; + int32 account_id = 9; + string firebase_reg_id = 10; + Client client = 11; + User user = 12; +} \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt new file mode 100644 index 000000000..a1fc33861 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt @@ -0,0 +1,116 @@ +package org.mifospay.core.datastore + +import org.mifospay.core.datastore.proto.ClientPreferences +import org.mifospay.core.datastore.proto.RolePreferences +import org.mifospay.core.datastore.proto.UserInfoPreferences +import org.mifospay.core.datastore.proto.UserPreferences +import org.mifospay.core.model.ClientInfo +import org.mifospay.core.model.RoleInfo +import org.mifospay.core.model.UserData +import org.mifospay.core.model.UserInfo + +fun ClientPreferences.toClientInfo(): ClientInfo { + return ClientInfo( + name = name, + image = image, + externalId = externalId, + clientId = clientId, + displayName = displayName, + mobileNo = mobileNo, + ) +} + +fun ClientInfo.toClientPreferences(): ClientPreferences { + return ClientPreferences( + name = name, + image = image, + externalId = externalId, + clientId = clientId, + displayName = displayName, + mobileNo = mobileNo, + ) +} + +fun RolePreferences.toRoleInfo(): RoleInfo { + return RoleInfo( + id = id, + name = name, + description = description, + disabled = disabled, + ) +} + +fun RoleInfo.toRolePreferences(): RolePreferences { + return RolePreferences( + id = id, + name = name, + description = description, + disabled = disabled, + ) +} + +fun UserInfoPreferences.toUserInfo(): UserInfo { + return UserInfo( + username = username, + userId = userId, + base64EncodedAuthenticationKey = base64EncodedAuthenticationKey, + authenticated = authenticated, + officeId = officeId, + officeName = officeName, + roles = roles.map { it.toRoleInfo() }, + permissions = permissions, + clients = clients, + shouldRenewPassword = shouldRenewPassword, + isTwoFactorAuthenticationRequired = isTwoFactorAuthenticationRequired, + ) +} + +fun UserInfo.toUserInfoPreferences(): UserInfoPreferences { + return UserInfoPreferences( + username = username, + userId = userId, + base64EncodedAuthenticationKey = base64EncodedAuthenticationKey, + authenticated = authenticated, + officeId = officeId, + officeName = officeName, + roles = roles.map { it.toRolePreferences() }, + permissions = permissions, + clients = clients, + shouldRenewPassword = shouldRenewPassword, + isTwoFactorAuthenticationRequired = isTwoFactorAuthenticationRequired, + ) +} + +fun UserPreferences.toUserData(): UserData { + return UserData( + token = token, + name = name, + username = username, + email = email, + mobileNo = mobileNo, + userId = userId, + clientId = clientId, + clientVpa = clientVpa, + accountId = accountId, + firebaseRegId = firebaseRegId, + client = client.toClientInfo(), + user = user.toUserInfo(), + ) +} + +fun UserData.toUserPreferences(): UserPreferences { + return UserPreferences( + token = token, + name = name, + username = username, + email = email, + mobileNo = mobileNo, + userId = userId, + clientId = clientId, + clientVpa = clientVpa, + accountId = accountId, + firebaseRegId = firebaseRegId, + client = client.toClientPreferences(), + user = user.toUserInfoPreferences(), + ) +} \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt new file mode 100644 index 000000000..a15d60c56 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt @@ -0,0 +1,150 @@ +@file:OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) + +package org.mifospay.core.datastore + +import com.russhwolf.settings.ExperimentalSettingsApi +import com.russhwolf.settings.Settings +import com.russhwolf.settings.serialization.decodeValue +import com.russhwolf.settings.serialization.decodeValueOrNull +import com.russhwolf.settings.serialization.encodeValue +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext +import kotlinx.serialization.ExperimentalSerializationApi +import org.mifospay.core.datastore.proto.ClientPreferences +import org.mifospay.core.datastore.proto.RolePreferences +import org.mifospay.core.datastore.proto.UserInfoPreferences +import org.mifospay.core.datastore.proto.UserPreferences +import org.mifospay.core.model.ClientInfo +import org.mifospay.core.model.RoleInfo +import org.mifospay.core.model.UserData +import org.mifospay.core.model.UserInfo + +private const val USER_DATA_KEY = "userData" +private const val USER_INFO_KEY = "userInfo" +private const val CLIENT_INFO_KEY = "clientInfo" +private const val ROLE_INFO_KEY = "roleInfo" + +class UserPreferencesDataSource( + private val settings: Settings, + private val dispatcher: CoroutineDispatcher, +) { + private val _userData = MutableStateFlow( + settings.decodeValue( + key = USER_DATA_KEY, + serializer = UserPreferences.serializer(), + defaultValue = settings.decodeValueOrNull( + key = USER_DATA_KEY, + serializer = UserPreferences.serializer(), + ) ?: UserPreferences.DEFAULT, + ), + ) + + private val _userInfo = MutableStateFlow( + settings.decodeValue( + key = USER_INFO_KEY, + serializer = UserInfoPreferences.serializer(), + defaultValue = settings.decodeValueOrNull( + key = USER_INFO_KEY, + serializer = UserInfoPreferences.serializer(), + ) ?: UserInfoPreferences.DEFAULT, + ), + ) + + private val _clientInfo = MutableStateFlow( + settings.decodeValue( + key = CLIENT_INFO_KEY, + serializer = ClientPreferences.serializer(), + defaultValue = settings.decodeValueOrNull( + key = CLIENT_INFO_KEY, + serializer = ClientPreferences.serializer(), + ) ?: ClientPreferences.DEFAULT, + ), + ) + + private val _roleInfo = MutableStateFlow( + settings.decodeValue( + key = ROLE_INFO_KEY, + serializer = RolePreferences.serializer(), + defaultValue = settings.decodeValueOrNull( + key = ROLE_INFO_KEY, + serializer = RolePreferences.serializer(), + ) ?: RolePreferences.DEFAULT, + ), + ) + + val userData = _userData.map(UserPreferences::toUserData) + val token = _userData.map(UserPreferences::toUserData).map { it.token } + val userInfo = _userInfo.map(UserInfoPreferences::toUserInfo) + val clientInfo = _clientInfo.map(ClientPreferences::toClientInfo) + val roleInfo = _roleInfo.map(RolePreferences::toRoleInfo) + + suspend fun updateRoleInfo(roleInfo: RoleInfo) { + withContext(dispatcher) { + settings.putRolePreference(roleInfo.toRolePreferences()) + _roleInfo.value = roleInfo.toRolePreferences() + } + } + + suspend fun updateClientInfo(clientInfo: ClientInfo) { + withContext(dispatcher) { + settings.putClientPreference(clientInfo.toClientPreferences()) + _clientInfo.value = clientInfo.toClientPreferences() + } + } + + suspend fun updateUserInfo(userInfo: UserInfo) { + withContext(dispatcher) { + settings.putUserInfoPreference(userInfo.toUserInfoPreferences()) + _userInfo.value = userInfo.toUserInfoPreferences() + } + } + + suspend fun updateUserData(userData: UserData) { + withContext(dispatcher) { + settings.putUserPreference(userData.toUserPreferences()) + _userData.value = userData.toUserPreferences() + } + } +} + +private fun Settings.putClientPreference(preference: ClientPreferences) { + encodeValue( + key = CLIENT_INFO_KEY, + serializer = ClientPreferences.serializer(), + value = preference, + ) +} + +private fun Settings.putRolePreference(preference: RolePreferences) { + encodeValue( + key = CLIENT_INFO_KEY, + serializer = RolePreferences.serializer(), + value = preference, + ) +} + +private fun Settings.putUserInfoPreference(preference: UserInfoPreferences) { + encodeValue( + key = USER_INFO_KEY, + serializer = UserInfoPreferences.serializer(), + value = preference, + ) +} + +private fun Settings.putUserPreference(preference: UserPreferences) { + encodeValue( + key = USER_DATA_KEY, + serializer = UserPreferences.serializer(), + value = preference, + ) +} + +private fun Settings.getUserPreference(): UserPreferences { + return decodeValue( + key = USER_DATA_KEY, + serializer = UserPreferences.serializer(), + defaultValue = UserPreferences.DEFAULT, + ) +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt new file mode 100644 index 000000000..fb8139122 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt @@ -0,0 +1,12 @@ +package org.mifospay.core.datastore.di + +import com.russhwolf.settings.Settings +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.datastore.UserPreferencesDataSource + +val PreferencesModule = module { + factory { Settings() } + // Use the IO dispatcher name - MifosDispatchers.IO.name + factory { UserPreferencesDataSource(get(), get(named("IO"))) } +} \ No newline at end of file diff --git a/core/datastore/src/test/java/org/mifospay/core/datastore/ExampleUnitTest.kt b/core/datastore/src/test/java/org/mifospay/core/datastore/ExampleUnitTest.kt deleted file mode 100644 index e4d40ddc7..000000000 --- a/core/datastore/src/test/java/org/mifospay/core/datastore/ExampleUnitTest.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.datastore - -import org.junit.Assert.assertEquals -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt new file mode 100644 index 000000000..54213d788 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt @@ -0,0 +1,10 @@ +package org.mifospay.core.model + +data class ClientInfo( + val name: String, + val image: String, + val externalId: String, + val clientId: Long, + val displayName: String, + val mobileNo: String, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt new file mode 100644 index 000000000..c100f8e69 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt @@ -0,0 +1,8 @@ +package org.mifospay.core.model + +data class RoleInfo( + val id: String, + val name: String, + val description: String, + val disabled: Boolean +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt index 180afee4a..93e6a2875 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt @@ -10,7 +10,16 @@ package org.mifospay.core.model data class UserData( - val isAuthenticated: Boolean, - val userName: String, - val clientId: Long, + val token: String, + val name: String, + val username: String, + val email: String, + val mobileNo: String, + val userId: Int, + val clientId: Int, + val clientVpa: String, + val accountId: Int, + val firebaseRegId: String, + val client: ClientInfo, + val user: UserInfo, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt new file mode 100644 index 000000000..c5274d25d --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt @@ -0,0 +1,15 @@ +package org.mifospay.core.model + +data class UserInfo( + val username: String, + val userId: Int, + val base64EncodedAuthenticationKey: String, + val authenticated: Boolean, + val officeId: Int, + val officeName: String, + val roles: List, + val permissions: List, + val clients: List, + val shouldRenewPassword: Boolean, + val isTwoFactorAuthenticationRequired: Boolean +) From 278da28c33a1130cc3fbda64b91a31d0ac11e6fd Mon Sep 17 00:00:00 2001 From: Sk Niyaj Ali Date: Mon, 30 Sep 2024 13:42:32 +0530 Subject: [PATCH 05/31] Feat: [:core:network] - Migrated to KMP (#1772) * Feat: [:core:network] - Migrated to KMP * Feat: [:core:data] - Migrated to KMP Library --- .../kotlin/KotlinInjectConventionPlugin.kt | 2 - .../kotlin/org/mifospay/core/common/Result.kt | 16 + .../org/mifospay/core/data/base/TaskLooper.kt | 62 ---- .../core/data/base/ThreadPoolQueue.kt | 24 -- .../org/mifospay/core/data/base/UseCase.kt | 45 --- .../mifospay/core/data/base/UseCaseFactory.kt | 33 -- .../mifospay/core/data/base/UseCaseHandler.kt | 65 ---- .../core/data/base/UseCaseScheduler.kt | 28 -- .../data/base/UseCaseThreadPoolScheduler.kt | 59 ---- .../org/mifospay/core/data/di/DataModule.kt | 214 ------------ .../usecase/account/BlockUnblockCommand.kt | 46 --- .../account/DownloadTransactionReceipt.kt | 45 --- .../domain/usecase/account/FetchAccount.kt | 66 ---- .../account/FetchAccountTransaction.kt | 62 ---- .../account/FetchAccountTransactions.kt | 53 --- .../usecase/account/FetchAccountTransfer.kt | 40 --- .../domain/usecase/account/FetchAccounts.kt | 55 --- .../domain/usecase/account/FetchMerchants.kt | 53 --- .../domain/usecase/account/TransferFunds.kt | 275 --------------- .../domain/usecase/client/CreateClient.kt | 54 --- .../domain/usecase/client/FetchClientData.kt | 75 ---- .../usecase/client/FetchClientDetails.kt | 44 --- .../domain/usecase/client/FetchClientImage.kt | 45 --- .../domain/usecase/client/SearchClient.kt | 55 --- .../domain/usecase/client/UpdateClient.kt | 55 --- .../usecase/history/TransactionsHistory.kt | 44 --- .../domain/usecase/invoice/FetchInvoice.kt | 63 ---- .../domain/usecase/invoice/FetchInvoices.kt | 48 --- .../usecase/kyc/FetchKYCLevel1Details.kt | 47 --- .../usecase/kyc/UpdateKYCLevel1Details.kt | 51 --- .../data/domain/usecase/kyc/UploadKYCDocs.kt | 57 ---- .../usecase/kyc/UploadKYCLevel1Details.kt | 50 --- .../notification/FetchNotifications.kt | 46 --- .../data/domain/usecase/savedcards/AddCard.kt | 43 --- .../domain/usecase/savedcards/DeleteCard.kt | 43 --- .../domain/usecase/savedcards/EditCard.kt | 44 --- .../usecase/savedcards/FetchSavedCards.kt | 48 --- .../CreateStandingTransaction.kt | 206 ----------- .../DeleteStandingInstruction.kt | 47 --- .../FetchStandingInstruction.kt | 46 --- .../GetAllStandingInstructions.kt | 51 --- .../UpdateStandingInstruction.kt | 89 ----- .../usecase/twofactor/FetchDeliveryMethods.kt | 45 --- .../domain/usecase/twofactor/RequestOTP.kt | 42 --- .../domain/usecase/twofactor/ValidateOTP.kt | 43 --- .../domain/usecase/user/AuthenticateUser.kt | 45 --- .../data/domain/usecase/user/CreateUser.kt | 51 --- .../data/domain/usecase/user/DeleteUser.kt | 42 --- .../domain/usecase/user/FetchUserDetails.kt | 42 --- .../data/domain/usecase/user/FetchUsers.kt | 51 --- .../data/domain/usecase/user/RegisterUser.kt | 45 --- .../data/domain/usecase/user/UpdateUser.kt | 52 --- .../data/domain/usecase/user/VerifyUser.kt | 44 --- .../fineract/entity/mapper/AccountMapper.kt | 35 -- .../entity/mapper/ClientDetailsMapper.kt | 34 -- .../fineract/entity/mapper/CurrencyMapper.kt | 23 -- .../fineract/entity/mapper/FetchAccount.kt | 62 ---- .../entity/mapper/SearchedEntitiesMapper.kt | 33 -- .../entity/mapper/TransactionMapper.kt | 60 ---- .../fineract/repository/FineractRepository.kt | 320 ------------------ .../auth/AuthenticationUserRepository.kt | 35 -- .../data/repository/local/LocalRepository.kt | 33 -- .../local/MifosLocalAssetRepository.kt | 47 --- .../di/AndroidPlatformDependentDataModule.kt | 32 ++ .../core/data/di/AndroidPlatformModule.kt | 41 +++ .../util/ConnectivityManagerNetworkMonitor.kt | 20 +- .../core/data/util/ErrorJsonMessageHelper.kt | 0 .../data/util/TimeZoneBroadcastMonitor.kt} | 12 +- .../assets/banks.json | 0 .../assets/cities.json | 0 .../assets/countriesToCities.json | 0 .../data/di/PlatformDependentDataModule.kt} | 12 +- .../mifospay/core/data/di/RepositoryModule.kt | 77 +++++ .../core/data/mapper/AccountMapper.kt | 26 ++ .../core/data/mapper/ClientDetailsMapper.kt | 34 ++ .../core/data/mapper/CurrencyMapper.kt | 21 ++ .../data/mapper/SearchedEntitiesMapper.kt | 23 ++ .../core/data/mapper/TransactionMapper.kt | 36 ++ .../data/repository/AccountRepository.kt} | 14 +- .../repository/AuthenticationRepository.kt | 19 ++ .../data/repository/BeneficiaryRepository.kt | 33 ++ .../core/data/repository/ClientRepository.kt | 36 ++ .../data/repository/DocumentRepository.kt | 40 +++ .../core/data/repository/InvoiceRepository.kt | 31 ++ .../data/repository/KycLevelRepository.kt | 29 ++ .../repository/NotificationRepository.kt} | 12 +- .../data/repository/RegistrationRepository.kt | 20 ++ .../data/repository/RunReportRepository.kt | 21 ++ .../data/repository/SavedCardRepository.kt | 25 ++ .../repository/SavingsAccountRepository.kt | 38 +++ .../core/data/repository/SearchRepository.kt | 22 ++ .../data/repository/SelfServiceRepository.kt | 52 +++ .../StandingInstructionRepository.kt | 37 ++ .../ThirdPartyTransferRepository.kt | 22 ++ .../repository/TwoFactorAuthRepository.kt | 23 ++ .../core/data/repository/UserRepository.kt | 29 ++ .../repositoryImp/AccountRepositoryImpl.kt | 32 ++ .../AuthenticationRepositoryImpl.kt | 29 ++ .../BeneficiaryRepositoryImpl.kt | 60 ++++ .../repositoryImp/ClientRepositoryImpl.kt | 78 +++++ .../repositoryImp/DocumentRepositoryImpl.kt | 77 +++++ .../repositoryImp/InvoiceRepositoryImpl.kt | 57 ++++ .../repositoryImp/KycLevelRepositoryImpl.kt | 49 +++ .../NotificationRepositoryImpl.kt | 32 ++ .../RegistrationRepositoryImpl.kt | 45 +++ .../repositoryImp/RunReportRepositoryImpl.kt | 37 ++ .../repositoryImp/SavedCardRepositoryImpl.kt | 47 +++ .../SavingsAccountRepositoryImpl.kt | 83 +++++ .../repositoryImp/SearchRepositoryImpl.kt | 34 ++ .../SelfServiceRepositoryImpl.kt | 95 ++++++ .../StandingInstructionRepositoryImpl.kt | 69 ++++ .../ThirdPartyTransferRepositoryImpl.kt | 38 +++ .../TwoFactorAuthRepositoryImpl.kt | 39 +++ .../data/repositoryImp/UserRepositoryImpl.kt | 47 +++ .../org/mifospay/core/data/util/Constants.kt | 8 +- .../mifospay/core/data/util/NetworkMonitor.kt | 0 .../core/data/util/TimeZoneMonitor.kt} | 20 +- .../data/JvmPlatformDependentDataModule.kt | 33 ++ .../data/NativePlatformDependentDataModule.kt | 33 ++ .../core/datastore/proto/ClientPreferences.kt | 11 +- .../core/datastore/proto/RolePreferences.kt | 13 +- .../datastore/proto/UserInfoPreferences.kt | 13 +- .../core/datastore/proto/UserPreferences.kt | 9 + .../core/model/domain/client/Client.kt | 17 +- .../entity/accounts/savings/PaymentType.kt | 1 + ...ns.kt => SavingsWithAssociationsEntity.kt} | 31 +- .../accounts/savings/TransactionType.kt | 4 +- ...{Transactions.kt => TransactionsEntity.kt} | 28 +- .../client/{Client.kt => ClientEntity.kt} | 27 +- .../StandingInstruction.kt | 6 +- core/network/build.gradle.kts | 4 + .../mifospay/core/network/ApiInterceptor.kt | 39 --- .../core/network/JvmLocalAssetManager.kt | 37 -- .../mifospay/core/network/KtorInterceptor.kt | 48 --- .../core/network/MifosWalletOkHttpClient.kt | 84 ----- .../mifospay/core/network/di/NetworkModule.kt | 233 ------------- .../core/network/services/ClientService.kt | 65 ---- .../services/KtorAuthenticationService.kt | 32 -- .../services/KtorSavingsAccountService.kt | 81 ----- .../services/ThirdPartyTransferService.kt | 30 -- .../core/network/services/UserService.kt | 47 --- .../assets/banks.json | 0 .../assets/cities.json | 0 .../assets/countries.json | 0 .../assets/countriesToCities.json | 0 .../assets/states.json | 0 .../org/mifospay/core/network/ApiEndPoints.kt | 0 .../org/mifospay/core/network/BaseURL.kt | 25 +- .../core/network/FineractApiManager.kt | 54 +-- .../mifospay/core/network/KtorfitClient.kt | 187 ++++++++++ .../core/network/SelfServiceApiManager.kt | 23 +- .../mifospay/core/network/di/LocalModule.kt | 6 +- .../mifospay/core/network/di/NetworkModule.kt | 50 +++ .../org/mifospay/core/network/di/Qualifier.kt | 4 +- .../localAssets/JvmLocalAssetManager.kt | 22 ++ .../localAssets/LocalAssetDataSource.kt | 0 .../network/localAssets/LocalAssetManager.kt | 4 +- .../localAssets/MifosLocalAssetDataSource.kt | 27 +- .../core/network/model/CommonResponse.kt} | 9 +- .../core/network/model}/GenericResponse.kt | 2 +- .../services/AccountTransfersService.kt | 10 +- .../network/services/AuthenticationService.kt | 12 +- .../network/services/BeneficiaryService.kt | 39 +-- .../core/network/services/ClientService.kt | 60 ++++ .../core/network/services/DocumentService.kt | 43 ++- .../core/network/services/InvoiceService.kt | 58 ++-- .../core/network/services/KYCLevel1Service.kt | 29 +- .../network/services/NotificationService.kt | 13 +- .../network/services/RegistrationService.kt | 14 +- .../core/network/services/RunReportService.kt | 16 +- .../core/network/services/SavedCardService.kt | 29 +- .../services/SavingsAccountsService.kt | 60 ++++ .../core/network/services/SearchService.kt | 12 +- .../services/StandingInstructionService.kt | 34 +- .../services/ThirdPartyTransferService.kt | 27 ++ .../network/services/TwoFactorAuthService.kt | 21 +- .../core/network/services/UserService.kt | 45 +++ gradle/libs.versions.toml | 6 +- settings.gradle.kts | 2 +- 179 files changed, 2570 insertions(+), 4890 deletions(-) create mode 100644 core/common/src/commonMain/kotlin/org/mifospay/core/common/Result.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/base/TaskLooper.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/base/ThreadPoolQueue.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/base/UseCase.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseFactory.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseHandler.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseScheduler.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseThreadPoolScheduler.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/di/DataModule.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalRepository.kt delete mode 100644 core/data/src/androidMain/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt create mode 100644 core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformDependentDataModule.kt create mode 100644 core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformModule.kt rename core/data/src/androidMain/{java => kotlin}/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt (84%) rename core/data/src/androidMain/{java => kotlin}/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt (100%) rename core/data/src/androidMain/{java/org/mifospay/core/data/util/TimeZoneMonitor.kt => kotlin/org/mifospay/core/data/util/TimeZoneBroadcastMonitor.kt} (91%) rename core/data/src/{androidMain => commonMain}/assets/banks.json (100%) rename core/data/src/{androidMain => commonMain}/assets/cities.json (100%) rename core/data/src/{androidMain => commonMain}/assets/countriesToCities.json (100%) rename core/data/src/{androidMain/java/org/mifospay/core/data/di/LocalDataModule.kt => commonMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.kt} (58%) create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/di/RepositoryModule.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/AccountMapper.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/ClientDetailsMapper.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/CurrencyMapper.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/SearchedEntitiesMapper.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TransactionMapper.kt rename core/data/src/{androidMain/java/org/mifospay/core/data/repository/auth/UserDataRepository.kt => commonMain/kotlin/org/mifospay/core/data/repository/AccountRepository.kt} (57%) create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/InvoiceRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/KycLevelRepository.kt rename core/data/src/{androidMain/java/org/mifospay/core/data/domain/usecase/history/HistoryContract.kt => commonMain/kotlin/org/mifospay/core/data/repository/NotificationRepository.kt} (51%) create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RegistrationRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RunReportRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavedCardRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavingsAccountRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/StandingInstructionRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ThirdPartyTransferRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/TwoFactorAuthRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AccountRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/InvoiceRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/KycLevelRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/NotificationRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RegistrationRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RunReportRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavedCardRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavingsAccountRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/StandingInstructionRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ThirdPartyTransferRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/TwoFactorAuthRepositoryImpl.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt rename core/data/src/{androidMain/java => commonMain/kotlin}/org/mifospay/core/data/util/Constants.kt (92%) rename core/data/src/{androidMain/java => commonMain/kotlin}/org/mifospay/core/data/util/NetworkMonitor.kt (100%) rename core/data/src/{androidMain/java/org/mifospay/core/data/repository/local/LocalAssetRepository.kt => commonMain/kotlin/org/mifospay/core/data/util/TimeZoneMonitor.kt} (50%) create mode 100644 core/data/src/jvmMain/kotlin/org/mifospay/core/data/JvmPlatformDependentDataModule.kt create mode 100644 core/data/src/nativeMain/kotlin/org/mifospay/core/data/NativePlatformDependentDataModule.kt rename core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/{SavingsWithAssociations.kt => SavingsWithAssociationsEntity.kt} (64%) rename core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/{Transactions.kt => TransactionsEntity.kt} (64%) rename core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/{Client.kt => ClientEntity.kt} (68%) delete mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiInterceptor.kt delete mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt delete mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorInterceptor.kt delete mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt delete mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt delete mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ClientService.kt delete mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt delete mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt delete mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt delete mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/services/UserService.kt rename core/network/src/{androidMain => commonMain}/assets/banks.json (100%) rename core/network/src/{androidMain => commonMain}/assets/cities.json (100%) rename core/network/src/{androidMain => commonMain}/assets/countries.json (100%) rename core/network/src/{androidMain => commonMain}/assets/countriesToCities.json (100%) rename core/network/src/{androidMain => commonMain}/assets/states.json (100%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/ApiEndPoints.kt (100%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/BaseURL.kt (52%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/FineractApiManager.kt (54%) create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt (56%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/di/LocalModule.kt (77%) create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/di/Qualifier.kt (93%) create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt (100%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt (85%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt (61%) rename core/network/src/{androidMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt => commonMain/kotlin/org/mifospay/core/network/model/CommonResponse.kt} (68%) rename core/network/src/{androidMain/kotlin/org/mifospay/core/network => commonMain/kotlin/org/mifospay/core/network/model}/GenericResponse.kt (91%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt (74%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/AuthenticationService.kt (69%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt (50%) create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/DocumentService.kt (82%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/InvoiceService.kt (52%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt (64%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/NotificationService.kt (64%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/RegistrationService.kt (57%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/RunReportService.kt (67%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/SavedCardService.kt (64%) create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/SearchService.kt (71%) rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt (72%) create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt rename core/network/src/{androidMain => commonMain}/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt (59%) create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt diff --git a/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt index 977f01b2d..cb89515b6 100644 --- a/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt @@ -21,8 +21,6 @@ class KotlinInjectConventionPlugin: Plugin { // add("kspWasmJs", libs.findLibrary("kotlin.inject.compiler.ksp").get()) add("kspAndroid", libs.findLibrary("kotlin.inject.compiler.ksp").get()) add("kspJvm", libs.findLibrary("kotlin.inject.compiler.ksp").get()) - add("kspMacosX64", libs.findLibrary("kotlin.inject.compiler.ksp").get()) - add("kspMacosArm64", libs.findLibrary("kotlin.inject.compiler.ksp").get()) } } } diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/Result.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Result.kt new file mode 100644 index 000000000..19a72890e --- /dev/null +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Result.kt @@ -0,0 +1,16 @@ +package org.mifospay.core.common + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.onStart + +sealed interface Result { + data class Success(val data: T) : Result + data class Error(val exception: Throwable) : Result + data object Loading : Result +} + +fun Flow.asResult(): Flow> = map> { Result.Success(it) } + .onStart { emit(Result.Loading) } + .catch { emit(Result.Error(it)) } \ No newline at end of file diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/base/TaskLooper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/TaskLooper.kt deleted file mode 100644 index 6fa7abbf7..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/base/TaskLooper.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.base - -import org.mifospay.core.data.base.UseCase.UseCaseCallback - -class TaskLooper( - private val mUseCaseHandler: UseCaseHandler, -) { - var isFailed = false - private var tasksPending: Long = 0 - private var listener: Listener? = null - - fun addTask( - useCase: UseCase, - values: T, - taskData: TaskData, - ) { - tasksPending++ - mUseCaseHandler.execute( - useCase, - values, - object : UseCaseCallback { - override fun onSuccess(response: R) { - if (isFailed) return - listener!!.onTaskSuccess(taskData, response) - tasksPending-- - if (isCompleted) { - listener!!.onComplete() - } - } - - override fun onError(message: String) { - isFailed = true - listener!!.onFailure(message) - } - }, - ) - } - - private val isCompleted: Boolean - get() = tasksPending == 0L - - fun listen(listener: Listener?) { - this.listener = listener - } - - interface Listener { - fun onTaskSuccess(taskData: TaskData, response: R) - fun onComplete() - fun onFailure(message: String?) - } - - class TaskData(var taskName: String, var taskId: Int) -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/base/ThreadPoolQueue.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/ThreadPoolQueue.kt deleted file mode 100644 index 083de6576..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/base/ThreadPoolQueue.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.base - -import java.util.concurrent.ArrayBlockingQueue - -class ThreadPoolQueue(capacity: Int) : ArrayBlockingQueue(capacity) { - - override fun offer(e: Runnable?): Boolean { - try { - put(e) - } catch (e1: InterruptedException) { - return false - } - return true - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCase.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCase.kt deleted file mode 100644 index 2784fd0a8..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCase.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.base - -/** - * Use cases are the entry points to the domain layer. - * - * @param the request type - * @param

the response type -

*/ -abstract class UseCase { - lateinit var walletRequestValues: Q - lateinit var useCaseCallback: UseCaseCallback

- - fun setRequestValues(requestValues: Q) { - this.walletRequestValues = requestValues - } - - fun run() { - executeUseCase(walletRequestValues) - } - - protected abstract fun executeUseCase(requestValues: Q) - - /** - * Data passed to a request. - */ - interface RequestValues - - /** - * Data received from a request. - */ - interface ResponseValue - interface UseCaseCallback { - fun onSuccess(response: R) - fun onError(message: String) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseFactory.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseFactory.kt deleted file mode 100644 index d7f6b510b..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseFactory.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.base - -import org.mifospay.core.data.domain.usecase.account.FetchAccountTransfer -import org.mifospay.core.data.domain.usecase.client.FetchClientDetails -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants - -class UseCaseFactory( - private val mFineractRepository: FineractRepository, -) { - fun getUseCase(useCase: String): UseCase<*, *>? { - return when (useCase) { - Constants.FETCH_ACCOUNT_TRANSFER_USECASE -> { - FetchAccountTransfer(mFineractRepository) - } - - Constants.FETCH_CLIENT_DETAILS_USE_CASE -> { - FetchClientDetails(mFineractRepository) - } - - else -> null - } - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseHandler.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseHandler.kt deleted file mode 100644 index 9fe654b62..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseHandler.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.base - -import org.mifospay.core.data.base.UseCase.UseCaseCallback - -/** - * Runs [UseCase]s using a [UseCaseScheduler]. - */ -class UseCaseHandler(private val mUseCaseScheduler: UseCaseScheduler) { - fun execute( - useCase: UseCase, - values: T?, - callback: UseCaseCallback, - ) { - values?.let { useCase.walletRequestValues = values } - useCase.useCaseCallback = UiCallbackWrapper(callback, this) - mUseCaseScheduler.execute { useCase.run() } - } - - fun notifyResponse( - response: V, - useCaseCallback: UseCaseCallback?, - ) { - mUseCaseScheduler.notifyResponse(response, useCaseCallback) - } - - private fun notifyError( - message: String?, - useCaseCallback: UseCaseCallback?, - ) { - mUseCaseScheduler.onError(message, useCaseCallback) - } - - private class UiCallbackWrapper( - private val mCallback: UseCaseCallback?, - private val mUseCaseHandler: UseCaseHandler, - ) : UseCaseCallback { - override fun onSuccess(response: V) { - mUseCaseHandler.notifyResponse(response, mCallback) - } - - override fun onError(message: String) { - mUseCaseHandler.notifyError(message, mCallback) - } - } - - companion object { - var instance: UseCaseHandler? = null - get() { - if (field == null) { - field = UseCaseHandler(UseCaseThreadPoolScheduler()) - } - return field - } - private set - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseScheduler.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseScheduler.kt deleted file mode 100644 index bff30b7e4..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseScheduler.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.base - -import org.mifospay.core.data.base.UseCase.UseCaseCallback - -/** - * Interface for schedulers, see [UseCaseThreadPoolScheduler]. - */ -interface UseCaseScheduler { - fun execute(runnable: Runnable?) - fun notifyResponse( - response: V, - useCaseCallback: UseCaseCallback?, - ) - - fun onError( - message: String?, - useCaseCallback: UseCaseCallback?, - ) -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseThreadPoolScheduler.kt b/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseThreadPoolScheduler.kt deleted file mode 100644 index 2066f1faa..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/base/UseCaseThreadPoolScheduler.kt +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.base - -import android.os.Handler -import android.os.Looper -import org.mifospay.core.data.base.UseCase.UseCaseCallback -import java.util.concurrent.ThreadPoolExecutor -import java.util.concurrent.TimeUnit - -/** - * Executes asynchronous tasks using a [ThreadPoolExecutor]. - * - * - * See also [ThreadPoolExecutor] for a list of factory methods to create common - * [java.util.concurrent.ExecutorService]s for different scenarios. - */ -class UseCaseThreadPoolScheduler : UseCaseScheduler { - - private val mHandler = Handler(Looper.getMainLooper()) - private var mThreadPoolExecutor: ThreadPoolExecutor = ThreadPoolExecutor( - POOL_SIZE, - MAX_POOL_SIZE, - TIMEOUT.toLong(), - TimeUnit.SECONDS, - ThreadPoolQueue(MAX_POOL_SIZE), - ) - - override fun execute(runnable: Runnable?) { - mThreadPoolExecutor.execute(runnable) - } - - override fun notifyResponse( - response: V, - useCaseCallback: UseCaseCallback?, - ) { - mHandler.post { useCaseCallback!!.onSuccess(response) } - } - - override fun onError( - message: String?, - useCaseCallback: UseCaseCallback?, - ) { - mHandler.post { useCaseCallback!!.onError(message!!) } - } - - companion object { - const val POOL_SIZE = 2 - const val MAX_POOL_SIZE = 40 - const val TIMEOUT = 60 - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/di/DataModule.kt b/core/data/src/androidMain/java/org/mifospay/core/data/di/DataModule.kt deleted file mode 100644 index e498908c9..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/di/DataModule.kt +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.di - -import org.koin.android.ext.koin.androidContext -import org.koin.core.qualifier.named -import org.koin.dsl.module -import org.mifos.core.network.localAssets.LocalAssetDataSource -import org.mifospay.core.data.base.TaskLooper -import org.mifospay.core.data.base.UseCaseFactory -import org.mifospay.core.data.base.UseCaseHandler -import org.mifospay.core.data.base.UseCaseScheduler -import org.mifospay.core.data.base.UseCaseThreadPoolScheduler -import org.mifospay.core.data.domain.usecase.account.BlockUnblockCommand -import org.mifospay.core.data.domain.usecase.account.DownloadTransactionReceipt -import org.mifospay.core.data.domain.usecase.account.FetchAccount -import org.mifospay.core.data.domain.usecase.account.FetchAccountTransaction -import org.mifospay.core.data.domain.usecase.account.FetchAccountTransactions -import org.mifospay.core.data.domain.usecase.account.FetchAccountTransfer -import org.mifospay.core.data.domain.usecase.account.FetchAccounts -import org.mifospay.core.data.domain.usecase.account.FetchMerchants -import org.mifospay.core.data.domain.usecase.account.TransferFunds -import org.mifospay.core.data.domain.usecase.client.CreateClient -import org.mifospay.core.data.domain.usecase.client.FetchClientData -import org.mifospay.core.data.domain.usecase.client.FetchClientDetails -import org.mifospay.core.data.domain.usecase.client.FetchClientImage -import org.mifospay.core.data.domain.usecase.client.SearchClient -import org.mifospay.core.data.domain.usecase.client.UpdateClient -import org.mifospay.core.data.domain.usecase.history.TransactionsHistory -import org.mifospay.core.data.domain.usecase.invoice.FetchInvoice -import org.mifospay.core.data.domain.usecase.invoice.FetchInvoices -import org.mifospay.core.data.domain.usecase.kyc.FetchKYCLevel1Details -import org.mifospay.core.data.domain.usecase.kyc.UpdateKYCLevel1Details -import org.mifospay.core.data.domain.usecase.kyc.UploadKYCDocs -import org.mifospay.core.data.domain.usecase.kyc.UploadKYCLevel1Details -import org.mifospay.core.data.domain.usecase.notification.FetchNotifications -import org.mifospay.core.data.domain.usecase.savedcards.AddCard -import org.mifospay.core.data.domain.usecase.savedcards.DeleteCard -import org.mifospay.core.data.domain.usecase.savedcards.EditCard -import org.mifospay.core.data.domain.usecase.savedcards.FetchSavedCards -import org.mifospay.core.data.domain.usecase.standinginstruction.CreateStandingTransaction -import org.mifospay.core.data.domain.usecase.standinginstruction.DeleteStandingInstruction -import org.mifospay.core.data.domain.usecase.standinginstruction.FetchStandingInstruction -import org.mifospay.core.data.domain.usecase.standinginstruction.GetAllStandingInstructions -import org.mifospay.core.data.domain.usecase.standinginstruction.UpdateStandingInstruction -import org.mifospay.core.data.domain.usecase.twofactor.FetchDeliveryMethods -import org.mifospay.core.data.domain.usecase.twofactor.RequestOTP -import org.mifospay.core.data.domain.usecase.twofactor.ValidateOTP -import org.mifospay.core.data.domain.usecase.user.AuthenticateUser -import org.mifospay.core.data.domain.usecase.user.CreateUser -import org.mifospay.core.data.domain.usecase.user.DeleteUser -import org.mifospay.core.data.domain.usecase.user.FetchUserDetails -import org.mifospay.core.data.domain.usecase.user.FetchUsers -import org.mifospay.core.data.domain.usecase.user.RegisterUser -import org.mifospay.core.data.domain.usecase.user.UpdateUser -import org.mifospay.core.data.domain.usecase.user.VerifyUser -import org.mifospay.core.data.fineract.entity.mapper.AccountMapper -import org.mifospay.core.data.fineract.entity.mapper.ClientDetailsMapper -import org.mifospay.core.data.fineract.entity.mapper.CurrencyMapper -import org.mifospay.core.data.fineract.entity.mapper.SearchedEntitiesMapper -import org.mifospay.core.data.fineract.entity.mapper.TransactionMapper -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.repository.auth.AuthenticationUserRepository -import org.mifospay.core.data.repository.auth.UserDataRepository -import org.mifospay.core.data.repository.local.LocalAssetRepository -import org.mifospay.core.data.repository.local.LocalRepository -import org.mifospay.core.data.repository.local.MifosLocalAssetRepository -import org.mifospay.core.data.util.ConnectivityManagerNetworkMonitor -import org.mifospay.core.data.util.NetworkMonitor -import org.mifospay.core.data.util.TimeZoneBroadcastMonitor -import org.mifospay.core.data.util.TimeZoneMonitor -import org.mifospay.core.datastore.PreferencesHelper -import org.mifospay.core.network.MifosDispatchers -import org.mifospay.core.network.di.LocalModule -import org.mifospay.core.network.localAssets.MifosLocalAssetDataSource - -val DataModule = module { - includes(LocalModule) - - single { UseCaseThreadPoolScheduler() } - single { UseCaseHandler(get()) } - single { TaskLooper(get()) } - single { UseCaseFactory(get()) } - single { FetchClientData(get(), get()) } - single { ClientDetailsMapper() } - single { SearchClient(get(), get()) } - single { UpdateClient(get()) } - single { CreateClient(get()) } - single { FetchClientDetails(get()) } - single { FetchClientImage(get()) } - single { BlockUnblockCommand(get()) } - single { DownloadTransactionReceipt(get()) } - single { AccountMapper(get()) } - single { FetchAccount(get(), get()) } - single { FetchAccounts(get(), get()) } - single { FetchAccountTransaction(get(), get()) } - single { FetchAccountTransactions(get(), get()) } - single { FetchAccountTransfer(get()) } - single { FetchMerchants(get()) } - single { TransferFunds(get()) } - single { - TransactionsHistory( - mUseCaseHandler = get(), - fetchAccountTransactionsUseCase = get(), - ) - } - - // Invoice UseCase - single { FetchInvoice(get()) } - single { FetchInvoices(get()) } - - // KYC UseCase - single { FetchKYCLevel1Details(get()) } - single { UpdateKYCLevel1Details(get()) } - single { UploadKYCDocs(get()) } - single { UploadKYCLevel1Details(get()) } - - // Notifications - single { FetchNotifications(get()) } - - // Saved Cards - single { AddCard(get()) } - single { DeleteCard(get()) } - single { EditCard(get()) } - single { FetchSavedCards(get()) } - - // Standing Instructions - single { CreateStandingTransaction(get()) } - single { DeleteStandingInstruction(get()) } - single { FetchStandingInstruction(get()) } - single { GetAllStandingInstructions(get()) } - single { UpdateStandingInstruction(get()) } - - // Two-Factor - single { FetchDeliveryMethods(get()) } - single { RequestOTP(get()) } - single { ValidateOTP(get()) } - - // User - single { AuthenticateUser(get()) } - single { CreateUser(get()) } - single { DeleteUser(get()) } - single { FetchUserDetails(get()) } - single { FetchUsers(get()) } - single { RegisterUser(get()) } - single { UpdateUser(get()) } - single { VerifyUser(get()) } - - // Fineract Entity Mappers - single { CurrencyMapper() } - single { SearchedEntitiesMapper() } - single { TransactionMapper(get()) } - single { AccountMapper(get()) } - single { ClientDetailsMapper() } - - // Fineract Repository - - single { - FineractRepository( - fineractApiManager = get(), - selfApiManager = get(), - ktorAuthenticationService = get(), - ) - } - - // Fineract Repository Auth - - single { AuthenticationUserRepository(get()) } - - // Fineract Repository Local - - single { - val preferencesHelper: PreferencesHelper = get() - LocalRepository(preferencesHelper) - } - - factory { - MifosLocalAssetDataSource( - ioDispatcher = get( - named(MifosDispatchers.IO.name), - ), - networkJson = get(), - assets = get(), - ) - } - - factory { - MifosLocalAssetRepository( - ioDispatcher = get( - named(MifosDispatchers.IO.name), - ), - datasource = get(), - ) - } - - // Util - - single { ConnectivityManagerNetworkMonitor(context = androidContext()) } - - single { - TimeZoneBroadcastMonitor( - context = androidContext(), - appScope = get(named("ApplicationScope")), - ioDispatcher = get(named(MifosDispatchers.IO.name)), - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt deleted file mode 100644 index 45075fd22..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/BlockUnblockCommand.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.account - -import android.util.Log -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository - -class BlockUnblockCommand( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - CoroutineScope(Dispatchers.IO).launch { - try { - val res = mFineractRepository.blockUnblockAccount( - requestValues.accountId, - requestValues.command, - ) - withContext(Dispatchers.Main) { - Log.d("BlockUnblockCommand@@@@", "$res") - useCaseCallback.onSuccess(ResponseValue) - } - } catch (e: Exception) { - Log.d("BlockUnblockCommand@@@@", "${e.message}") - useCaseCallback.onError( - "Error " + requestValues.command + "ing account", - ) - } - } - } - - data class RequestValues(val accountId: Long, val command: String) : UseCase.RequestValues - data object ResponseValue : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt deleted file mode 100644 index 36d955040..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/DownloadTransactionReceipt.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.account - -import okhttp3.ResponseBody -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class DownloadTransactionReceipt( - private val mFineractRepository: FineractRepository, -) : UseCase() { - override fun executeUseCase(requestValues: RequestValues) { - requestValues.transactionId?.let { - mFineractRepository.getTransactionReceipt(Constants.PDF, it) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(t: ResponseBody) { - useCaseCallback.onSuccess(ResponseValue(t)) - } - }, - ) - } - } - - data class RequestValues(val transactionId: String?) : UseCase.RequestValues - data class ResponseValue(val responseBody: ResponseBody) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt deleted file mode 100644 index 4bc88a5e1..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccount.kt +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.account - -import com.mifospay.core.model.domain.Account -import com.mifospay.core.model.entity.client.ClientAccounts -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.entity.mapper.AccountMapper -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchAccount( - private val fineractRepository: FineractRepository, - private val accountMapper: AccountMapper, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - fineractRepository.getSelfAccounts(requestValues.clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_ACCOUNTS) - } - - override fun onNext(clientAccounts: ClientAccounts) { - val accounts = accountMapper.transform(clientAccounts) - - if (accounts.isNotEmpty()) { - var walletAccount: Account? = null - for (account in accounts) { - if (account.productId.toInt() == Constants.WALLET_ACCOUNT_SAVINGS_PRODUCT_ID) { - walletAccount = account - break - } - } - if (walletAccount != null) { - useCaseCallback.onSuccess(ResponseValue(walletAccount)) - } else { - useCaseCallback.onError(Constants.NO_ACCOUNT_FOUND) - } - } else { - useCaseCallback.onError(Constants.NO_ACCOUNTS_FOUND) - } - } - }, - ) - } - - data class RequestValues(val clientId: Long) : UseCase.RequestValues - - data class ResponseValue(val account: Account) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt deleted file mode 100644 index 6ad743a05..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransaction.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.account - -import android.util.Log -import com.mifospay.core.model.domain.Transaction -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.entity.mapper.TransactionMapper -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants - -class FetchAccountTransaction( - private val fineractRepository: FineractRepository, - private val transactionMapper: TransactionMapper, -) : - UseCase() { - override fun executeUseCase(requestValues: RequestValues) { - CoroutineScope(Dispatchers.IO).launch { - try { - val res = fineractRepository.getSelfAccountTransactionFromId( - requestValues.accountId, - requestValues.transactionId, - ) - withContext(Dispatchers.Main) { - Log.d("FetchTransactions@@@@", "$res") - useCaseCallback.onSuccess( - ResponseValue(transactionMapper.transformInvoice(res)), - ) - } - } catch (e: Exception) { - Log.d("FetchTransactions@@@@", "${e.message}") - withContext(Dispatchers.Main) { - if (e.message == "HTTP 401 Unauthorized") { - useCaseCallback.onError(Constants.UNAUTHORIZED_ERROR) - } else { - useCaseCallback.onError( - Constants.ERROR_FETCHING_REMOTE_ACCOUNT_TRANSACTIONS, - ) - } - } - } - } - } - - data class RequestValues( - val accountId: Long, - val transactionId: Long, - ) : UseCase.RequestValues - - data class ResponseValue(val transaction: Transaction) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt deleted file mode 100644 index 7ab0830d4..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransactions.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.account - -import android.util.Log -import com.mifospay.core.model.domain.Transaction -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.entity.mapper.TransactionMapper -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants - -class FetchAccountTransactions( - private val fineractRepository: FineractRepository, - private val transactionMapper: TransactionMapper, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - CoroutineScope(Dispatchers.IO).launch { - try { - val api = fineractRepository.getSelfAccountTransactions(requestValues.accountId) - withContext(Dispatchers.Main) { - Log.d("FetchTransactions@@@@", "$api") - useCaseCallback.onSuccess( - ResponseValue( - transactionMapper.transformTransactionList(api), - ), - ) - } - } catch (e: Exception) { - withContext(Dispatchers.Main) { - Log.d("FetchTransactions@@@@", "${e.message}") - useCaseCallback.onError( - Constants.ERROR_FETCHING_REMOTE_ACCOUNT_TRANSACTIONS, - ) - } - } - } - } - - data class RequestValues(var accountId: Long) : UseCase.RequestValues - data class ResponseValue(val transactions: List) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt deleted file mode 100644 index 78cc231a7..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccountTransfer.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.account - -import com.mifospay.core.model.entity.accounts.savings.TransferDetail -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchAccountTransfer( - private val mFineractRepository: FineractRepository, -) : UseCase() { - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.getAccountTransfer(requestValues.transferId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe(object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(transferDetail: TransferDetail) { - useCaseCallback.onSuccess(ResponseValue(transferDetail)) - } - }) - } - - data class RequestValues(var transferId: Long) : UseCase.RequestValues - data class ResponseValue(val transferDetail: TransferDetail) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt deleted file mode 100644 index 9b3b4732f..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchAccounts.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.account - -import com.mifospay.core.model.domain.Account -import com.mifospay.core.model.entity.client.ClientAccounts -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.entity.mapper.AccountMapper -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchAccounts( - private val fineractRepository: FineractRepository, - private val accountMapper: AccountMapper, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - fineractRepository.getAccounts(requestValues.clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_ACCOUNTS) - } - - override fun onNext(t: ClientAccounts?) { - if (t != null) { - useCaseCallback.onSuccess( - ResponseValue( - accountMapper.transform(t), - ), - ) - } else { - useCaseCallback.onError(Constants.NO_ACCOUNTS_FOUND) - } - } - }, - ) - } - - data class RequestValues(val clientId: Long) : UseCase.RequestValues - data class ResponseValue(val accountList: List) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt deleted file mode 100644 index 57bdbba0a..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/FetchMerchants.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.account - -import android.util.Log -import com.mifospay.core.model.entity.accounts.savings.SavingsWithAssociations -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants - -class FetchMerchants( - private val mFineractRepository: FineractRepository, -) : UseCase() { - override fun executeUseCase(requestValues: RequestValues) { - CoroutineScope(Dispatchers.IO).launch { - try { - val res = mFineractRepository.savingsAccounts() - withContext(Dispatchers.Main) { - Log.d("FetchMerchants@@@@", "$res") - val savingsWithAssociationsList = res.pageItems - val merchantsList: MutableList = ArrayList() - for (i in savingsWithAssociationsList.indices) { - if (savingsWithAssociationsList[i].savingsProductId == - Constants.MIFOS_MERCHANT_SAVINGS_PRODUCT_ID - ) { - merchantsList.add(savingsWithAssociationsList[i]) - } - } - useCaseCallback.onSuccess(ResponseValue(merchantsList)) - } - } catch (e: Exception) { - Log.d("FetchTransactions@@@@", "${e.message}") - e.message?.let { useCaseCallback.onError(it) } - } - } - } - - class RequestValues : UseCase.RequestValues - data class ResponseValue( - val savingsWithAssociationsList: List, - ) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt deleted file mode 100644 index ec3efb669..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/account/TransferFunds.kt +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.account - -import com.mifospay.core.model.entity.TPTResponse -import com.mifospay.core.model.entity.accounts.savings.SavingAccount -import com.mifospay.core.model.entity.beneficary.Beneficiary -import com.mifospay.core.model.entity.beneficary.BeneficiaryPayload -import com.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload -import com.mifospay.core.model.entity.client.Client -import com.mifospay.core.model.entity.client.ClientAccounts -import com.mifospay.core.model.entity.payload.TransferPayload -import com.mifospay.core.model.utils.DateHelper -import okhttp3.ResponseBody -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -@Suppress("UnusedPrivateMember") -class TransferFunds( - private val apiRepository: FineractRepository, -) : UseCase() { - - // override var requestValues: RequestValues - private lateinit var fromClient: Client - private lateinit var toClient: Client - private lateinit var fromAccount: SavingAccount - private lateinit var toAccount: SavingAccount - - override fun executeUseCase(requestValues: RequestValues) { - this.walletRequestValues = requestValues - apiRepository.getSelfClientDetails(requestValues.fromClientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_CLIENT_DATA) - } - - override fun onNext(client: Client) { - fromClient = client - fetchToClientDetails() - } - }, - ) - } - - private fun fetchToClientDetails() { - apiRepository.getClientDetails(walletRequestValues.toClientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_CLIENT_DATA) - } - - override fun onNext(client: Client) { - toClient = client - fetchFromAccountDetails() - } - }, - ) - } - - private fun fetchFromAccountDetails() { - apiRepository.getSelfAccounts(walletRequestValues.fromClientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_FROM_ACCOUNT) - } - - override fun onNext(clientAccounts: ClientAccounts) { - val accounts = clientAccounts.savingsAccounts - if (accounts.isNotEmpty()) { - var walletAccount: SavingAccount? = null - for (account in accounts) { - if (account.productId == Constants.WALLET_ACCOUNT_SAVINGS_PRODUCT_ID) { - walletAccount = account - break - } - } - if (walletAccount != null) { - fromAccount = walletAccount - fetchToAccountDetails() - } else { - useCaseCallback.onError(Constants.NO_WALLET_FOUND) - } - } else { - useCaseCallback.onError(Constants.ERROR_FETCHING_FROM_ACCOUNT) - } - } - }, - ) - } - - private fun fetchToAccountDetails() { - apiRepository.getAccounts(walletRequestValues.toClientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_TO_ACCOUNT) - } - - override fun onNext(clientAccounts: ClientAccounts) { - val accounts = clientAccounts.savingsAccounts - if (accounts.isNotEmpty()) { - var walletAccount: SavingAccount? = null - for (account in accounts) { - if (account.productId == Constants.WALLET_ACCOUNT_SAVINGS_PRODUCT_ID) { - walletAccount = account - break - } - } - if (walletAccount != null) { - toAccount = walletAccount - makeTransfer() - } else { - useCaseCallback.onError(Constants.NO_WALLET_FOUND) - } - } else { - useCaseCallback.onError(Constants.ERROR_FETCHING_TO_ACCOUNT) - } - } - }, - ) - } - - private fun checkBeneficiary() { - apiRepository.beneficiaryList - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber>() { - override fun onCompleted() {} - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_BENEFICIARIES) - } - - override fun onNext(beneficiaries: List) { - var exists = false - beneficiaries.forEach { beneficiary -> - if (beneficiary.accountNumber == toAccount.accountNo) { - exists = true - if (beneficiary.transferLimit >= walletRequestValues.amount) { - makeTransfer() - } else { - updateTransferLimit(beneficiary.id?.toLong()!!) - } - return@forEach - } - } - if (!exists) { - addBeneficiary() - } - } - }, - ) - } - - private fun addBeneficiary() { - val payload = BeneficiaryPayload().apply { - accountNumber = toAccount.accountNo - name = toClient.displayName - officeName = toClient.officeName - transferLimit = walletRequestValues.amount.toInt() - accountType = 2 - } - - apiRepository.createBeneficiary(payload) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_ADDING_BENEFICIARY) - } - - override fun onNext(responseBody: ResponseBody) { - makeTransfer() - } - }, - ) - } - - private fun updateTransferLimit(beneficiaryId: Long) { - val updatePayload = BeneficiaryUpdatePayload().apply { - transferLimit = walletRequestValues.amount.toInt() - } - apiRepository.updateBeneficiary(beneficiaryId, updatePayload) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_ADDING_BENEFICIARY) - } - - override fun onNext(responseBody: ResponseBody) { - makeTransfer() - } - }, - ) - } - - private fun makeTransfer() { - val transferPayload = TransferPayload().apply { - fromAccountId = fromAccount.id.toInt() - fromClientId = fromClient.id.toLong() - fromAccountType = 2 - fromOfficeId = fromClient.officeId - toOfficeId = toClient.officeId - toAccountId = toAccount.id.toInt() - toClientId = toClient.id.toLong() - toAccountType = 2 - transferDate = DateHelper.getDateAsStringFromLong(System.currentTimeMillis()) - transferAmount = walletRequestValues.amount - transferDescription = Constants.WALLET_TRANSFER - } - - apiRepository.makeThirdPartyTransfer(transferPayload) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_MAKING_TRANSFER) - } - - override fun onNext(responseBody: TPTResponse) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } - - data class RequestValues( - val fromClientId: Long, - val toClientId: Long, - val amount: Double, - ) : UseCase.RequestValues - - class ResponseValue : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt deleted file mode 100644 index fd84e1477..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/CreateClient.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.client - -import com.mifospay.core.model.domain.client.NewClient -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.ErrorJsonMessageHelper.getUserMessage -import retrofit2.HttpException -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class CreateClient( - private val apiRepository: FineractRepository, -) : UseCase() { - - data class RequestValues(val client: NewClient) : UseCase.RequestValues - - data class ResponseValue(val clientId: Int) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - apiRepository.createClient(requestValues.client) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - var message: String - try { - message = - (e as HttpException).response()?.errorBody()?.string().toString() - message = getUserMessage(message) - } catch (e1: Exception) { - message = e1.message.toString() - } - useCaseCallback.onError(message) - } - - override fun onNext(genericResponse: ResponseValue) { - useCaseCallback.onSuccess(genericResponse) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt deleted file mode 100644 index ad588cd33..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientData.kt +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.client - -import com.mifospay.core.model.entity.Page -import com.mifospay.core.model.entity.client.Client -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.entity.mapper.ClientDetailsMapper -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchClientData( - private val fineractRepository: FineractRepository, - private val clientDetailsMapper: ClientDetailsMapper, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - requestValues.clientId?.let { clientId -> - fineractRepository.getSelfClientDetails(clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_CLIENT_DATA) - } - - override fun onNext(client: Client) { - useCaseCallback.onSuccess( - ResponseValue(clientDetailsMapper.transform(client)), - ) - } - }, - ) - } ?: run { - fineractRepository.selfClientDetails - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber>() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_CLIENT_DATA) - } - - override fun onNext(client: Page) { - if (client.pageItems.size != 0) { - useCaseCallback.onSuccess( - ResponseValue(clientDetailsMapper.transform(client.pageItems[0])), - ) - } else { - useCaseCallback.onError(Constants.NO_CLIENT_FOUND) - } - } - }, - ) - } - } - - data class RequestValues(val clientId: Long?) : UseCase.RequestValues - data class ResponseValue( - val clientDetails: com.mifospay.core.model.domain.client.Client, - ) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt deleted file mode 100644 index 3ab9b074f..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientDetails.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.client - -import com.mifospay.core.model.entity.client.Client -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchClientDetails( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - data class RequestValues(val clientId: Long) : UseCase.RequestValues - data class ResponseValue(val client: Client) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.getClientDetails(requestValues.clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_CLIENT_DATA) - } - - override fun onNext(client: Client) { - useCaseCallback.onSuccess(ResponseValue(client)) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt deleted file mode 100644 index 90bd05665..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/FetchClientImage.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.client - -import okhttp3.ResponseBody -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.ErrorJsonMessageHelper.getUserMessage -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchClientImage( - private val mFineractRepository: FineractRepository, -) : - UseCase() { - - data class RequestValues(val clientId: Long) : UseCase.RequestValues - data class ResponseValue(val responseBody: ResponseBody) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.getClientImage(requestValues.clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - getUserMessage(e)?.let { useCaseCallback.onError(it) } - } - - override fun onNext(responseBody: ResponseBody) { - useCaseCallback.onSuccess(ResponseValue(responseBody)) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt deleted file mode 100644 index 05b882da0..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/SearchClient.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.client - -import com.mifospay.core.model.domain.SearchResult -import com.mifospay.core.model.entity.SearchedEntity -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.entity.mapper.SearchedEntitiesMapper -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class SearchClient( - private val apiRepository: FineractRepository, - private val searchedEntitiesMapper: SearchedEntitiesMapper, -) : UseCase() { - - data class RequestValues(val externalId: String) : UseCase.RequestValues - data class ResponseValue(val results: List) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - apiRepository.searchResources(requestValues.externalId, Constants.CLIENTS, false) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber>() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_SEARCHING_CLIENTS) - } - - override fun onNext(results: List) { - if (results.isNotEmpty()) { - useCaseCallback.onSuccess( - ResponseValue( - searchedEntitiesMapper.transformList(results), - ), - ) - } else { - useCaseCallback.onError(Constants.NO_CLIENTS_FOUND) - } - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt deleted file mode 100644 index 6badef3e6..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/client/UpdateClient.kt +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.client - -import okhttp3.ResponseBody -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.ErrorJsonMessageHelper.getUserMessage -import retrofit2.HttpException -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class UpdateClient( - private val fineractRepository: FineractRepository, -) : UseCase() { - - data class RequestValues(val updateClientEntity: Any, val clientId: Long) : - UseCase.RequestValues - - data class ResponseValue(val responseBody: ResponseBody) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - fineractRepository.updateClient(requestValues.clientId, requestValues.updateClientEntity) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - var message: String - try { - message = - (e as HttpException).response()?.errorBody()?.string().toString() - message = getUserMessage(message) - } catch (e1: Exception) { - message = e1.message.toString() - } - useCaseCallback.onError(message) - } - - override fun onNext(responseBody: ResponseBody) { - useCaseCallback.onSuccess(ResponseValue(responseBody)) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt deleted file mode 100644 index 10e105b76..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/TransactionsHistory.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.history - -import com.mifospay.core.model.domain.Transaction -import org.mifospay.core.data.base.UseCase.UseCaseCallback -import org.mifospay.core.data.base.UseCaseHandler -import org.mifospay.core.data.domain.usecase.account.FetchAccountTransactions - -class TransactionsHistory( - private val mUseCaseHandler: UseCaseHandler, - private val fetchAccountTransactionsUseCase: FetchAccountTransactions, -) { - var delegate: HistoryContract.TransactionsHistoryAsync? = null - private var transactions: List? - - init { - transactions = ArrayList() - } - - fun fetchTransactionsHistory(accountId: Long) { - mUseCaseHandler.execute( - fetchAccountTransactionsUseCase, - FetchAccountTransactions.RequestValues(accountId), - object : UseCaseCallback { - override fun onSuccess(response: FetchAccountTransactions.ResponseValue?) { - transactions = response?.transactions - delegate!!.onTransactionsFetchCompleted(transactions) - } - - override fun onError(message: String) { - transactions = null - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt deleted file mode 100644 index 4a6cf57ea..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoice.kt +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.invoice - -import android.net.Uri -import android.util.Log -import com.mifospay.core.model.entity.Invoice -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchInvoice( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - class RequestValues(val uniquePaymentLink: Uri?) : UseCase.RequestValues - class ResponseValue( - val invoices: List, - ) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - val paymentLink = requestValues.uniquePaymentLink - try { - val params = paymentLink?.pathSegments - val clientId = params?.get(0) // "clientId" - val invoiceId = params?.get(1) // "invoiceId" - if (clientId != null && invoiceId != null) { - mFineractRepository.fetchInvoice(clientId, invoiceId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber?>() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.INVALID_UPL) - } - - override fun onNext(invoices: List?) { - if (invoices?.isNotEmpty() == true) { - useCaseCallback.onSuccess(ResponseValue(invoices)) - } else { - useCaseCallback.onError(Constants.INVOICE_DOES_NOT_EXIST) - } - } - }, - ) - } - } catch (e: IndexOutOfBoundsException) { - Log.e("Error", e.message.toString()) - useCaseCallback.onError("Invalid link used to open the App") - } - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt deleted file mode 100644 index e9a4b5b2a..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/invoice/FetchInvoices.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.invoice - -import android.util.Log -import com.mifospay.core.model.entity.Invoice -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchInvoices( - private val mFineractRepository: FineractRepository, -) : - UseCase() { - - class RequestValues(val clientId: String) : UseCase.RequestValues - class ResponseValue( - val invoiceList: List, - ) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.fetchInvoices(requestValues.clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber>() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - Log.e("Invoices", e.message.toString()) - useCaseCallback.onError(e.toString()) - } - - override fun onNext(invoices: List) { - useCaseCallback.onSuccess(ResponseValue(invoices)) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt deleted file mode 100644 index 42e9d19c9..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/FetchKYCLevel1Details.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.kyc - -import com.mifospay.core.model.entity.kyc.KYCLevel1Details -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchKYCLevel1Details( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - class RequestValues(val clientId: Int) : UseCase.RequestValues - class ResponseValue( - val kycLevel1DetailsList: List, - ) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.fetchKYCLevel1Details(requestValues.clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber>() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(kycLevel1Details: List) { - useCaseCallback.onSuccess( - ResponseValue(kycLevel1Details), - ) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt deleted file mode 100644 index 6f232ca29..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UpdateKYCLevel1Details.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.kyc - -import com.mifospay.core.model.entity.kyc.KYCLevel1Details -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.network.GenericResponse -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class UpdateKYCLevel1Details( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - class RequestValues( - val clientId: Int, - val kycLevel1Details: KYCLevel1Details, - ) : UseCase.RequestValues - - class ResponseValue : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.updateKYCLevel1Details( - requestValues.clientId, - requestValues.kycLevel1Details, - ) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(t: GenericResponse) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt deleted file mode 100644 index 6eb539c1f..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCDocs.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.kyc - -import okhttp3.MultipartBody -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.network.GenericResponse -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class UploadKYCDocs( - private val apiRepository: FineractRepository, -) : UseCase() { - - class RequestValues( - val entityType: String, - val clientId: Long, - val docname: String, - val identityType: String, - val file: MultipartBody.Part, - ) : UseCase.RequestValues - - class ResponseValue : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - apiRepository.uploadKYCDocs( - requestValues.entityType, - requestValues.clientId, - requestValues.docname, - requestValues.identityType, - requestValues.file, - ) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(t: GenericResponse) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt deleted file mode 100644 index 74ace32cb..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/kyc/UploadKYCLevel1Details.kt +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.kyc - -import com.mifospay.core.model.entity.kyc.KYCLevel1Details -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.network.GenericResponse -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class UploadKYCLevel1Details( - var mFineractRepository: FineractRepository, -) : UseCase() { - class RequestValues( - val clientId: Int, - val mKYCLevel1Details: KYCLevel1Details, - ) : UseCase.RequestValues - - class ResponseValue : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.uploadKYCLevel1Details( - requestValues.clientId, - requestValues.mKYCLevel1Details, - ) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(t: GenericResponse) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt deleted file mode 100644 index 4237dc12a..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/notification/FetchNotifications.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.notification - -import com.mifospay.core.model.domain.NotificationPayload -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchNotifications( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - class RequestValues(val clientId: Long) : UseCase.RequestValues - class ResponseValue( - val notificationPayloadList: List?, - ) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.fetchNotifications(requestValues.clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber>() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_NOTIFICATIONS) - } - - override fun onNext(notificationPayloads: List) { - useCaseCallback.onSuccess(ResponseValue(notificationPayloads)) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt deleted file mode 100644 index 73bb2bbcc..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/AddCard.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.savedcards - -import com.mifospay.core.model.entity.savedcards.Card -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.network.GenericResponse -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class AddCard( - private val mFineractRepository: FineractRepository, -) : UseCase() { - class RequestValues(val clientId: Long, val card: Card) : UseCase.RequestValues - class ResponseValue : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.addSavedCards(requestValues.clientId, requestValues.card) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(t: GenericResponse?) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt deleted file mode 100644 index c11cb90f0..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/DeleteCard.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.savedcards - -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.network.GenericResponse -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class DeleteCard( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - class RequestValues(val clientId: Int, val cardId: Int) : UseCase.RequestValues - class ResponseValue : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.deleteSavedCard(requestValues.clientId, requestValues.cardId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(t: GenericResponse?) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt deleted file mode 100644 index 7f0440b18..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/EditCard.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.savedcards - -import com.mifospay.core.model.entity.savedcards.Card -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.network.GenericResponse -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class EditCard( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - class RequestValues(val clientId: Int, val card: Card) : UseCase.RequestValues - class ResponseValue : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.editSavedCard(requestValues.clientId, requestValues.card) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(t: GenericResponse?) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt deleted file mode 100644 index 8750008de..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/savedcards/FetchSavedCards.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.savedcards - -import com.mifospay.core.model.entity.savedcards.Card -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchSavedCards( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - class RequestValues(val clientId: Long) : UseCase.RequestValues - class ResponseValue(val cardList: List) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.fetchSavedCards(requestValues.clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber>() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(cards: List) { - if (cards.isNotEmpty()) { - useCaseCallback.onSuccess(ResponseValue(cards)) - } else { - useCaseCallback.onError(Constants.NO_SAVED_CARDS) - } - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt deleted file mode 100644 index 5e4dfd300..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/CreateStandingTransaction.kt +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.standinginstruction - -import com.mifospay.core.model.entity.accounts.savings.SavingAccount -import com.mifospay.core.model.entity.client.Client -import com.mifospay.core.model.entity.client.ClientAccounts -import com.mifospay.core.model.entity.payload.StandingInstructionPayload -import com.mifospay.core.model.entity.standinginstruction.SDIResponse -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class CreateStandingTransaction( - private val apiRepository: FineractRepository, -) : UseCase() { - - lateinit var fromClient: Client - lateinit var toClient: Client - lateinit var fromAccount: SavingAccount - lateinit var toAccount: SavingAccount - - override fun executeUseCase(requestValues: RequestValues) { - apiRepository.getSelfClientDetails(requestValues.fromClientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - - override fun onCompleted() { - } - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_CLIENT_DATA) - } - - override fun onNext(client: Client) { - fromClient = client - fetchToClientData() - } - }, - ) - } - - private fun fetchToClientData() { - apiRepository.getClientDetails(walletRequestValues.toClientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - - override fun onCompleted() { - } - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_CLIENT_DATA) - } - - override fun onNext(client: Client) { - toClient = client - fetchFromAccountDetails() - } - }, - ) - } - - private fun fetchFromAccountDetails() { - apiRepository.getSelfAccounts(walletRequestValues.fromClientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() { - } - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_FROM_ACCOUNT) - } - - override fun onNext(clientAccounts: ClientAccounts) { - val accounts = clientAccounts.savingsAccounts - if (accounts.isNotEmpty()) { - var walletAccount: SavingAccount? = null - for (account in accounts) { - if (account.productId == - Constants.WALLET_ACCOUNT_SAVINGS_PRODUCT_ID - ) { - walletAccount = account - break - } - } - walletAccount?.let { - fromAccount = walletAccount - fetchToAccountDetails() - } ?: useCaseCallback.onError(Constants.NO_WALLET_FOUND) - } else { - useCaseCallback.onError(Constants.ERROR_FETCHING_FROM_ACCOUNT) - } - } - }, - ) - } - - private fun fetchToAccountDetails() { - apiRepository.getAccounts(walletRequestValues.toClientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_TO_ACCOUNT) - } - - override fun onNext(clientAccounts: ClientAccounts) { - val accounts = clientAccounts.savingsAccounts - if (accounts.isNotEmpty()) { - var walletAccount: SavingAccount? = null - for (account in accounts) { - if (account.productId == - Constants.WALLET_ACCOUNT_SAVINGS_PRODUCT_ID - ) { - walletAccount = account - break - } - } - walletAccount?.let { - toAccount = walletAccount - createNewStandingInstruction() - } ?: useCaseCallback.onError(Constants.NO_WALLET_FOUND) - } else { - useCaseCallback.onError(Constants.ERROR_FETCHING_TO_ACCOUNT) - } - } - }, - ) - } - - private fun createNewStandingInstruction() { - val standingInstructionPayload = StandingInstructionPayload( - fromClient.officeId, - fromClient.id, - 2, - "wallet standing transaction", - 1, - 2, - 1, - fromAccount.id, - toClient.officeId, - toClient.id, - 2, - toAccount.id, - 1, - walletRequestValues.amount, - walletRequestValues.validFrom, - 1, - walletRequestValues.recurrenceInterval, - 2, - "en", - "dd MM yyyy", - walletRequestValues.validTill, - walletRequestValues.recurrenceOnDayMonth, - "dd MM", - ) - apiRepository.createStandingInstruction(standingInstructionPayload) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - - override fun onCompleted() { - } - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_MAKING_TRANSFER) - } - - override fun onNext(sdiResponse: SDIResponse) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } - - class RequestValues( - val validTill: String, - val validFrom: String, - val recurrenceInterval: Int, - val recurrenceOnDayMonth: String, - val fromClientId: Long, - val toClientId: Long, - val amount: Double, - ) : UseCase.RequestValues - - class ResponseValue : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt deleted file mode 100644 index 569a9149b..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/DeleteStandingInstruction.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.standinginstruction - -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.network.GenericResponse -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class DeleteStandingInstruction( - private val apiRepository: FineractRepository, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - apiRepository.deleteStandingInstruction(requestValues.standingInstructionId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - - override fun onCompleted() { - } - - override fun onError(e: Throwable) { - e.message?.let { useCaseCallback.onError(it) } - } - - override fun onNext(genericResponse: GenericResponse) = - useCaseCallback.onSuccess(ResponseValue()) - }, - ) - } - - class RequestValues(val standingInstructionId: Long) : - UseCase.RequestValues - - class ResponseValue : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt deleted file mode 100644 index 8e165f333..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/FetchStandingInstruction.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.standinginstruction - -import com.mifospay.core.model.entity.standinginstruction.StandingInstruction -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchStandingInstruction( - private val apiRepository: FineractRepository, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - apiRepository.getStandingInstruction(requestValues.standingInstructionId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - - override fun onCompleted() { - } - - override fun onError(e: Throwable) { - e.message?.let { useCaseCallback.onError(it) } - } - - override fun onNext(standingInstruction: StandingInstruction) = - useCaseCallback.onSuccess(ResponseValue(standingInstruction)) - }, - ) - } - - class RequestValues(val standingInstructionId: Long) : UseCase.RequestValues - - class ResponseValue(val standingInstruction: StandingInstruction) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt deleted file mode 100644 index 1e4338704..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/GetAllStandingInstructions.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.standinginstruction - -import com.mifospay.core.model.entity.Page -import com.mifospay.core.model.entity.standinginstruction.StandingInstruction -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class GetAllStandingInstructions( - private val apiRepository: FineractRepository, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - apiRepository.getAllStandingInstructions(requestValues.clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber>() { - - override fun onCompleted() { - } - - override fun onError(e: Throwable) { - e.message?.let { useCaseCallback.onError(it) } - } - - override fun onNext(standingInstructionPage: Page) { - return useCaseCallback.onSuccess( - ResponseValue(standingInstructionPage.pageItems), - ) - } - }, - ) - } - - class RequestValues(val clientId: Long) : UseCase.RequestValues - - class ResponseValue(val standingInstructionsList: List) : - UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt deleted file mode 100644 index 8eef580b2..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/standinginstruction/UpdateStandingInstruction.kt +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.standinginstruction - -import com.mifospay.core.model.entity.payload.StandingInstructionPayload -import com.mifospay.core.model.entity.standinginstruction.StandingInstruction -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.network.GenericResponse -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class UpdateStandingInstruction( - private val apiRepository: FineractRepository, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - val validTillString = "${requestValues.standingInstruction.validTill?.get(2)} " + - "${requestValues.standingInstruction.validTill?.get(1)} " + - "${requestValues.standingInstruction.validTill?.get(0)}" - val validFromString = "${requestValues.standingInstruction.validFrom[2]} " + - "${requestValues.standingInstruction.validFrom[1]} " + - "${requestValues.standingInstruction.validFrom[0]}" - val recurrenceOnMonthDayString = "${requestValues.standingInstruction.validFrom[2]} " + - "${requestValues.standingInstruction.validFrom[1]}" - - val standingInstructionPayload = StandingInstructionPayload( - requestValues.standingInstruction.fromClient.officeId, - requestValues.standingInstruction.fromClient.id, - 2, - "wallet standing transaction", - 1, - 2, - 1, - requestValues.standingInstruction.fromAccount.id, - requestValues.standingInstruction.toClient.officeId, - requestValues.standingInstruction.toClient.id, - 2, - requestValues.standingInstruction.toAccount.id, - 1, - requestValues.standingInstruction.amount, - validFromString, - 1, - 1, - 2, - "en", - "dd MM yyyy", - validTillString, - recurrenceOnMonthDayString, - "dd MM", - ) - - apiRepository.updateStandingInstruction( - requestValues.standingInstructionId, - standingInstructionPayload, - ) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - - override fun onCompleted() { - } - - override fun onError(e: Throwable) { - e.message?.let { useCaseCallback.onError(it) } - } - - override fun onNext(genericResponse: GenericResponse) = - useCaseCallback.onSuccess(ResponseValue()) - }, - ) - } - - class RequestValues( - val standingInstructionId: Long, - val standingInstruction: StandingInstruction, - ) : UseCase.RequestValues - - class ResponseValue : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt deleted file mode 100644 index 29cf2bb7c..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/FetchDeliveryMethods.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.twofactor - -import com.mifospay.core.model.domain.twofactor.DeliveryMethod -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchDeliveryMethods( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - class RequestValues : UseCase.RequestValues - class ResponseValue( - val deliveryMethodList: List, - ) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.deliveryMethods - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber>() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(deliveryMethods: List) { - useCaseCallback.onSuccess(ResponseValue(deliveryMethods)) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt deleted file mode 100644 index 004806f96..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/RequestOTP.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.twofactor - -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class RequestOTP( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - class RequestValues(val deliveryMethod: String) : UseCase.RequestValues - class ResponseValue(val response: String) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.requestOTP(requestValues.deliveryMethod) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(response: String) { - useCaseCallback.onSuccess(ResponseValue(response)) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt deleted file mode 100644 index 1249e58be..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/twofactor/ValidateOTP.kt +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.twofactor - -import com.mifospay.core.model.domain.twofactor.AccessToken -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class ValidateOTP( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - class RequestValues(val token: String) : UseCase.RequestValues - class ResponseValue(val accessToken: AccessToken) : UseCase.ResponseValue - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.validateToken(requestValues.token) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(accessToken: AccessToken) { - useCaseCallback.onSuccess(ResponseValue(accessToken)) - } - }, - ) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt deleted file mode 100644 index c849b1261..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/AuthenticateUser.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.user - -import com.mifospay.core.model.domain.user.User -import com.mifospay.core.model.entity.authentication.AuthenticationPayload -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants - -class AuthenticateUser( - private val apiRepository: FineractRepository, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - CoroutineScope(Dispatchers.IO).launch { - try { - val user = apiRepository.loginSelf( - AuthenticationPayload(requestValues.username, requestValues.password), - ) - withContext(Dispatchers.Main) { - useCaseCallback.onSuccess(ResponseValue(user)) - } - } catch (e: Exception) { - withContext(Dispatchers.Main) { - useCaseCallback.onError(Constants.ERROR_LOGGING_IN) - } - } - } - } - - data class RequestValues(val username: String, val password: String) : UseCase.RequestValues - data class ResponseValue(val user: User) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt deleted file mode 100644 index 79f056b70..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/CreateUser.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.user - -import com.mifospay.core.model.domain.user.NewUser -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.ErrorJsonMessageHelper.getUserMessage -import retrofit2.HttpException -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class CreateUser(private val apiRepository: FineractRepository) : - UseCase() { - override fun executeUseCase(requestValues: RequestValues) { - apiRepository.createUser(requestValues.user) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - getUserMessage(e) - var message: String - try { - message = (e as HttpException).response()!!.errorBody()!!.string() - message = getUserMessage(message) - } catch (e1: Exception) { - message = e1.message.toString() - } - useCaseCallback.onError(message) - } - - override fun onNext(genericResponse: ResponseValue) { - useCaseCallback.onSuccess(genericResponse) - } - }, - ) - } - - class RequestValues(val user: NewUser) : UseCase.RequestValues - class ResponseValue(val userId: Int) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt deleted file mode 100644 index 2a537345f..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/DeleteUser.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.user - -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.network.GenericResponse -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class DeleteUser( - private val mFineractRepository: FineractRepository, -) : UseCase() { - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.deleteUser(requestValues.userId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - e.message?.let { useCaseCallback.onError(it) } - } - - override fun onNext(genericResponse: GenericResponse) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } - - class RequestValues(val userId: Int) : UseCase.RequestValues - class ResponseValue : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt deleted file mode 100644 index 153e46ee0..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUserDetails.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.user - -import com.mifospay.core.model.entity.UserWithRole -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchUserDetails( - private val mFineractRepository: FineractRepository, -) : UseCase() { - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.getUser() - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - e.message?.let { useCaseCallback.onError(it) } - } - - override fun onNext(userWithRole: UserWithRole) { - useCaseCallback.onSuccess(ResponseValue(userWithRole)) - } - }, - ) - } - - class RequestValues(val userId: Long) : UseCase.RequestValues - class ResponseValue(val userWithRole: UserWithRole) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt deleted file mode 100644 index 61340673a..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/FetchUsers.kt +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.user - -import com.mifospay.core.model.entity.UserWithRole -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchUsers( - private val mFineractRepository: FineractRepository, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.users - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe(object : Subscriber>() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(e.toString()) - } - - override fun onNext(userWithRoles: List) { - val tbp: MutableList = ArrayList() - for (userWithRole in userWithRoles) { - for ((_, name) in userWithRole.selectedRoles!!) { - if (name == Constants.MERCHANT) { - tbp.add(userWithRole) - break - } - } - } - useCaseCallback.onSuccess(ResponseValue(tbp)) - } - }) - } - - class RequestValues : UseCase.RequestValues - data class ResponseValue(val userWithRoleList: List) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt deleted file mode 100644 index f37d1df98..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/RegisterUser.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.user - -import com.mifospay.core.model.entity.register.RegisterPayload -import okhttp3.ResponseBody -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class RegisterUser( - private val apiRepository: FineractRepository, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - apiRepository.registerUser(requestValues.registerPayload) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_REGISTERING_USER) - } - - override fun onNext(t: ResponseBody?) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } - - data class RequestValues(val registerPayload: RegisterPayload) : UseCase.RequestValues - class ResponseValue : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt deleted file mode 100644 index 9fac23150..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/UpdateUser.kt +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.user - -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.ErrorJsonMessageHelper.getUserMessage -import org.mifospay.core.network.GenericResponse -import retrofit2.HttpException -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class UpdateUser( - private val mFineractRepository: FineractRepository, -) : UseCase() { - override fun executeUseCase(requestValues: RequestValues) { - mFineractRepository.updateUser(requestValues.updateUserEntity, requestValues.userId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - var message: String - try { - message = (e as HttpException).response()!!.errorBody()!!.string() - message = getUserMessage(message) - } catch (e1: Exception) { - message = e1.message.toString() - } - useCaseCallback.onError(message) - } - - override fun onNext(genericResponse: GenericResponse?) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } - - class RequestValues(val updateUserEntity: Any, val userId: Int) : UseCase.RequestValues - - class ResponseValue : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt b/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt deleted file mode 100644 index d946eff90..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/user/VerifyUser.kt +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.domain.usecase.user - -import com.mifospay.core.model.entity.register.UserVerify -import okhttp3.ResponseBody -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class VerifyUser( - private val apiRepository: FineractRepository, -) : UseCase() { - override fun executeUseCase(requestValues: RequestValues) { - apiRepository.verifyUser(requestValues.userVerify) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe( - object : Subscriber() { - override fun onCompleted() {} - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_VERIFYING_USER) - } - - override fun onNext(t: ResponseBody?) { - useCaseCallback.onSuccess(ResponseValue()) - } - }, - ) - } - - class RequestValues(val userVerify: UserVerify) : UseCase.RequestValues - class ResponseValue : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt deleted file mode 100644 index 672f1a393..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/AccountMapper.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.fineract.entity.mapper - -import com.mifospay.core.model.domain.Account -import com.mifospay.core.model.entity.client.ClientAccounts - -class AccountMapper( - private val currencyMapper: CurrencyMapper, -) { - - fun transform(clientAccounts: ClientAccounts?): List { - val accountList = mutableListOf() - - clientAccounts?.savingsAccounts?.forEach { savingAccount -> - val account = Account( - name = savingAccount.productName, - number = savingAccount.accountNo, - id = savingAccount.id, - balance = savingAccount.accountBalance, - currency = currencyMapper.transform(savingAccount.currency), - productId = savingAccount.productId.toLong(), - ) - accountList.add(account) - } - return accountList - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt deleted file mode 100644 index eccd4a613..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/ClientDetailsMapper.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.fineract.entity.mapper - -import com.mifospay.core.model.entity.client.Client -import com.mifospay.core.model.domain.client.Client as DomainClient - -class ClientDetailsMapper { - fun transformList(clients: List?): List { - val clientList: MutableList = ArrayList() - clients?.forEach { client -> - clientList.add(transform(client)) - } - return clientList - } - - fun transform(client: Client?): DomainClient { - val clientDetails = DomainClient() - if (client != null) { - clientDetails.name = client.displayName - clientDetails.clientId = client.id.toLong() - clientDetails.externalId = client.externalId - clientDetails.mobileNo = client.mobileNo - } - return clientDetails - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt deleted file mode 100644 index 21270ee2d..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/CurrencyMapper.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.fineract.entity.mapper - -import com.mifospay.core.model.entity.accounts.savings.Currency -import com.mifospay.core.model.domain.Currency as DomainCurrency - -class CurrencyMapper { - fun transform(savingsCurrency: Currency): DomainCurrency { - val currency = DomainCurrency() - currency.code = savingsCurrency.code - currency.displayLabel = savingsCurrency.displayLabel - currency.displaySymbol = savingsCurrency.displaySymbol - return currency - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt deleted file mode 100644 index d21aa0b8e..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/FetchAccount.kt +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.fineract.entity.mapper - -import com.mifospay.core.model.domain.Account -import com.mifospay.core.model.entity.client.ClientAccounts -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.fineract.repository.FineractRepository -import org.mifospay.core.data.util.Constants -import rx.Subscriber -import rx.android.schedulers.AndroidSchedulers -import rx.schedulers.Schedulers - -class FetchAccount( - private val fineractRepository: FineractRepository, - private val accountMapper: AccountMapper, -) : UseCase() { - - override fun executeUseCase(requestValues: RequestValues) { - fineractRepository.getSelfAccounts(requestValues.clientId) - .observeOn(AndroidSchedulers.mainThread()) - .subscribeOn(Schedulers.io()) - .subscribe(object : Subscriber() { - override fun onCompleted() {} - - override fun onError(e: Throwable) { - useCaseCallback.onError(Constants.ERROR_FETCHING_ACCOUNTS) - } - - override fun onNext(clientAccounts: ClientAccounts) { - val accounts: List = accountMapper.transform(clientAccounts) - if (accounts.isNotEmpty()) { - var walletAccount: Account? = null - for (account in accounts) { - if (account.productId.toInt() == Constants.WALLET_ACCOUNT_SAVINGS_PRODUCT_ID) { - walletAccount = account - break - } - } - if (walletAccount != null) { - useCaseCallback.onSuccess(ResponseValue(walletAccount)) - } else { - useCaseCallback.onError(Constants.NO_ACCOUNT_FOUND) - } - } else { - useCaseCallback.onError(Constants.NO_ACCOUNTS_FOUND) - } - } - }) - } - - data class RequestValues(val clientId: Long) : UseCase.RequestValues - - data class ResponseValue(val account: Account) : UseCase.ResponseValue -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt deleted file mode 100644 index affc21632..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/SearchedEntitiesMapper.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.fineract.entity.mapper - -import com.mifospay.core.model.domain.SearchResult -import com.mifospay.core.model.entity.SearchedEntity - -class SearchedEntitiesMapper { - fun transformList(searchedEntities: List?): List { - val searchResults: MutableList = ArrayList() - - searchedEntities?.forEach { entity -> - searchResults.add(transform(entity)) - } - - return searchResults - } - - fun transform(searchedEntity: SearchedEntity): SearchResult { - val searchResult = SearchResult() - searchResult.resultId = searchedEntity.entityId - searchResult.resultName = searchedEntity.entityName - searchResult.resultType = searchedEntity.entityType - return searchResult - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt deleted file mode 100644 index 340298508..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/entity/mapper/TransactionMapper.kt +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.fineract.entity.mapper - -import com.mifospay.core.model.domain.Transaction -import com.mifospay.core.model.domain.TransactionType -import com.mifospay.core.model.entity.accounts.savings.SavingsWithAssociations -import com.mifospay.core.model.entity.accounts.savings.Transactions -import com.mifospay.core.model.utils.DateHelper - -class TransactionMapper( - private val currencyMapper: CurrencyMapper, -) { - - fun transformTransactionList(savingsWithAssociations: SavingsWithAssociations?): List { - val transactionList = ArrayList() - - savingsWithAssociations?.transactions?.forEach { transaction -> - transactionList.add(transformInvoice(transaction)) - } - return transactionList - } - - fun transformInvoice(transactions: Transactions?): Transaction { - val transaction = Transaction() - - if (transactions != null) { - transaction.transactionId = transactions.id.toString() - transactions.paymentDetailData?.let { - transaction.receiptId = it.receiptNumber - } - transaction.amount = transactions.amount - transactions.submittedOnDate.let { - transaction.date = DateHelper.getDateAsString(it) - } - transaction.currency = currencyMapper.transform(transactions.currency) - transaction.transactionType = TransactionType.OTHER - - if (transactions.transactionType.deposit) { - transaction.transactionType = TransactionType.CREDIT - } - - if (transactions.transactionType.withdrawal) { - transaction.transactionType = TransactionType.DEBIT - } - - transactions.transfer.let { - transaction.transferId = it.id - } - } - return transaction - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt b/core/data/src/androidMain/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt deleted file mode 100644 index 80e0be3ea..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/fineract/repository/FineractRepository.kt +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.fineract.repository - -import com.mifospay.core.model.domain.NewAccount -import com.mifospay.core.model.domain.NotificationPayload -import com.mifospay.core.model.domain.client.NewClient -import com.mifospay.core.model.domain.twofactor.AccessToken -import com.mifospay.core.model.domain.twofactor.DeliveryMethod -import com.mifospay.core.model.domain.user.NewUser -import com.mifospay.core.model.domain.user.User -import com.mifospay.core.model.entity.Invoice -import com.mifospay.core.model.entity.Page -import com.mifospay.core.model.entity.SearchedEntity -import com.mifospay.core.model.entity.TPTResponse -import com.mifospay.core.model.entity.UserWithRole -import com.mifospay.core.model.entity.accounts.savings.SavingsWithAssociations -import com.mifospay.core.model.entity.accounts.savings.Transactions -import com.mifospay.core.model.entity.accounts.savings.TransferDetail -import com.mifospay.core.model.entity.authentication.AuthenticationPayload -import com.mifospay.core.model.entity.beneficary.Beneficiary -import com.mifospay.core.model.entity.beneficary.BeneficiaryPayload -import com.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload -import com.mifospay.core.model.entity.client.Client -import com.mifospay.core.model.entity.client.ClientAccounts -import com.mifospay.core.model.entity.kyc.KYCLevel1Details -import com.mifospay.core.model.entity.payload.StandingInstructionPayload -import com.mifospay.core.model.entity.payload.TransferPayload -import com.mifospay.core.model.entity.register.RegisterPayload -import com.mifospay.core.model.entity.register.UserVerify -import com.mifospay.core.model.entity.savedcards.Card -import com.mifospay.core.model.entity.standinginstruction.SDIResponse -import com.mifospay.core.model.entity.standinginstruction.StandingInstruction -import okhttp3.MultipartBody -import okhttp3.ResponseBody -import org.mifos.core.network.services.KtorAuthenticationService -import org.mifospay.core.data.domain.usecase.client.CreateClient -import org.mifospay.core.data.domain.usecase.user.CreateUser -import org.mifospay.core.data.util.Constants -import org.mifospay.core.network.FineractApiManager -import org.mifospay.core.network.GenericResponse -import org.mifospay.core.network.SelfServiceApiManager -import rx.Observable - -@Suppress("TooManyFunctions") -class FineractRepository( - private val fineractApiManager: FineractApiManager, - private val selfApiManager: SelfServiceApiManager, - private val ktorAuthenticationService: KtorAuthenticationService, -) { - fun createClient(newClient: NewClient): Observable { - return fineractApiManager.clientsApi.createClient(newClient) - } - - fun createUser(user: NewUser): Observable { - return fineractApiManager.userApi.createUser(user) - } - - fun updateUser(updateUserEntity: Any, userId: Int): Observable { - return fineractApiManager.userApi.updateUser(userId, updateUserEntity) - } - - fun registerUser(registerPayload: RegisterPayload): Observable { - return fineractApiManager.registrationAPi.registerUser(registerPayload) - } - - fun deleteUser(userId: Int): Observable { - return fineractApiManager.userApi.deleteUser(userId) - } - - fun verifyUser(userVerify: UserVerify): Observable { - return fineractApiManager.registrationAPi.verifyUser(userVerify) - } - - fun searchResources( - query: String, - resources: String, - exactMatch: Boolean, - ): Observable> { - return fineractApiManager.searchApi.searchResources(query, resources, exactMatch) - } - - fun updateClient(clientId: Long, payload: Any): Observable { - return fineractApiManager.clientsApi.updateClient(clientId, payload) - .map { responseBody -> responseBody } - } - - fun createSavingsAccount(newAccount: NewAccount?): Observable { - return fineractApiManager.clientsApi.createAccount(newAccount) - } - - fun getAccounts(clientId: Long): Observable { - return fineractApiManager.clientsApi.getAccounts(clientId, Constants.SAVINGS) - } - - suspend fun savingsAccounts(): Page = - fineractApiManager.ktorSavingsAccountApi.getSavingsAccounts(-1) - - suspend fun blockUnblockAccount(accountId: Long, command: String?): GenericResponse { - return fineractApiManager.ktorSavingsAccountApi.blockUnblockAccount( - accountId, - command, - ) - } - - fun getClientDetails(clientId: Long): Observable { - return fineractApiManager.clientsApi.getClientForId(clientId) - } - - fun getClientImage(clientId: Long): Observable { - return fineractApiManager.clientsApi.getClientImage(clientId) - } - - fun addSavedCards( - clientId: Long, - card: Card, - ): Observable { - return fineractApiManager.savedCardApi.addSavedCard(clientId.toInt(), card) - } - - fun fetchSavedCards(clientId: Long): Observable> { - return fineractApiManager.savedCardApi.getSavedCards(clientId.toInt()) - } - - fun editSavedCard(clientId: Int, card: Card): Observable { - return fineractApiManager.savedCardApi.updateCard(clientId, card.id, card) - } - - fun deleteSavedCard(clientId: Int, cardId: Int): Observable { - return fineractApiManager.savedCardApi.deleteCard(clientId, cardId) - } - - fun uploadKYCDocs( - entityType: String, - entityId: Long, - name: String, - desc: String, - file: MultipartBody.Part, - ): Observable { - return fineractApiManager.documentApi.createDocument( - entityType, - entityId, - name, - desc, - file, - ) - } - - fun getAccountTransfer(transferId: Long): Observable { - return fineractApiManager.accountTransfersApi.getAccountTransfer(transferId) - } - - fun uploadKYCLevel1Details( - clientId: Int, - kycLevel1Details: KYCLevel1Details, - ): Observable { - return fineractApiManager.kycLevel1Api.addKYCLevel1Details( - clientId, - kycLevel1Details, - ) - } - - fun fetchKYCLevel1Details(clientId: Int): Observable> { - return fineractApiManager.kycLevel1Api.fetchKYCLevel1Details(clientId) - } - - fun updateKYCLevel1Details( - clientId: Int, - kycLevel1Details: KYCLevel1Details, - ): Observable { - return fineractApiManager.kycLevel1Api.updateKYCLevel1Details( - clientId, - kycLevel1Details, - ) - } - - fun fetchNotifications(clientId: Long): Observable> { - return fineractApiManager.notificationApi.fetchNotifications(clientId) - } - - val deliveryMethods: Observable> - get() = fineractApiManager.twoFactorAuthApi.deliveryMethods - - fun requestOTP(deliveryMethod: String): Observable { - return fineractApiManager.twoFactorAuthApi.requestOTP(deliveryMethod) - } - - fun validateToken(token: String): Observable { - return fineractApiManager.twoFactorAuthApi.validateToken(token) - } - - fun getTransactionReceipt( - outputType: String, - transactionId: String, - ): Observable { - return fineractApiManager.runReportApi.getTransactionReceipt( - outputType, - transactionId, - ) - } - - fun addInvoice(clientId: String, invoice: Invoice?): Observable { - return fineractApiManager.invoiceApi.addInvoice(clientId, invoice) - } - - fun fetchInvoices(clientId: String): Observable> { - return fineractApiManager.invoiceApi.getInvoices(clientId) - } - - fun fetchInvoice(clientId: String, invoiceId: String): Observable> { - return fineractApiManager.invoiceApi.getInvoice(clientId, invoiceId) - } - - fun editInvoice(clientId: String, invoice: Invoice): Observable { - return fineractApiManager.invoiceApi.updateInvoice(clientId, invoice.id, invoice) - } - - fun deleteInvoice(clientId: String, invoiceId: Int): Observable { - return fineractApiManager.invoiceApi.deleteInvoice(clientId, invoiceId) - } - - val users: Observable> - get() = fineractApiManager.userApi.users - - fun getUser(): Observable { - return fineractApiManager.userApi.getUser() - } - - fun makeThirdPartyTransfer(transferPayload: TransferPayload): Observable { - return fineractApiManager.thirdPartyTransferApi.makeTransfer(transferPayload) - } - - fun createStandingInstruction( - standingInstructionPayload: StandingInstructionPayload, - ): Observable { - return fineractApiManager.standingInstructionApi - .createStandingInstruction(standingInstructionPayload) - } - - fun getAllStandingInstructions(clientId: Long): Observable> { - return fineractApiManager.standingInstructionApi.getAllStandingInstructions(clientId) - } - - fun getStandingInstruction(standingInstructionId: Long): Observable { - return fineractApiManager.standingInstructionApi - .getStandingInstruction(standingInstructionId) - } - - fun updateStandingInstruction( - standingInstructionId: Long, - data: StandingInstructionPayload, - ): Observable { - return fineractApiManager.standingInstructionApi.updateStandingInstruction( - standingInstructionId, - data, - "update", - ) - } - - fun deleteStandingInstruction(standingInstruction: Long): Observable { - return fineractApiManager.standingInstructionApi.deleteStandingInstruction( - standingInstruction, - "delete", - ) - } - - // self user apis - suspend fun loginSelf(payload: AuthenticationPayload): User { - return ktorAuthenticationService.authenticate(payload) - } - - fun getSelfClientDetails(clientId: Long): Observable { - return selfApiManager.clientsApi.getClientForId(clientId) - } - - val selfClientDetails: Observable> - get() = selfApiManager.clientsApi.clients - - suspend fun getSelfAccountTransactions(accountId: Long): SavingsWithAssociations { - return selfApiManager.ktorSavingsAccountApi.getSavingsWithAssociations( - accountId, - Constants.TRANSACTIONS, - ) - } - - suspend fun getSelfAccountTransactionFromId( - accountId: Long, - transactionId: Long, - ): Transactions { - return selfApiManager.ktorSavingsAccountApi.getSavingAccountTransaction( - accountId, - transactionId, - ) - } - - fun getSelfAccounts(clientId: Long): Observable { - return selfApiManager.clientsApi.getAccounts(clientId, Constants.SAVINGS) - } - - val beneficiaryList: Observable> - get() = selfApiManager.beneficiaryApi.beneficiaryList - - fun createBeneficiary(beneficiaryPayload: BeneficiaryPayload): Observable { - return selfApiManager.beneficiaryApi.createBeneficiary(beneficiaryPayload) - } - - fun updateBeneficiary( - beneficiaryId: Long, - payload: BeneficiaryUpdatePayload, - ): Observable { - return selfApiManager.beneficiaryApi.updateBeneficiary(beneficiaryId, payload) - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt b/core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt deleted file mode 100644 index 70cc1a2c3..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/AuthenticationUserRepository.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.repository.auth - -import com.mifospay.core.model.UserData -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import org.mifospay.core.datastore.PreferencesHelper - -class AuthenticationUserRepository( - private val preferencesHelper: PreferencesHelper, -) : UserDataRepository { - - override val userData: Flow = flow { - emit( - UserData( - isAuthenticated = !preferencesHelper.token.isNullOrEmpty(), - userName = preferencesHelper.username, - // user = preferencesHelper.user, - clientId = preferencesHelper.clientId, - ), - ) - } - - override fun logOut() { - preferencesHelper.clear() - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalRepository.kt b/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalRepository.kt deleted file mode 100644 index de55915ed..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalRepository.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.repository.local - -import com.mifospay.core.model.domain.client.Client -import org.mifospay.core.datastore.PreferencesHelper - -class LocalRepository( - val preferencesHelper: PreferencesHelper, -) { - - val clientDetails: Client - get() { - val details = Client() - details.name = preferencesHelper.fullName - details.clientId = preferencesHelper.clientId - details.externalId = preferencesHelper.clientVpa - return details - } - - fun saveClientData(client: Client) { - preferencesHelper.saveFullName(client.name) - preferencesHelper.clientId = client.clientId - preferencesHelper.clientVpa = client.externalId - } -} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt b/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt deleted file mode 100644 index c93b060fa..000000000 --- a/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/MifosLocalAssetRepository.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.repository.local - -import com.mifospay.core.model.City -import com.mifospay.core.model.Country -import com.mifospay.core.model.State -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import kotlinx.coroutines.flow.flowOn -import org.mifos.core.network.localAssets.LocalAssetDataSource - -/** - * Local implementation of the [LocalAssetRepository] that retrieves the countries, banks, cities - * and state list from a JSON String. - * - */ - -class MifosLocalAssetRepository( - private val ioDispatcher: CoroutineDispatcher, - private val datasource: LocalAssetDataSource, -) : LocalAssetRepository { - - override fun getCountries(): Flow> = flow { - emit(datasource.getCountries()) - }.flowOn(ioDispatcher) - - override fun getStateList(): Flow> = flow { - emit(datasource.getStateList()) - }.flowOn(ioDispatcher) - - override fun getBanks(): Flow> = flow { - emit(datasource.getBanks()) - }.flowOn(ioDispatcher) - - override fun getCities(): Flow> = flow { - emit(datasource.getCities()) - }.flowOn(ioDispatcher) -} diff --git a/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformDependentDataModule.kt b/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformDependentDataModule.kt new file mode 100644 index 000000000..8d825d28b --- /dev/null +++ b/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformDependentDataModule.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.di + +import android.content.Context +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import org.mifospay.core.data.util.ConnectivityManagerNetworkMonitor +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneBroadcastMonitor +import org.mifospay.core.data.util.TimeZoneMonitor + +class AndroidPlatformDependentDataModule( + private val context: Context, + private val dispatcher: CoroutineDispatcher, + private val scope: CoroutineScope, +) : PlatformDependentDataModule() { + override fun bindsNetworkMonitor(): NetworkMonitor { + return ConnectivityManagerNetworkMonitor(context, dispatcher) + } + + override fun bindsTimeZoneMonitor(): TimeZoneMonitor { + return TimeZoneBroadcastMonitor(context, scope, dispatcher) + } +} diff --git a/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformModule.kt b/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformModule.kt new file mode 100644 index 000000000..f975f2d91 --- /dev/null +++ b/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformModule.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.di + +import org.koin.android.ext.koin.androidContext +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.common.MifosDispatchers +import org.mifospay.core.data.util.ConnectivityManagerNetworkMonitor +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneBroadcastMonitor +import org.mifospay.core.data.util.TimeZoneMonitor + +val androidDataModule = module { + single { + ConnectivityManagerNetworkMonitor(androidContext(), get(named(MifosDispatchers.IO.name))) + } + + single { + TimeZoneBroadcastMonitor( + context = androidContext(), + appScope = get(named("ApplicationScope")), + ioDispatcher = get(named(MifosDispatchers.IO.name)), + ) + } + + single { + AndroidPlatformDependentDataModule( + context = androidContext(), + dispatcher = get(named(MifosDispatchers.IO.name)), + scope = get(named("ApplicationScope")), + ) + } +} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt b/core/data/src/androidMain/kotlin/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt similarity index 84% rename from core/data/src/androidMain/java/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt rename to core/data/src/androidMain/kotlin/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt index 8e0986c79..5d1e606e9 100644 --- a/core/data/src/androidMain/java/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt +++ b/core/data/src/androidMain/kotlin/org/mifospay/core/data/util/ConnectivityManagerNetworkMonitor.kt @@ -16,16 +16,17 @@ import android.net.Network import android.net.NetworkCapabilities import android.net.NetworkRequest import android.net.NetworkRequest.Builder -import android.os.Build.VERSION -import android.os.Build.VERSION_CODES import androidx.core.content.getSystemService +import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.conflate +import kotlinx.coroutines.flow.flowOn internal class ConnectivityManagerNetworkMonitor( private val context: Context, + ioDispatcher: CoroutineDispatcher, ) : NetworkMonitor { override val isOnline: Flow = callbackFlow { val connectivityManager = context.getSystemService() @@ -53,12 +54,10 @@ internal class ConnectivityManagerNetworkMonitor( channel.trySend(networks.isNotEmpty()) } } - val request = Builder() .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) .build() connectivityManager.registerNetworkCallback(request, callback) - /** * Sends the latest connectivity status to the underlying channel. */ @@ -68,15 +67,10 @@ internal class ConnectivityManagerNetworkMonitor( connectivityManager.unregisterNetworkCallback(callback) } } + .flowOn(ioDispatcher) .conflate() - @Suppress("DEPRECATION") - private fun ConnectivityManager.isCurrentlyConnected() = when { - VERSION.SDK_INT >= VERSION_CODES.M -> - activeNetwork - ?.let(::getNetworkCapabilities) - ?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - - else -> activeNetworkInfo?.isConnected - } ?: false + private fun ConnectivityManager.isCurrentlyConnected() = activeNetwork + ?.let(::getNetworkCapabilities) + ?.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) ?: false } diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt b/core/data/src/androidMain/kotlin/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt similarity index 100% rename from core/data/src/androidMain/java/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt rename to core/data/src/androidMain/kotlin/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/util/TimeZoneMonitor.kt b/core/data/src/androidMain/kotlin/org/mifospay/core/data/util/TimeZoneBroadcastMonitor.kt similarity index 91% rename from core/data/src/androidMain/java/org/mifospay/core/data/util/TimeZoneMonitor.kt rename to core/data/src/androidMain/kotlin/org/mifospay/core/data/util/TimeZoneBroadcastMonitor.kt index bd92230cd..012bd5376 100644 --- a/core/data/src/androidMain/java/org/mifospay/core/data/util/TimeZoneMonitor.kt +++ b/core/data/src/androidMain/kotlin/org/mifospay/core/data/util/TimeZoneBroadcastMonitor.kt @@ -19,7 +19,6 @@ import androidx.tracing.trace import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.callbackFlow @@ -31,19 +30,10 @@ import kotlinx.datetime.TimeZone import kotlinx.datetime.toKotlinTimeZone import java.time.ZoneId -/** - * Utility for reporting current timezone the device has set. - * It always emits at least once with default setting and then for each TZ change. - */ - -interface TimeZoneMonitor { - val currentTimeZone: Flow -} - internal class TimeZoneBroadcastMonitor( private val context: Context, appScope: CoroutineScope, - private val ioDispatcher: CoroutineDispatcher, + ioDispatcher: CoroutineDispatcher, ) : TimeZoneMonitor { override val currentTimeZone: SharedFlow = diff --git a/core/data/src/androidMain/assets/banks.json b/core/data/src/commonMain/assets/banks.json similarity index 100% rename from core/data/src/androidMain/assets/banks.json rename to core/data/src/commonMain/assets/banks.json diff --git a/core/data/src/androidMain/assets/cities.json b/core/data/src/commonMain/assets/cities.json similarity index 100% rename from core/data/src/androidMain/assets/cities.json rename to core/data/src/commonMain/assets/cities.json diff --git a/core/data/src/androidMain/assets/countriesToCities.json b/core/data/src/commonMain/assets/countriesToCities.json similarity index 100% rename from core/data/src/androidMain/assets/countriesToCities.json rename to core/data/src/commonMain/assets/countriesToCities.json diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/di/LocalDataModule.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.kt similarity index 58% rename from core/data/src/androidMain/java/org/mifospay/core/data/di/LocalDataModule.kt rename to core/data/src/commonMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.kt index 87be810d2..0a635a1f7 100644 --- a/core/data/src/androidMain/java/org/mifospay/core/data/di/LocalDataModule.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.kt @@ -9,11 +9,11 @@ */ package org.mifospay.core.data.di -import androidx.lifecycle.SavedStateHandle -import org.koin.dsl.module +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneMonitor -val LocalDataModule = module { - factory { - SavedStateHandle() - } +abstract class PlatformDependentDataModule { + abstract fun bindsNetworkMonitor(): NetworkMonitor + + abstract fun bindsTimeZoneMonitor(): TimeZoneMonitor } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/RepositoryModule.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/RepositoryModule.kt new file mode 100644 index 000000000..c551d41d4 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/RepositoryModule.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.di + +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.common.MifosDispatchers +import org.mifospay.core.data.repository.AccountRepository +import org.mifospay.core.data.repository.AuthenticationRepository +import org.mifospay.core.data.repository.BeneficiaryRepository +import org.mifospay.core.data.repository.ClientRepository +import org.mifospay.core.data.repository.DocumentRepository +import org.mifospay.core.data.repository.InvoiceRepository +import org.mifospay.core.data.repository.KycLevelRepository +import org.mifospay.core.data.repository.NotificationRepository +import org.mifospay.core.data.repository.RegistrationRepository +import org.mifospay.core.data.repository.RunReportRepository +import org.mifospay.core.data.repository.SavedCardRepository +import org.mifospay.core.data.repository.SavingsAccountRepository +import org.mifospay.core.data.repository.SearchRepository +import org.mifospay.core.data.repository.SelfServiceRepository +import org.mifospay.core.data.repository.StandingInstructionRepository +import org.mifospay.core.data.repository.ThirdPartyTransferRepository +import org.mifospay.core.data.repository.TwoFactorAuthRepository +import org.mifospay.core.data.repository.UserRepository +import org.mifospay.core.data.repositoryImp.AccountRepositoryImpl +import org.mifospay.core.data.repositoryImp.AuthenticationRepositoryImpl +import org.mifospay.core.data.repositoryImp.BeneficiaryRepositoryImpl +import org.mifospay.core.data.repositoryImp.ClientRepositoryImpl +import org.mifospay.core.data.repositoryImp.DocumentRepositoryImpl +import org.mifospay.core.data.repositoryImp.InvoiceRepositoryImpl +import org.mifospay.core.data.repositoryImp.KycLevelRepositoryImpl +import org.mifospay.core.data.repositoryImp.NotificationRepositoryImpl +import org.mifospay.core.data.repositoryImp.RegistrationRepositoryImpl +import org.mifospay.core.data.repositoryImp.RunReportRepositoryImpl +import org.mifospay.core.data.repositoryImp.SavedCardRepositoryImpl +import org.mifospay.core.data.repositoryImp.SavingsAccountRepositoryImpl +import org.mifospay.core.data.repositoryImp.SearchRepositoryImpl +import org.mifospay.core.data.repositoryImp.SelfServiceRepositoryImpl +import org.mifospay.core.data.repositoryImp.StandingInstructionRepositoryImpl +import org.mifospay.core.data.repositoryImp.ThirdPartyTransferRepositoryImpl +import org.mifospay.core.data.repositoryImp.TwoFactorAuthRepositoryImpl +import org.mifospay.core.data.repositoryImp.UserRepositoryImpl + +private val ioDispatcher = named(MifosDispatchers.IO.name) + +val repositoryModule = module { + single { AccountRepositoryImpl(get(), get(ioDispatcher)) } + single { AuthenticationRepositoryImpl(get(), get(ioDispatcher)) } + single { BeneficiaryRepositoryImpl(get(), get(ioDispatcher)) } + single { ClientRepositoryImpl(get(), get(ioDispatcher)) } + single { DocumentRepositoryImpl(get(), get(ioDispatcher)) } + single { InvoiceRepositoryImpl(get(), get(ioDispatcher)) } + single { KycLevelRepositoryImpl(get(), get(ioDispatcher)) } + single { NotificationRepositoryImpl(get(), get(ioDispatcher)) } + single { RegistrationRepositoryImpl(get(), get(ioDispatcher)) } + single { RunReportRepositoryImpl(get(), get(ioDispatcher)) } + single { SavedCardRepositoryImpl(get(), get(ioDispatcher)) } + single { SavingsAccountRepositoryImpl(get(), get(ioDispatcher)) } + single { SearchRepositoryImpl(get(), get(ioDispatcher)) } + single { SelfServiceRepositoryImpl(get(), get(ioDispatcher)) } + single { + StandingInstructionRepositoryImpl(get(), get(ioDispatcher)) + } + single { + ThirdPartyTransferRepositoryImpl(get(), get(ioDispatcher)) + } + single { TwoFactorAuthRepositoryImpl(get(), get(ioDispatcher)) } + single { UserRepositoryImpl(get(), get(ioDispatcher)) } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/AccountMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/AccountMapper.kt new file mode 100644 index 000000000..e4aca8873 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/AccountMapper.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.mapper + +import org.mifospay.core.model.domain.Account +import org.mifospay.core.model.entity.client.ClientAccounts + +fun ClientAccounts.toAccount(): List { + return this.savingsAccounts.map { + Account( + name = it.productName, + number = it.accountNo, + id = it.id, + balance = it.accountBalance, + currency = it.currency.toModel(), + productId = it.productId.toLong(), + ) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/ClientDetailsMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/ClientDetailsMapper.kt new file mode 100644 index 000000000..727d28a4f --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/ClientDetailsMapper.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.mapper + +import org.mifospay.core.model.domain.client.Client +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.client.ClientEntity + +fun ClientEntity.toModel(): Client { + return Client( + name = this.displayName, + clientId = this.id.toLong(), + externalId = this.externalId, + mobileNo = this.mobileNo, + displayName = this.displayName ?: "", + image = this.imageId.toString(), + ) +} + +fun List.toModel(): List = map { it.toModel() } + +fun Page.toModel(): Page { + return Page( + totalFilteredRecords = this.totalFilteredRecords, + pageItems = this.pageItems.map { it.toModel() }.toMutableList(), + ) +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/CurrencyMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/CurrencyMapper.kt new file mode 100644 index 000000000..c70c2c882 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/CurrencyMapper.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.mapper + +import org.mifospay.core.model.entity.accounts.savings.Currency +import org.mifospay.core.model.domain.Currency as DomainCurrency + +fun Currency.toModel(): DomainCurrency { + return DomainCurrency( + code = this.code, + displayLabel = this.displayLabel, + displaySymbol = this.displaySymbol, + ) +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/SearchedEntitiesMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/SearchedEntitiesMapper.kt new file mode 100644 index 000000000..4208aed4a --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/SearchedEntitiesMapper.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.mapper + +import org.mifospay.core.model.domain.SearchResult +import org.mifospay.core.model.entity.SearchedEntity + +fun SearchedEntity.toSearchResult(): SearchResult { + return SearchResult( + resultId = this.entityId, + resultName = this.entityName, + resultType = this.entityType, + ) +} + +fun List.toSearchResult(): List = map { it.toSearchResult() } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TransactionMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TransactionMapper.kt new file mode 100644 index 000000000..41c4820b3 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TransactionMapper.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.mapper + +import org.mifospay.core.model.domain.Transaction +import org.mifospay.core.model.domain.TransactionType +import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity +import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity +import org.mifospay.core.model.utils.DateHelper + +fun SavingsWithAssociationsEntity.toTransactionList(): List { + return this.transactions.map { it.toModel() } +} + +fun TransactionsEntity.toModel(): Transaction { + return Transaction( + transactionId = this.id.toString(), + receiptId = this.paymentDetailData?.receiptNumber, + amount = this.amount, + date = DateHelper.getDateAsString(this.submittedOnDate), + currency = this.currency.toModel(), + transactionType = when { + this.transactionType.deposit -> TransactionType.CREDIT + this.transactionType.withdrawal -> TransactionType.DEBIT + else -> TransactionType.OTHER + }, + transferId = this.originalTransactionId ?: 0, + ) +} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/UserDataRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AccountRepository.kt similarity index 57% rename from core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/UserDataRepository.kt rename to core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AccountRepository.kt index 5241ba9ab..246d77517 100644 --- a/core/data/src/androidMain/java/org/mifospay/core/data/repository/auth/UserDataRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AccountRepository.kt @@ -7,16 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.data.repository.auth +package org.mifospay.core.data.repository -import com.mifospay.core.model.UserData import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.entity.accounts.savings.TransferDetail -interface UserDataRepository { - /** - * Stream of [UserData] - */ - val userData: Flow - - fun logOut(): Unit +interface AccountRepository { + suspend fun getAccountTransfer(transferId: Long): Flow> } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt new file mode 100644 index 000000000..a8102a1db --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.entity.authentication.AuthenticationPayload + +interface AuthenticationRepository { + suspend fun authenticate(payload: AuthenticationPayload): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt new file mode 100644 index 000000000..d21675c7b --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.entity.beneficary.Beneficiary +import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload +import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload +import org.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate +import org.mifospay.core.network.model.CommonResponse + +interface BeneficiaryRepository { + fun getBeneficiaryList(): Flow>> + + fun getBeneficiaryTemplate(): Flow> + + fun createBeneficiary(beneficiaryPayload: BeneficiaryPayload): Flow> + + fun updateBeneficiary( + beneficiaryId: Long, + payload: BeneficiaryUpdatePayload, + ): Flow> + + fun deleteBeneficiary(beneficiaryId: Long): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt new file mode 100644 index 000000000..a9657874e --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.domain.client.Client +import org.mifospay.core.model.domain.client.NewClient +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.client.ClientAccounts + +interface ClientRepository { + + suspend fun getClients(): Flow>> + + suspend fun getClient(clientId: Long): Flow> + + suspend fun updateClient(clientId: Long, client: Client): Flow> + + suspend fun getClientImage(clientId: Long): Flow> + + suspend fun updateClientImage(clientId: Long, image: String): Flow> + + suspend fun getClientAccounts(clientId: Long): Flow> + + suspend fun getAccounts(clientId: Long, accountType: String): Flow> + + suspend fun createClient(newClient: NewClient): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt new file mode 100644 index 000000000..ec54d64b6 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import io.ktor.http.content.PartData +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.entity.noncore.Document + +interface DocumentRepository { + fun getDocuments(entityType: String, entityId: Int): Flow>> + + fun createDocument( + entityType: String, + entityId: Int, + name: String, + description: String, + fileName: PartData.FileItem, + ): Flow> + + fun downloadDocument(entityType: String, entityId: Int, documentId: Int): Flow> + + fun deleteDocument(entityType: String, entityId: Int, documentId: Int): Flow> + + fun updateDocument( + entityType: String, + entityId: Int, + documentId: Int, + name: String, + description: String, + fileName: PartData.FileItem, + ): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/InvoiceRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/InvoiceRepository.kt new file mode 100644 index 000000000..63d5affb5 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/InvoiceRepository.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.entity.Invoice +import org.mifospay.core.network.model.GenericResponse + +interface InvoiceRepository { + suspend fun getInvoice(clientId: Int, invoiceId: Int): Flow> + + suspend fun getInvoices(clientId: Int): Flow>> + + suspend fun createInvoice(clientId: Int, invoice: Invoice): Result + + suspend fun updateInvoice( + clientId: Int, + invoiceId: Int, + invoice: Invoice, + ): Flow> + + suspend fun deleteInvoice(clientId: Int, invoiceId: Int): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/KycLevelRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/KycLevelRepository.kt new file mode 100644 index 000000000..0326045ff --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/KycLevelRepository.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.entity.kyc.KYCLevel1Details +import org.mifospay.core.network.model.GenericResponse + +interface KycLevelRepository { + suspend fun fetchKYCLevel1Details(clientId: Int): Flow>> + + suspend fun addKYCLevel1Details( + clientId: Int, + kycLevel1Details: KYCLevel1Details, + ): Flow> + + suspend fun updateKYCLevel1Details( + clientId: Int, + kycLevel1Details: KYCLevel1Details, + ): Flow> +} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/HistoryContract.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/NotificationRepository.kt similarity index 51% rename from core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/HistoryContract.kt rename to core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/NotificationRepository.kt index 7d59304ab..30d10ddad 100644 --- a/core/data/src/androidMain/java/org/mifospay/core/data/domain/usecase/history/HistoryContract.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/NotificationRepository.kt @@ -7,12 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.data.domain.usecase.history +package org.mifospay.core.data.repository -import com.mifospay.core.model.domain.Transaction +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.domain.NotificationPayload -interface HistoryContract { - interface TransactionsHistoryAsync { - fun onTransactionsFetchCompleted(transactions: List?) - } +interface NotificationRepository { + suspend fun fetchNotifications(clientId: Long): Flow>> } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RegistrationRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RegistrationRepository.kt new file mode 100644 index 000000000..9cc290d42 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RegistrationRepository.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import org.mifospay.core.common.Result +import org.mifospay.core.model.entity.register.RegisterPayload +import org.mifospay.core.model.entity.register.UserVerify + +interface RegistrationRepository { + suspend fun registerUser(registerPayload: RegisterPayload): Result + + suspend fun verifyUser(userVerify: UserVerify): Result +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RunReportRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RunReportRepository.kt new file mode 100644 index 000000000..e2eb96968 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RunReportRepository.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.domain.Transaction + +interface RunReportRepository { + suspend fun getTransactionReceipt( + outputType: String, + transactionId: String, + ): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavedCardRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavedCardRepository.kt new file mode 100644 index 000000000..e2feb9514 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavedCardRepository.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.entity.savedcards.Card +import org.mifospay.core.network.model.GenericResponse + +interface SavedCardRepository { + suspend fun getSavedCards(clientId: Int): Flow>> + + suspend fun addSavedCard(clientId: Int, card: Card): Flow> + + suspend fun deleteCard(clientId: Int, cardId: Int): Flow> + + suspend fun updateCard(clientId: Int, cardId: Int, card: Card): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavingsAccountRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavingsAccountRepository.kt new file mode 100644 index 000000000..f3a3b70ba --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavingsAccountRepository.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.domain.Transaction +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.accounts.savings.SavingAccount +import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity +import org.mifospay.core.network.model.GenericResponse + +interface SavingsAccountRepository { + suspend fun getSavingsAccounts(limit: Int): Flow>> + + suspend fun getSavingsWithAssociations( + accountId: Long, + associationType: String, + ): Flow> + + suspend fun createSavingsAccount(savingAccount: SavingAccount): Flow> + + suspend fun blockUnblockAccount(accountId: Long, command: String?): Flow> + + suspend fun getSavingAccountTransaction( + accountId: Long, + transactionId: Long, + ): Flow> + + suspend fun payViaMobile(accountId: Long): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt new file mode 100644 index 000000000..bd7ee0656 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.entity.SearchedEntity + +interface SearchRepository { + suspend fun searchResources( + query: String, + resources: String, + exactMatch: Boolean, + ): Flow>> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt new file mode 100644 index 000000000..307bfad04 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.domain.client.Client +import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity +import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity +import org.mifospay.core.model.entity.authentication.AuthenticationPayload +import org.mifospay.core.model.entity.beneficary.Beneficiary +import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload +import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload +import org.mifospay.core.model.entity.client.ClientAccounts +import org.mifospay.core.network.model.CommonResponse + +interface SelfServiceRepository { + suspend fun loginSelf(payload: AuthenticationPayload): Flow> + + suspend fun getSelfClientDetails(clientId: Long): Flow> + + suspend fun getSelfClientDetails(): Flow>> + + suspend fun getSelfAccountTransactions( + accountId: Long, + ): Flow> + + suspend fun getSelfAccountTransactionFromId( + accountId: Long, + transactionId: Long, + ): Flow> + + suspend fun getSelfAccounts(clientId: Long): Flow> + + suspend fun getBeneficiaryList(): Flow>> + + suspend fun createBeneficiary(beneficiaryPayload: BeneficiaryPayload): Flow> + + suspend fun updateBeneficiary( + beneficiaryId: Long, + payload: BeneficiaryUpdatePayload, + ): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/StandingInstructionRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/StandingInstructionRepository.kt new file mode 100644 index 000000000..747e46a88 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/StandingInstructionRepository.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.payload.StandingInstructionPayload +import org.mifospay.core.model.entity.standinginstruction.SDIResponse +import org.mifospay.core.model.entity.standinginstruction.StandingInstruction +import org.mifospay.core.network.model.GenericResponse + +interface StandingInstructionRepository { + suspend fun getAllStandingInstructions( + clientId: Long, + ): Flow>> + + suspend fun getStandingInstruction(instructionId: Long): Flow> + + suspend fun createStandingInstruction( + payload: StandingInstructionPayload, + ): Flow> + + suspend fun updateStandingInstruction( + instructionId: Long, + payload: StandingInstructionPayload, + ): Flow> + + suspend fun deleteStandingInstruction(instructionId: Long): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ThirdPartyTransferRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ThirdPartyTransferRepository.kt new file mode 100644 index 000000000..c7cadf08b --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ThirdPartyTransferRepository.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.entity.TPTResponse +import org.mifospay.core.model.entity.payload.TransferPayload +import org.mifospay.core.model.entity.templates.account.AccountOptionsTemplate + +interface ThirdPartyTransferRepository { + suspend fun getTransferTemplate(): Flow> + + suspend fun makeTransfer(payload: TransferPayload): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/TwoFactorAuthRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/TwoFactorAuthRepository.kt new file mode 100644 index 000000000..267560b3e --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/TwoFactorAuthRepository.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.domain.twofactor.AccessToken +import org.mifospay.core.model.domain.twofactor.DeliveryMethod + +interface TwoFactorAuthRepository { + suspend fun deliveryMethods(): Flow>> + + suspend fun requestOTP(deliveryMethod: String): Flow> + + suspend fun validateToken(token: String): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt new file mode 100644 index 000000000..6367b63b2 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repository + +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.common.Result +import org.mifospay.core.model.domain.user.NewUser +import org.mifospay.core.model.entity.UserWithRole +import org.mifospay.core.network.model.CommonResponse +import org.mifospay.core.network.model.GenericResponse + +interface UserRepository { + fun getUsers(): Flow>> + + fun getUser(): Flow> + + fun createUser(newUser: NewUser): Flow> + + fun updateUser(userId: Int, updatedUser: NewUser): Flow> + + fun deleteUser(userId: Int): Flow> +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AccountRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AccountRepositoryImpl.kt new file mode 100644 index 000000000..13230bb62 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AccountRepositoryImpl.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.AccountRepository +import org.mifospay.core.model.entity.accounts.savings.TransferDetail +import org.mifospay.core.network.FineractApiManager + +class AccountRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : AccountRepository { + override suspend fun getAccountTransfer(transferId: Long): Flow> { + return apiManager + .accountTransfersApi + .getAccountTransfer(transferId) + .asResult() + .flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt new file mode 100644 index 000000000..ee6a28d0a --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.AuthenticationRepository +import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.entity.authentication.AuthenticationPayload +import org.mifospay.core.network.SelfServiceApiManager + +class AuthenticationRepositoryImpl( + private val apiManager: SelfServiceApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : AuthenticationRepository { + override suspend fun authenticate(payload: AuthenticationPayload): Flow> { + return apiManager.authenticationApi.authenticate(payload).asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt new file mode 100644 index 000000000..66f88ba01 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.BeneficiaryRepository +import org.mifospay.core.model.entity.beneficary.Beneficiary +import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload +import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload +import org.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate +import org.mifospay.core.network.SelfServiceApiManager +import org.mifospay.core.network.model.CommonResponse + +class BeneficiaryRepositoryImpl( + private val apiManager: SelfServiceApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : BeneficiaryRepository { + override fun getBeneficiaryList(): Flow>> { + return apiManager.beneficiaryApi.beneficiaryList().asResult().flowOn(ioDispatcher) + } + + override fun getBeneficiaryTemplate(): Flow> { + return apiManager.beneficiaryApi.beneficiaryTemplate().asResult().flowOn(ioDispatcher) + } + + override fun createBeneficiary( + beneficiaryPayload: BeneficiaryPayload, + ): Flow> { + return apiManager + .beneficiaryApi + .createBeneficiary(beneficiaryPayload) + .asResult().flowOn(ioDispatcher) + } + + override fun updateBeneficiary( + beneficiaryId: Long, + payload: BeneficiaryUpdatePayload, + ): Flow> { + return apiManager.beneficiaryApi + .updateBeneficiary(beneficiaryId, payload) + .asResult().flowOn(ioDispatcher) + } + + override fun deleteBeneficiary(beneficiaryId: Long): Flow> { + return apiManager.beneficiaryApi + .deleteBeneficiary(beneficiaryId) + .asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt new file mode 100644 index 000000000..c463bc478 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt @@ -0,0 +1,78 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.mapper.toModel +import org.mifospay.core.data.repository.ClientRepository +import org.mifospay.core.model.domain.client.Client +import org.mifospay.core.model.domain.client.NewClient +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.client.ClientAccounts +import org.mifospay.core.network.FineractApiManager + +class ClientRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : ClientRepository { + override suspend fun getClients(): Flow>> { + return apiManager.clientsApi.clients().map { it.toModel() }.asResult().flowOn(ioDispatcher) + } + + override suspend fun getClient(clientId: Long): Flow> { + return apiManager.clientsApi + .getClientForId(clientId) + .map { it.toModel() } + .asResult().flowOn(ioDispatcher) + } + + override suspend fun updateClient(clientId: Long, client: Client): Flow> { + return apiManager.clientsApi + .updateClient(clientId, client) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun getClientImage(clientId: Long): Flow> { + return apiManager.clientsApi.getClientImage(clientId).asResult().flowOn(ioDispatcher) + } + + override suspend fun updateClientImage(clientId: Long, image: String): Flow> { + return apiManager.clientsApi + .updateClientImage(clientId, image) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun getClientAccounts(clientId: Long): Flow> { + return apiManager.clientsApi + .getClientAccounts(clientId) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun getAccounts( + clientId: Long, + accountType: String, + ): Flow> { + return apiManager.clientsApi + .getAccounts(clientId, accountType) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun createClient(newClient: NewClient): Flow> { + return apiManager.clientsApi + .createClient(newClient) + .map { it.toModel() } + .asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt new file mode 100644 index 000000000..38a51d15a --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt @@ -0,0 +1,77 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import io.ktor.http.content.PartData +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.DocumentRepository +import org.mifospay.core.model.entity.noncore.Document +import org.mifospay.core.network.FineractApiManager + +class DocumentRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : DocumentRepository { + override fun getDocuments(entityType: String, entityId: Int): Flow>> { + return apiManager.documentApi + .getDocuments(entityType, entityId) + .asResult().flowOn(ioDispatcher) + } + + override fun createDocument( + entityType: String, + entityId: Int, + name: String, + description: String, + fileName: PartData.FileItem, + ): Flow> { + return apiManager.documentApi + .createDocument(entityType, entityId, name, description, fileName) + .asResult().flowOn(ioDispatcher) + } + + override fun downloadDocument( + entityType: String, + entityId: Int, + documentId: Int, + ): Flow> { + return apiManager.documentApi + .downloadDocument(entityType, entityId, documentId) + .asResult().flowOn(ioDispatcher) + } + + override fun deleteDocument( + entityType: String, + entityId: Int, + documentId: Int, + ): Flow> { + return apiManager.documentApi + .removeDocument(entityType, entityId, documentId) + .asResult().flowOn(ioDispatcher) + } + + override fun updateDocument( + entityType: String, + entityId: Int, + documentId: Int, + name: String, + description: String, + fileName: PartData.FileItem, + ): Flow> { + return apiManager.documentApi + .updateDocument(entityType, entityId, documentId, name, description, fileName) + .asResult() + .flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/InvoiceRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/InvoiceRepositoryImpl.kt new file mode 100644 index 000000000..c41461773 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/InvoiceRepositoryImpl.kt @@ -0,0 +1,57 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.InvoiceRepository +import org.mifospay.core.model.entity.Invoice +import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.GenericResponse + +class InvoiceRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : InvoiceRepository { + override suspend fun getInvoice(clientId: Int, invoiceId: Int): Flow> { + return apiManager.invoiceApi.getInvoice(clientId, invoiceId).asResult().flowOn(ioDispatcher) + } + + override suspend fun getInvoices(clientId: Int): Flow>> { + return apiManager.invoiceApi.getInvoices(clientId).asResult().flowOn(ioDispatcher) + } + + override suspend fun createInvoice(clientId: Int, invoice: Invoice): Result { + return try { + Result.Success(apiManager.invoiceApi.addInvoice(clientId, invoice)) + } catch (e: Exception) { + Result.Error(e) + } + } + + override suspend fun updateInvoice( + clientId: Int, + invoiceId: Int, + invoice: Invoice, + ): Flow> { + return apiManager.invoiceApi + .updateInvoice(clientId, invoiceId, invoice).asResult() + .flowOn(ioDispatcher) + } + + override suspend fun deleteInvoice(clientId: Int, invoiceId: Int): Flow> { + return apiManager.invoiceApi + .deleteInvoice(clientId, invoiceId).asResult() + .flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/KycLevelRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/KycLevelRepositoryImpl.kt new file mode 100644 index 000000000..32d5ca277 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/KycLevelRepositoryImpl.kt @@ -0,0 +1,49 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.KycLevelRepository +import org.mifospay.core.model.entity.kyc.KYCLevel1Details +import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.GenericResponse + +class KycLevelRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : KycLevelRepository { + override suspend fun fetchKYCLevel1Details(clientId: Int): Flow>> { + return apiManager.kycLevel1Api + .fetchKYCLevel1Details(clientId) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun addKYCLevel1Details( + clientId: Int, + kycLevel1Details: KYCLevel1Details, + ): Flow> { + return apiManager.kycLevel1Api + .addKYCLevel1Details(clientId, kycLevel1Details) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun updateKYCLevel1Details( + clientId: Int, + kycLevel1Details: KYCLevel1Details, + ): Flow> { + return apiManager.kycLevel1Api + .updateKYCLevel1Details(clientId, kycLevel1Details) + .asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/NotificationRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/NotificationRepositoryImpl.kt new file mode 100644 index 000000000..209a3008a --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/NotificationRepositoryImpl.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.NotificationRepository +import org.mifospay.core.model.domain.NotificationPayload +import org.mifospay.core.network.FineractApiManager + +class NotificationRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : NotificationRepository { + override suspend fun fetchNotifications( + clientId: Long, + ): Flow>> { + return apiManager.notificationApi + .fetchNotifications(clientId) + .asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RegistrationRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RegistrationRepositoryImpl.kt new file mode 100644 index 000000000..34c4d11ee --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RegistrationRepositoryImpl.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext +import org.mifospay.core.common.Result +import org.mifospay.core.data.repository.RegistrationRepository +import org.mifospay.core.model.entity.register.RegisterPayload +import org.mifospay.core.model.entity.register.UserVerify +import org.mifospay.core.network.FineractApiManager + +class RegistrationRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : RegistrationRepository { + override suspend fun registerUser(registerPayload: RegisterPayload): Result { + return try { + val result = withContext(ioDispatcher) { + apiManager.registrationAPi.registerUser(registerPayload) + } + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } + } + + override suspend fun verifyUser(userVerify: UserVerify): Result { + return try { + val result = withContext(ioDispatcher) { + apiManager.registrationAPi.verifyUser(userVerify) + } + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RunReportRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RunReportRepositoryImpl.kt new file mode 100644 index 000000000..f24187988 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RunReportRepositoryImpl.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.mapper.toModel +import org.mifospay.core.data.repository.RunReportRepository +import org.mifospay.core.model.domain.Transaction +import org.mifospay.core.network.FineractApiManager + +class RunReportRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : RunReportRepository { + override suspend fun getTransactionReceipt( + outputType: String, + transactionId: String, + ): Flow> { + return apiManager.runReportApi + .getTransactionReceipt(outputType, transactionId) + .map { it.toModel() } + .asResult() + .flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavedCardRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavedCardRepositoryImpl.kt new file mode 100644 index 000000000..3bf8bd19b --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavedCardRepositoryImpl.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.SavedCardRepository +import org.mifospay.core.model.entity.savedcards.Card +import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.GenericResponse + +class SavedCardRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : SavedCardRepository { + override suspend fun getSavedCards(clientId: Int): Flow>> { + return apiManager.savedCardApi.getSavedCards(clientId).asResult().flowOn(ioDispatcher) + } + + override suspend fun addSavedCard(clientId: Int, card: Card): Flow> { + return apiManager.savedCardApi.addSavedCard(clientId, card).asResult().flowOn(ioDispatcher) + } + + override suspend fun deleteCard(clientId: Int, cardId: Int): Flow> { + return apiManager.savedCardApi.deleteCard(clientId, cardId).asResult().flowOn(ioDispatcher) + } + + override suspend fun updateCard( + clientId: Int, + cardId: Int, + card: Card, + ): Flow> { + return apiManager.savedCardApi + .updateCard(clientId, cardId, card) + .asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavingsAccountRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavingsAccountRepositoryImpl.kt new file mode 100644 index 000000000..0e450c251 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavingsAccountRepositoryImpl.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.mapper.toModel +import org.mifospay.core.data.repository.SavingsAccountRepository +import org.mifospay.core.model.domain.Transaction +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.accounts.savings.SavingAccount +import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity +import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity +import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.GenericResponse + +class SavingsAccountRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : SavingsAccountRepository { + override suspend fun getSavingsAccounts( + limit: Int, + ): Flow>> { + return apiManager.savingsAccountsApi + .getSavingsAccounts(limit) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun getSavingsWithAssociations( + accountId: Long, + associationType: String, + ): Flow> { + return apiManager.savingsAccountsApi + .getSavingsWithAssociations(accountId, associationType) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun createSavingsAccount( + savingAccount: SavingAccount, + ): Flow> { + return apiManager.savingsAccountsApi + .createSavingsAccount(savingAccount) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun blockUnblockAccount( + accountId: Long, + command: String?, + ): Flow> { + return apiManager.savingsAccountsApi + .blockUnblockAccount(accountId, command) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun getSavingAccountTransaction( + accountId: Long, + transactionId: Long, + ): Flow> { + return apiManager.savingsAccountsApi + .getSavingAccountTransaction(accountId, transactionId) + .map(TransactionsEntity::toModel) + .asResult() + .flowOn(ioDispatcher) + } + + override suspend fun payViaMobile(accountId: Long): Flow> { + return apiManager.savingsAccountsApi + .payViaMobile(accountId) + .map(TransactionsEntity::toModel) + .asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt new file mode 100644 index 000000000..fc2aa0571 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.SearchRepository +import org.mifospay.core.model.entity.SearchedEntity +import org.mifospay.core.network.FineractApiManager + +class SearchRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : SearchRepository { + override suspend fun searchResources( + query: String, + resources: String, + exactMatch: Boolean, + ): Flow>> { + return apiManager.searchApi + .searchResources(query, resources, exactMatch) + .asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt new file mode 100644 index 000000000..32d33bac5 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt @@ -0,0 +1,95 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.mapper.toModel +import org.mifospay.core.data.repository.SelfServiceRepository +import org.mifospay.core.data.util.Constants +import org.mifospay.core.model.domain.client.Client +import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity +import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity +import org.mifospay.core.model.entity.authentication.AuthenticationPayload +import org.mifospay.core.model.entity.beneficary.Beneficiary +import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload +import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload +import org.mifospay.core.model.entity.client.ClientAccounts +import org.mifospay.core.network.SelfServiceApiManager +import org.mifospay.core.network.model.CommonResponse + +class SelfServiceRepositoryImpl( + private val apiManager: SelfServiceApiManager, + private val dispatcher: CoroutineDispatcher, +) : SelfServiceRepository { + + override suspend fun loginSelf(payload: AuthenticationPayload): Flow> { + return apiManager.authenticationApi.authenticate(payload).asResult().flowOn(dispatcher) + } + + override suspend fun getSelfClientDetails(clientId: Long): Flow> { + return apiManager.clientsApi + .getClientForId(clientId) + .map { it.toModel() } + .asResult().flowOn(dispatcher) + } + + override suspend fun getSelfClientDetails(): Flow>> { + return apiManager.clientsApi.clients().map { it.toModel() }.asResult().flowOn(dispatcher) + } + + override suspend fun getSelfAccountTransactions( + accountId: Long, + ): Flow> { + return apiManager.savingAccountsListApi + .getSavingsWithAssociations(accountId, Constants.TRANSACTIONS) + .asResult().flowOn(dispatcher) + } + + override suspend fun getSelfAccountTransactionFromId( + accountId: Long, + transactionId: Long, + ): Flow> { + return apiManager.savingAccountsListApi + .getSavingAccountTransaction(accountId, transactionId) + .asResult().flowOn(dispatcher) + } + + override suspend fun getSelfAccounts(clientId: Long): Flow> { + return apiManager.clientsApi + .getAccounts(clientId, Constants.SAVINGS) + .asResult().flowOn(dispatcher) + } + + override suspend fun getBeneficiaryList(): Flow>> { + return apiManager.beneficiaryApi.beneficiaryList().asResult().flowOn(dispatcher) + } + + override suspend fun createBeneficiary(beneficiaryPayload: BeneficiaryPayload): Flow> { + return apiManager.beneficiaryApi + .createBeneficiary(beneficiaryPayload) + .asResult().flowOn(dispatcher) + } + + override suspend fun updateBeneficiary( + beneficiaryId: Long, + payload: BeneficiaryUpdatePayload, + ): Flow> { + return apiManager.beneficiaryApi + .updateBeneficiary(beneficiaryId, payload) + .asResult().flowOn(dispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/StandingInstructionRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/StandingInstructionRepositoryImpl.kt new file mode 100644 index 000000000..5693df4c1 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/StandingInstructionRepositoryImpl.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.StandingInstructionRepository +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.payload.StandingInstructionPayload +import org.mifospay.core.model.entity.standinginstruction.SDIResponse +import org.mifospay.core.model.entity.standinginstruction.StandingInstruction +import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.GenericResponse + +class StandingInstructionRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : StandingInstructionRepository { + override suspend fun getAllStandingInstructions( + clientId: Long, + ): Flow>> { + return apiManager.standingInstructionApi + .getAllStandingInstructions(clientId) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun getStandingInstruction( + instructionId: Long, + ): Flow> { + return apiManager.standingInstructionApi + .getStandingInstruction(instructionId) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun createStandingInstruction( + payload: StandingInstructionPayload, + ): Flow> { + return apiManager.standingInstructionApi + .createStandingInstruction(payload) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun updateStandingInstruction( + instructionId: Long, + payload: StandingInstructionPayload, + ): Flow> { + return apiManager.standingInstructionApi + .updateStandingInstruction(instructionId, payload, "update") + .asResult().flowOn(ioDispatcher) + } + + override suspend fun deleteStandingInstruction( + instructionId: Long, + ): Flow> { + return apiManager.standingInstructionApi + .deleteStandingInstruction(instructionId, "delete") + .asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ThirdPartyTransferRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ThirdPartyTransferRepositoryImpl.kt new file mode 100644 index 000000000..8a4b466ce --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ThirdPartyTransferRepositoryImpl.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.ThirdPartyTransferRepository +import org.mifospay.core.model.entity.TPTResponse +import org.mifospay.core.model.entity.payload.TransferPayload +import org.mifospay.core.model.entity.templates.account.AccountOptionsTemplate +import org.mifospay.core.network.FineractApiManager + +class ThirdPartyTransferRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : ThirdPartyTransferRepository { + override suspend fun getTransferTemplate(): Flow> { + return apiManager.thirdPartyTransferApi + .accountTransferTemplate() + .asResult().flowOn(ioDispatcher) + } + + override suspend fun makeTransfer(payload: TransferPayload): Flow> { + return apiManager.thirdPartyTransferApi + .makeTransfer(payload) + .asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/TwoFactorAuthRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/TwoFactorAuthRepositoryImpl.kt new file mode 100644 index 000000000..d2342495e --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/TwoFactorAuthRepositoryImpl.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.TwoFactorAuthRepository +import org.mifospay.core.model.domain.twofactor.AccessToken +import org.mifospay.core.model.domain.twofactor.DeliveryMethod +import org.mifospay.core.network.FineractApiManager + +class TwoFactorAuthRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : TwoFactorAuthRepository { + override suspend fun deliveryMethods(): Flow>> { + return apiManager.twoFactorAuthApi.deliveryMethods().asResult().flowOn(ioDispatcher) + } + + override suspend fun requestOTP(deliveryMethod: String): Flow> { + return apiManager.twoFactorAuthApi + .requestOTP(deliveryMethod) + .asResult().flowOn(ioDispatcher) + } + + override suspend fun validateToken(token: String): Flow> { + return apiManager.twoFactorAuthApi.validateToken(token).asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt new file mode 100644 index 000000000..7cac96cd9 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.repositoryImp + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn +import org.mifospay.core.common.Result +import org.mifospay.core.common.asResult +import org.mifospay.core.data.repository.UserRepository +import org.mifospay.core.model.domain.user.NewUser +import org.mifospay.core.model.entity.UserWithRole +import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.CommonResponse +import org.mifospay.core.network.model.GenericResponse + +class UserRepositoryImpl( + private val apiManager: FineractApiManager, + private val ioDispatcher: CoroutineDispatcher, +) : UserRepository { + override fun getUsers(): Flow>> { + return apiManager.userApi.users().asResult().flowOn(ioDispatcher) + } + + override fun getUser(): Flow> { + return apiManager.userApi.getUser().asResult().flowOn(ioDispatcher) + } + + override fun createUser(newUser: NewUser): Flow> { + return apiManager.userApi.createUser(newUser).asResult().flowOn(ioDispatcher) + } + + override fun updateUser(userId: Int, updatedUser: NewUser): Flow> { + return apiManager.userApi.updateUser(userId, updatedUser).asResult().flowOn(ioDispatcher) + } + + override fun deleteUser(userId: Int): Flow> { + return apiManager.userApi.deleteUser(userId).asResult().flowOn(ioDispatcher) + } +} diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/util/Constants.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/util/Constants.kt similarity index 92% rename from core/data/src/androidMain/java/org/mifospay/core/data/util/Constants.kt rename to core/data/src/commonMain/kotlin/org/mifospay/core/data/util/Constants.kt index 758c1fb23..669234b76 100644 --- a/core/data/src/androidMain/java/org/mifospay/core/data/util/Constants.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/util/Constants.kt @@ -9,9 +9,6 @@ */ package org.mifospay.core.data.util -import java.util.Arrays -import java.util.Collections - object Constants { const val BASIC = "Basic " const val SAVINGS = "savingsAccounts" @@ -22,10 +19,7 @@ object Constants { private const val MOBILE_WALLET_ROLE_ID = 471 private const val SUPER_USER_ROLE_ID = 1 - @JvmField - val NEW_USER_ROLE_IDS: Collection = Collections.unmodifiableList( - Arrays.asList(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID), - ) + val NEW_USER_ROLE_IDS: List = listOf(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID) const val ENTITY_TYPE_CLIENTS = "clients" const val FETCH_ACCOUNT_TRANSFER_USECASE = "FetchAccountTransfer" const val NO_SAVED_CARDS = "No saved cards." diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/util/NetworkMonitor.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/util/NetworkMonitor.kt similarity index 100% rename from core/data/src/androidMain/java/org/mifospay/core/data/util/NetworkMonitor.kt rename to core/data/src/commonMain/kotlin/org/mifospay/core/data/util/NetworkMonitor.kt diff --git a/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalAssetRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/util/TimeZoneMonitor.kt similarity index 50% rename from core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalAssetRepository.kt rename to core/data/src/commonMain/kotlin/org/mifospay/core/data/util/TimeZoneMonitor.kt index 4ed5c49d0..bea88a147 100644 --- a/core/data/src/androidMain/java/org/mifospay/core/data/repository/local/LocalAssetRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/util/TimeZoneMonitor.kt @@ -7,20 +7,16 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.data.repository.local +package org.mifospay.core.data.util -import com.mifospay.core.model.City -import com.mifospay.core.model.Country -import com.mifospay.core.model.State import kotlinx.coroutines.flow.Flow +import kotlinx.datetime.TimeZone -interface LocalAssetRepository { - - fun getCountries(): Flow> - - fun getStateList(): Flow> - - fun getBanks(): Flow> +/** + * Utility for reporting current timezone the device has set. + * It always emits at least once with default setting and then for each TZ change. + */ - fun getCities(): Flow> +interface TimeZoneMonitor { + val currentTimeZone: Flow } diff --git a/core/data/src/jvmMain/kotlin/org/mifospay/core/data/JvmPlatformDependentDataModule.kt b/core/data/src/jvmMain/kotlin/org/mifospay/core/data/JvmPlatformDependentDataModule.kt new file mode 100644 index 000000000..ba5672f7e --- /dev/null +++ b/core/data/src/jvmMain/kotlin/org/mifospay/core/data/JvmPlatformDependentDataModule.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.datetime.TimeZone +import org.mifospay.core.data.di.PlatformDependentDataModule +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneMonitor + +class JvmPlatformDependentDataModule : PlatformDependentDataModule() { + override fun bindsNetworkMonitor(): NetworkMonitor { + return object : NetworkMonitor { + override val isOnline: Flow + get() = flowOf(true) + } + } + + override fun bindsTimeZoneMonitor(): TimeZoneMonitor { + return object : TimeZoneMonitor { + override val currentTimeZone: Flow + get() = flowOf(TimeZone.currentSystemDefault()) + } + } +} diff --git a/core/data/src/nativeMain/kotlin/org/mifospay/core/data/NativePlatformDependentDataModule.kt b/core/data/src/nativeMain/kotlin/org/mifospay/core/data/NativePlatformDependentDataModule.kt new file mode 100644 index 000000000..e02565f39 --- /dev/null +++ b/core/data/src/nativeMain/kotlin/org/mifospay/core/data/NativePlatformDependentDataModule.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.datetime.TimeZone +import org.mifospay.core.data.di.PlatformDependentDataModule +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneMonitor + +class NativePlatformDependentDataModule : PlatformDependentDataModule() { + override fun bindsNetworkMonitor(): NetworkMonitor { + return object : NetworkMonitor { + override val isOnline: Flow + get() = flowOf(true) + } + } + + override fun bindsTimeZoneMonitor(): TimeZoneMonitor { + return object : TimeZoneMonitor { + override val currentTimeZone: Flow + get() = flowOf(TimeZone.currentSystemDefault()) + } + } +} diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt index f3d4a9bf3..4d5edcf1b 100644 --- a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt +++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.datastore.proto import kotlinx.serialization.Serializable @@ -21,4 +30,4 @@ data class ClientPreferences( mobileNo = "", ) } -} \ No newline at end of file +} diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt index 5568d8e46..17269b376 100644 --- a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt +++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.datastore.proto import kotlinx.serialization.Serializable @@ -7,14 +16,14 @@ data class RolePreferences( val id: String, val name: String, val description: String, - val disabled: Boolean + val disabled: Boolean, ) { companion object { val DEFAULT = RolePreferences( id = "", name = "", description = "", - disabled = false + disabled = false, ) } } diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt index 179ca3c3b..af951f03b 100644 --- a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt +++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.datastore.proto import kotlinx.serialization.Serializable @@ -14,7 +23,7 @@ data class UserInfoPreferences( val permissions: List, val clients: List, val shouldRenewPassword: Boolean, - val isTwoFactorAuthenticationRequired: Boolean + val isTwoFactorAuthenticationRequired: Boolean, ) { companion object { val DEFAULT = UserInfoPreferences( @@ -28,7 +37,7 @@ data class UserInfoPreferences( permissions = emptyList(), clients = emptyList(), shouldRenewPassword = false, - isTwoFactorAuthenticationRequired = false + isTwoFactorAuthenticationRequired = false, ) } } diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt index 07113fc78..91d76ef11 100644 --- a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt +++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.datastore.proto import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt index 01e0c5e2e..00eb538fe 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt @@ -14,18 +14,9 @@ import kotlinx.serialization.Serializable @Serializable data class Client( val name: String? = null, - val image: String, + val image: String? = null, val externalId: String? = null, val clientId: Long = 0L, - val displayName: String, - val mobileNo: String, -) { - constructor() : this( - name = "", - image = "", - externalId = "", - clientId = 0L, - displayName = "", - mobileNo = "", - ) -} + val displayName: String? = null, + val mobileNo: String? = null, +) \ No newline at end of file diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentType.kt index cd19f5e89..3318b0fb9 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentType.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentType.kt @@ -15,4 +15,5 @@ import kotlinx.serialization.Serializable data class PaymentType( val id: Int? = null, val name: String? = null, + val isSystemDefined: Boolean, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociationsEntity.kt similarity index 64% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociationsEntity.kt index ae8e2b0fc..5e4f55c7c 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociations.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociationsEntity.kt @@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable import org.mifospay.core.model.entity.client.DepositType @Serializable -data class SavingsWithAssociations( +data class SavingsWithAssociationsEntity( val id: Long = 0L, val accountNo: String? = null, val depositType: DepositType? = null, @@ -38,30 +38,5 @@ data class SavingsWithAssociations( @SerialName("isDormancyTrackingActive") val dormancyTrackingActive: Boolean? = null, val summary: Summary? = null, - val transactions: List = ArrayList(), -) { - constructor() : this( - id = 0L, - accountNo = null, - depositType = null, - externalId = "", - clientId = 0, - clientName = "", - savingsProductId = null, - savingsProductName = null, - fieldOfficerId = 0, - status = null, - timeline = null, - currency = null, - nominalAnnualInterestRate = null, - minRequiredOpeningBalance = null, - lockinPeriodFrequency = 0.0, - withdrawalFeeForTransfers = false, - allowOverdraft = false, - enforceMinRequiredBalance = false, - withHoldTax = null, - lastActiveTransactionDate = listOf(), - dormancyTrackingActive = null, - summary = null, - ) -} + val transactions: List = ArrayList(), +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt index 532a91c42..baed86912 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt @@ -30,4 +30,6 @@ data class TransactionType( val overdraftFee: Boolean = false, val withholdTax: Boolean = false, val escheat: Boolean? = null, -) + val amountHold: Boolean = false, + val amountRelease: Boolean = false, +) \ No newline at end of file diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transactions.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionsEntity.kt similarity index 64% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transactions.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionsEntity.kt index 00db6abea..45c081985 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transactions.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionsEntity.kt @@ -12,8 +12,9 @@ package org.mifospay.core.model.entity.accounts.savings import kotlinx.serialization.Serializable @Serializable -data class Transactions( +data class TransactionsEntity( val id: Int? = null, + val entryType: String? = null, val transactionType: TransactionType = TransactionType(), val accountId: Int? = null, val accountNo: String? = null, @@ -21,25 +22,14 @@ data class Transactions( val currency: Currency = Currency(), val paymentDetailData: PaymentDetailData? = null, val amount: Double = 0.0, - val transfer: Transfer = Transfer(), val runningBalance: Double? = null, val reversed: Boolean? = null, val submittedOnDate: List = ArrayList(), val interestedPostedAsOn: Boolean? = null, -) { - constructor() : this( - id = 0, - transactionType = TransactionType(), - accountId = 0, - accountNo = "", - date = ArrayList(), - currency = Currency(), - paymentDetailData = PaymentDetailData(), - amount = 0.0, - transfer = Transfer(), - runningBalance = 0.0, - reversed = false, - submittedOnDate = ArrayList(), - interestedPostedAsOn = false, - ) -} + val submittedByUsername: String? = null, + val isManualTransaction: Boolean = false, + val isReversal: Boolean = false, + val originalTransactionId: Long? = null, + val lienTransaction: Boolean = false, + val releaseTransactionId: Long? = null, +) \ No newline at end of file diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Client.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientEntity.kt similarity index 68% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Client.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientEntity.kt index 5d5cd3922..a0e9915b2 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Client.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientEntity.kt @@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable import org.mifospay.core.model.entity.Timeline @Serializable -data class Client( +data class ClientEntity( val id: Int = 0, val accountNo: String? = null, val status: Status? = null, @@ -36,27 +36,4 @@ data class Client( val isImagePresent: Boolean = false, val externalId: String = "", val mobileNo: String = "", -) { - constructor() : this( - id = 0, - accountNo = "", - status = Status(), - active = false, - activationDate = ArrayList(), - dobDate = ArrayList(), - firstname = "", - middlename = "", - lastname = "", - displayName = "", - fullname = "", - officeId = 0, - officeName = "", - staffId = 0, - staffName = "", - timeline = Timeline(), - imageId = 0, - isImagePresent = false, - externalId = "", - mobileNo = "", - ) -} +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt index 6d9edad60..874762bcd 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt @@ -11,16 +11,16 @@ package org.mifospay.core.model.entity.standinginstruction import kotlinx.serialization.Serializable import org.mifospay.core.model.entity.accounts.savings.SavingAccount -import org.mifospay.core.model.entity.client.Client +import org.mifospay.core.model.entity.client.ClientEntity import org.mifospay.core.model.entity.client.Status @Serializable data class StandingInstruction( val id: Long, val name: String, - val fromClient: Client, + val fromClient: ClientEntity, val fromAccount: SavingAccount, - val toClient: Client, + val toClient: ClientEntity, val toAccount: SavingAccount, val status: Status, val amount: Double, diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index f4f2243dd..68ba5e7bb 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -19,6 +19,7 @@ */ plugins { alias(libs.plugins.mifospay.kmp.library) + alias(libs.plugins.mifospay.kotlin.inject) alias(libs.plugins.ktrofit) id("kotlinx-serialization") id("com.google.devtools.ksp") @@ -49,10 +50,13 @@ kotlin { implementation(libs.ktor.client.logging) implementation(libs.ktor.client.serialization) implementation(libs.ktor.client.content.negotiation) + implementation(libs.ktor.client.auth) + implementation(libs.ktor.client.cio) implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.ktorfit.lib) implementation(libs.ktorfit.converters.call) implementation(libs.ktorfit.converters.flow) + implementation(libs.squareup.okio) } androidMain.dependencies { implementation(libs.ktor.client.android) diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiInterceptor.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiInterceptor.kt deleted file mode 100644 index 26d2511d6..000000000 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiInterceptor.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network - -import okhttp3.Interceptor -import okhttp3.Response -import org.mifospay.core.datastore.PreferencesHelper -import java.io.IOException - -class ApiInterceptor(private val preferencesHelper: PreferencesHelper) : Interceptor { - - @Throws(IOException::class) - override fun intercept(chain: Interceptor.Chain): Response { - val chainRequest = chain.request() - val builder = chainRequest.newBuilder().header( - HEADER_TENANT, - DEFAULT, - ) - val authToken = preferencesHelper.token - if (!authToken.isNullOrEmpty()) { - builder.header(HEADER_AUTH, authToken) - } - val request = builder.build() - return chain.proceed(request) - } - - companion object { - const val HEADER_TENANT = "Fineract-Platform-TenantId" - const val HEADER_AUTH = "Authorization" - const val DEFAULT = "venus" - } -} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt deleted file mode 100644 index 37cc92891..000000000 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/JvmLocalAssetManager.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network - -import androidx.annotation.VisibleForTesting -import org.mifospay.core.network.localAssets.LocalAssetManager -import java.io.File -import java.io.InputStream - -/** - * This class helps with loading Android `/assets` files, especially when running JVM unit tests. - * It must remain on the root package for an easier [Class.getResource] with relative paths. - * @see https://developer.android.com/reference/tools/gradle-api/7.3/com/android/build/api/dsl/UnitTestOptions - */ - -@VisibleForTesting -internal object JvmLocalAssetManager : LocalAssetManager { -// private val config = -// requireNotNull(javaClass.getResource("com/android/tools/test_config.properties")) { -// """ -// Missing Android resources properties file. -// Did you forget to enable the feature in the gradle build file? -// android.testOptions.unitTests.isIncludeAndroidResources = true -// """.trimIndent() -// } -// private val properties = Properties().apply { config.openStream().use(::load) } -// private val assets = File(properties["android_merged_assets"].toString()) - - override fun open(fileName: String): InputStream = File(fileName).inputStream() -} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorInterceptor.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorInterceptor.kt deleted file mode 100644 index 5a5fd156f..000000000 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorInterceptor.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network - -import io.ktor.client.HttpClient -import io.ktor.client.plugins.HttpClientPlugin -import io.ktor.client.request.HttpRequestPipeline -import io.ktor.client.request.header -import io.ktor.util.AttributeKey -import org.mifospay.core.datastore.PreferencesHelper - -class KtorInterceptor( - private val preferencesHelper: PreferencesHelper, -) { - class Config { - lateinit var preferencesHelper: PreferencesHelper - } - - companion object Plugin : HttpClientPlugin { - const val HEADER_TENANT = "Fineract-Platform-TenantId" - const val HEADER_AUTH = "Authorization" - const val DEFAULT = "venus" - - override val key: AttributeKey = AttributeKey("KtorInterceptor") - - override fun install(plugin: KtorInterceptor, scope: HttpClient) { - scope.requestPipeline.intercept(HttpRequestPipeline.State) { - val authToken = plugin.preferencesHelper.token - context.header(HEADER_TENANT, DEFAULT) - if (!authToken.isNullOrEmpty()) { - context.header(HEADER_AUTH, authToken) - } - } - } - - override fun prepare(block: Config.() -> Unit): KtorInterceptor { - val config = Config().apply(block) - return KtorInterceptor(config.preferencesHelper) - } - } -} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt deleted file mode 100644 index b2fd7bafd..000000000 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/MifosWalletOkHttpClient.kt +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network - -import okhttp3.OkHttpClient -import okhttp3.logging.HttpLoggingInterceptor -import org.mifospay.core.datastore.PreferencesHelper -import java.security.SecureRandom -import java.security.cert.CertificateException -import java.security.cert.X509Certificate -import java.util.concurrent.TimeUnit -import javax.net.ssl.SSLContext -import javax.net.ssl.TrustManager -import javax.net.ssl.X509TrustManager - -class MifosWalletOkHttpClient(private val preferences: PreferencesHelper) { - // Create a trust manager that does not validate certificate chains - val mifosOkHttpClient: OkHttpClient - // Interceptor :> Full Body Logger and ApiRequest Header - get() { - val builder = OkHttpClient.Builder() - try { - // Create a trust manager that does not validate certificate chains - val trustAllCerts = arrayOf( - object : X509TrustManager { - @Throws(CertificateException::class) - override fun checkClientTrusted( - chain: Array, - authType: String, - ) { - } - - @Throws(CertificateException::class) - override fun checkServerTrusted( - chain: Array, - authType: String, - ) { - } - - override fun getAcceptedIssuers(): Array { - return emptyArray() - } - }, - ) - - // Install the all-trusting trust manager - val sslContext = SSLContext.getInstance("SSL") - sslContext.init(null, trustAllCerts, SecureRandom()) - // Create an ssl socket factory with our all-trusting manager - val sslSocketFactory = sslContext.socketFactory - - // Enable Full Body Logging - val logger = HttpLoggingInterceptor() - logger.level = HttpLoggingInterceptor.Level.BODY - - // Set SSL certificate to OkHttpClient Builder -// builder.sslSocketFactory(sslSocketFactory) - builder.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager) - builder.hostnameVerifier { _, _ -> true } - } catch (e: Exception) { - throw RuntimeException(e) - } - - // Enable Full Body Logging - val logger = HttpLoggingInterceptor() - logger.level = HttpLoggingInterceptor.Level.BODY - - // Setting Timeout 30 Seconds - builder.connectTimeout(60, TimeUnit.SECONDS) - builder.readTimeout(60, TimeUnit.SECONDS) - - // Interceptor :> Full Body Logger and ApiRequest Header - builder.addInterceptor(logger) - builder.addInterceptor(ApiInterceptor(preferences)) - return builder.build() - } -} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt deleted file mode 100644 index 639d5623c..000000000 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.di - -import io.ktor.client.HttpClient -import io.ktor.client.engine.android.Android -import io.ktor.client.plugins.HttpTimeout -import io.ktor.client.plugins.contentnegotiation.ContentNegotiation -import io.ktor.client.plugins.logging.LogLevel -import io.ktor.client.plugins.logging.Logging -import io.ktor.client.plugins.websocket.WebSockets -import io.ktor.serialization.kotlinx.json.json -import kotlinx.serialization.json.Json -import org.koin.dsl.module -import org.mifospay.core.datastore.PreferencesHelper -import org.mifospay.core.network.BaseURL -import org.mifospay.core.network.FineractApiManager -import org.mifospay.core.network.KtorInterceptor -import org.mifospay.core.network.MifosWalletOkHttpClient -import org.mifospay.core.network.SelfServiceApiManager -import org.mifospay.core.network.services.AccountTransfersService -import org.mifospay.core.network.services.AuthenticationService -import org.mifospay.core.network.services.BeneficiaryService -import org.mifospay.core.network.services.ClientService -import org.mifospay.core.network.services.DocumentService -import org.mifospay.core.network.services.InvoiceService -import org.mifospay.core.network.services.KYCLevel1Service -import org.mifospay.core.network.services.KtorAuthenticationService -import org.mifospay.core.network.services.KtorSavingsAccountService -import org.mifospay.core.network.services.NotificationService -import org.mifospay.core.network.services.RegistrationService -import org.mifospay.core.network.services.RunReportService -import org.mifospay.core.network.services.SavedCardService -import org.mifospay.core.network.services.SavingsAccountsService -import org.mifospay.core.network.services.SearchService -import org.mifospay.core.network.services.StandingInstructionService -import org.mifospay.core.network.services.ThirdPartyTransferService -import org.mifospay.core.network.services.TwoFactorAuthService -import org.mifospay.core.network.services.UserService -import retrofit2.Retrofit -import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory -import retrofit2.converter.gson.GsonConverterFactory - -@Suppress("TooManyFunctions") -val NetworkModule = module { - - single { - Json { - ignoreUnknownKeys = true - } - } - - single(SelfServiceApi) { - val preferencesHelper: PreferencesHelper = get() - Retrofit.Builder() - .baseUrl(BaseURL().selfServiceUrl) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - .client(MifosWalletOkHttpClient(preferencesHelper).mifosOkHttpClient) - .build() - } - - single(FineractApi) { - val preferencesHelper: PreferencesHelper = get() - Retrofit.Builder() - .baseUrl(BaseURL().url) - .addConverterFactory(GsonConverterFactory.create()) - .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) - .client(MifosWalletOkHttpClient(preferencesHelper).mifosOkHttpClient) - .build() - } - - single { - FineractApiManager( - authenticationService = get(FineractAuthenticationService), - clientService = get(FineractClientService), - savingsAccountsService = get(FineractSavingsAccountsService), - registrationService = get(FineractRegistrationService), - searchService = get(), - documentService = get(), - runReportService = get(), - twoFactorAuthService = get(), - accountTransfersService = get(), - savedCardService = get(), - kYCLevel1Service = get(), - invoiceService = get(), - userService = get(), - thirdPartyTransferService = get(FineractThirdPartyTransferService), - standingInstructionService = get(), - notificationService = get(), - ktorSavingsAccountService = get(), - ) - } - - single { - SelfServiceApiManager( - authenticationService = get(SelfServiceAuthenticationService), - clientService = get(SelfServiceClientService), - savingsAccountsService = get(SelfServiceSavingsAccountsService), - registrationService = get(SelfServiceRegistrationService), - beneficiaryService = get(), - thirdPartyTransferService = get(SelfServiceThirdPartyTransferService), - ktorSavingsAccountService = get(), - ) - } - -// Http client for Ktor - - single { - HttpClient(Android) { - install(WebSockets) - install(KtorInterceptor) { - this.preferencesHelper = get() - } - install(ContentNegotiation) { - json( - Json { - ignoreUnknownKeys = true - isLenient = true - }, - ) - } - install(HttpTimeout) { - requestTimeoutMillis = 15000 - } - install(Logging) { - level = LogLevel.ALL - } - } - } - - single { KtorAuthenticationService(client = get()) } - single { KtorSavingsAccountService(client = get()) } - - // -----Fineract API Service---------// - - single(FineractAuthenticationService) { - get(FineractApi).create(AuthenticationService::class.java) - } - - single(FineractClientService) { - get(FineractApi).create(ClientService::class.java) - } - - single(FineractSavingsAccountsService) { - get(FineractApi).create(SavingsAccountsService::class.java) - } - - single(FineractRegistrationService) { - get(FineractApi).create(RegistrationService::class.java) - } - - single { - get(FineractApi).create(SearchService::class.java) - } - - single { - get(FineractApi).create(SavedCardService::class.java) - } - - single { - get(FineractApi).create(DocumentService::class.java) - } - - single { - get(FineractApi).create(TwoFactorAuthService::class.java) - } - - single { - get(FineractApi).create(AccountTransfersService::class.java) - } - - single { - get(FineractApi).create(RunReportService::class.java) - } - - single { - get(FineractApi).create(KYCLevel1Service::class.java) - } - - single { - get(FineractApi).create(InvoiceService::class.java) - } - - single { - get(FineractApi).create(UserService::class.java) - } - - single(FineractThirdPartyTransferService) { - get(FineractApi).create(ThirdPartyTransferService::class.java) - } - - single { - get(FineractApi).create(NotificationService::class.java) - } - - single { - get(FineractApi).create(StandingInstructionService::class.java) - } - - // -------SelfService API Service-------// - - single(SelfServiceAuthenticationService) { - get(SelfServiceApi).create(AuthenticationService::class.java) - } - - single(SelfServiceClientService) { - get(SelfServiceApi).create(ClientService::class.java) - } - - single(SelfServiceSavingsAccountsService) { - get(SelfServiceApi).create(SavingsAccountsService::class.java) - } - - single(SelfServiceRegistrationService) { - get(SelfServiceApi).create(RegistrationService::class.java) - } - - single { - get(SelfServiceApi).create(BeneficiaryService::class.java) - } - - single(SelfServiceThirdPartyTransferService) { - get(SelfServiceApi).create(ThirdPartyTransferService::class.java) - } -} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ClientService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ClientService.kt deleted file mode 100644 index 02f7511f3..000000000 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ClientService.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.services - -import com.mifospay.core.model.domain.NewAccount -import com.mifospay.core.model.entity.Page -import com.mifospay.core.model.entity.client.Client -import com.mifospay.core.model.entity.client.ClientAccounts -import okhttp3.MultipartBody -import okhttp3.ResponseBody -import org.mifospay.core.network.ApiEndPoints -import org.mifospay.core.network.GenericResponse -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Part -import retrofit2.http.Path -import retrofit2.http.Query -import rx.Observable - -interface ClientService { - @get:GET(ApiEndPoints.CLIENTS) - val clients: Observable> - - @GET(ApiEndPoints.CLIENTS + "/{clientId}") - fun getClientForId(@Path("clientId") clientId: Long): Observable - - @PUT(ApiEndPoints.CLIENTS + "/{clientId}") - fun updateClient( - @Path("clientId") clientId: Long, - @Body payload: Any, - ): Observable - - @GET(ApiEndPoints.CLIENTS + "/{clientId}/images") - fun getClientImage(@Path("clientId") clientId: Long): Observable - - @PUT(ApiEndPoints.CLIENTS + "/{clientId}/images") - fun updateClientImage( - @Path("clientId") clientId: Long, - @Part typedFile: MultipartBody.Part?, - ): Observable - - @GET(ApiEndPoints.CLIENTS + "/{clientId}/accounts") - fun getClientAccounts(@Path("clientId") clientId: Long): Observable - - @GET(ApiEndPoints.CLIENTS + "/{clientId}/accounts") - fun getAccounts( - @Path("clientId") clientId: Long, - @Query("fields") accountType: String, - ): Observable - - @POST(ApiEndPoints.CLIENTS) - fun createClient(@Body newClient: com.mifospay.core.model.domain.client.NewClient): Observable - - @POST - fun createAccount(@Body newAccount: NewAccount?): Observable -} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt deleted file mode 100644 index 4df4b550c..000000000 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorAuthenticationService.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.services - -import com.mifospay.core.model.domain.user.User -import com.mifospay.core.model.entity.authentication.AuthenticationPayload -import io.ktor.client.HttpClient -import io.ktor.client.call.body -import io.ktor.client.request.post -import io.ktor.client.request.setBody -import io.ktor.http.ContentType -import io.ktor.http.contentType -import org.mifospay.core.network.BaseURL - -class KtorAuthenticationService( - private val client: HttpClient, -) { - - suspend fun authenticate(authPayload: AuthenticationPayload): User { - return client.post("${BaseURL().selfServiceUrl}authentication") { - contentType(ContentType.Application.Json) - setBody(authPayload) - }.body() - } -} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt deleted file mode 100644 index 141088cd7..000000000 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KtorSavingsAccountService.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.services - -import com.mifospay.core.model.entity.Page -import com.mifospay.core.model.entity.accounts.savings.SavingAccount -import com.mifospay.core.model.entity.accounts.savings.SavingsWithAssociations -import com.mifospay.core.model.entity.accounts.savings.Transactions -import io.ktor.client.HttpClient -import io.ktor.client.call.body -import io.ktor.client.request.get -import io.ktor.client.request.post -import io.ktor.client.request.setBody -import io.ktor.http.ContentType -import io.ktor.http.contentType -import org.mifospay.core.network.ApiEndPoints.SAVINGS_ACCOUNTS -import org.mifospay.core.network.ApiEndPoints.TRANSACTIONS -import org.mifospay.core.network.BaseURL -import org.mifospay.core.network.GenericResponse - -class KtorSavingsAccountService( - private val client: HttpClient, -) { - suspend fun getSavingsWithAssociations( - accountId: Long, - associationType: String, - ): SavingsWithAssociations { - return client.get("${BaseURL().selfServiceUrl}$SAVINGS_ACCOUNTS/$accountId") { - url { - parameters.append("associations", associationType) - } - }.body() - } - - suspend fun getSavingsAccounts(limit: Int): Page { - return client.get("${BaseURL().selfServiceUrl}$SAVINGS_ACCOUNTS") { - url { - parameters.append("limit", limit.toString()) - } - }.body() - } - - suspend fun createSavingsAccount(savingAccount: SavingAccount): GenericResponse { - return client.post("${BaseURL().selfServiceUrl}$SAVINGS_ACCOUNTS") { - contentType(ContentType.Application.Json) - setBody(savingAccount) - }.body() - } - - suspend fun blockUnblockAccount(accountId: Long, command: String?): GenericResponse { - return client.post("${BaseURL().selfServiceUrl}$SAVINGS_ACCOUNTS/$accountId") { - url { - parameters.append("command", command ?: "") - } - }.body() - } - - suspend fun getSavingAccountTransaction(accountId: Long, transactionId: Long): Transactions { - return client.get( - urlString = "${BaseURL().selfServiceUrl}$SAVINGS_ACCOUNTS/" + - "$accountId/$TRANSACTIONS/$transactionId", - ).body() - } - - suspend fun payViaMobile(accountId: Long): Transactions { - return client.post( - urlString = "${BaseURL().selfServiceUrl}$SAVINGS_ACCOUNTS/$accountId/$TRANSACTIONS", - ) { - url { - parameters.append("command", "deposit") - } - }.body() - } -} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt deleted file mode 100644 index a05074da1..000000000 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.services - -import com.mifospay.core.model.entity.TPTResponse -import com.mifospay.core.model.entity.payload.TransferPayload -import org.mifospay.core.model.entity.templates.account.AccountOptionsTemplate -import org.mifospay.core.network.ApiEndPoints -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import rx.Observable - -/** - * Created by dilpreet on 21/6/17. - */ -interface ThirdPartyTransferService { - @get:GET(ApiEndPoints.ACCOUNT_TRANSFER + "/template?type=tpt") - val accountTransferTemplate: Observable - - @POST(ApiEndPoints.ACCOUNT_TRANSFER + "?type=\"tpt\"") - fun makeTransfer(@Body transferPayload: TransferPayload): Observable -} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/UserService.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/UserService.kt deleted file mode 100644 index b2c65fba7..000000000 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/UserService.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.network.services - -import com.mifospay.core.model.domain.user.NewUser -import com.mifospay.core.model.entity.UserWithRole -import org.mifospay.core.network.ApiEndPoints -import org.mifospay.core.network.GenericResponse -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path -import rx.Observable - -/** - * Created by ankur on 11/June/2018 - */ -interface UserService { - @get:GET(ApiEndPoints.USER) - val users: Observable> - - @POST(ApiEndPoints.USER) - fun createUser(@Body user: NewUser): Observable - - @PUT(ApiEndPoints.USER + "/{userId}") - fun updateUser( - @Path("userId") userId: Int, - @Body updateUserEntity: Any, - ): Observable - - @DELETE(ApiEndPoints.USER + "/{userId}") - fun deleteUser( - @Path("userId") userId: Int, - ): Observable - - @GET("self/userdetails") - fun getUser(): Observable -} diff --git a/core/network/src/androidMain/assets/banks.json b/core/network/src/commonMain/assets/banks.json similarity index 100% rename from core/network/src/androidMain/assets/banks.json rename to core/network/src/commonMain/assets/banks.json diff --git a/core/network/src/androidMain/assets/cities.json b/core/network/src/commonMain/assets/cities.json similarity index 100% rename from core/network/src/androidMain/assets/cities.json rename to core/network/src/commonMain/assets/cities.json diff --git a/core/network/src/androidMain/assets/countries.json b/core/network/src/commonMain/assets/countries.json similarity index 100% rename from core/network/src/androidMain/assets/countries.json rename to core/network/src/commonMain/assets/countries.json diff --git a/core/network/src/androidMain/assets/countriesToCities.json b/core/network/src/commonMain/assets/countriesToCities.json similarity index 100% rename from core/network/src/androidMain/assets/countriesToCities.json rename to core/network/src/commonMain/assets/countriesToCities.json diff --git a/core/network/src/androidMain/assets/states.json b/core/network/src/commonMain/assets/states.json similarity index 100% rename from core/network/src/androidMain/assets/states.json rename to core/network/src/commonMain/assets/states.json diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt similarity index 100% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/BaseURL.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/BaseURL.kt similarity index 52% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/BaseURL.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/BaseURL.kt index 1359b7e8c..ed472d2e0 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/BaseURL.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/BaseURL.kt @@ -9,19 +9,22 @@ */ package org.mifospay.core.network -class BaseURL { +object BaseURL { + private const val PROTOCOL_HTTPS = "https://" + private const val API_ENDPOINT = "venus.mifos.community" + private const val API_PATH = "/fineract-provider/api/v1/" + + // self service url + private const val API_ENDPOINT_SELF = "venus.mifos.community" + private const val API_PATH_SELF = "/fineract-provider/api/v1/self/" + + const val HEADER_TENANT = "Fineract-Platform-TenantId" + const val HEADER_AUTH = "Authorization" + const val DEFAULT = "venus" + val url: String get() = PROTOCOL_HTTPS + API_ENDPOINT + API_PATH + val selfServiceUrl: String get() = PROTOCOL_HTTPS + API_ENDPOINT_SELF + API_PATH_SELF - - companion object { - const val PROTOCOL_HTTPS = "https://" - const val API_ENDPOINT = "venus.mifos.community" - const val API_PATH = "/fineract-provider/api/v1/" - - // self service url - const val API_ENDPOINT_SELF = "venus.mifos.community" - const val API_PATH_SELF = "/fineract-provider/api/v1/self/" - } } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/FineractApiManager.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/FineractApiManager.kt similarity index 54% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/FineractApiManager.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/FineractApiManager.kt index b42a185f4..8c89cdc72 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/FineractApiManager.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/FineractApiManager.kt @@ -15,7 +15,6 @@ import org.mifospay.core.network.services.ClientService import org.mifospay.core.network.services.DocumentService import org.mifospay.core.network.services.InvoiceService import org.mifospay.core.network.services.KYCLevel1Service -import org.mifospay.core.network.services.KtorSavingsAccountService import org.mifospay.core.network.services.NotificationService import org.mifospay.core.network.services.RegistrationService import org.mifospay.core.network.services.RunReportService @@ -28,73 +27,54 @@ import org.mifospay.core.network.services.TwoFactorAuthService import org.mifospay.core.network.services.UserService class FineractApiManager( - private val authenticationService: AuthenticationService, - private val clientService: ClientService, - private val savingsAccountsService: SavingsAccountsService, - private val registrationService: RegistrationService, - private val searchService: SearchService, - private val documentService: DocumentService, - private val runReportService: RunReportService, - private val twoFactorAuthService: TwoFactorAuthService, - private val accountTransfersService: AccountTransfersService, - private val savedCardService: SavedCardService, - private val kYCLevel1Service: KYCLevel1Service, - private val invoiceService: InvoiceService, - private val userService: UserService, - private val thirdPartyTransferService: ThirdPartyTransferService, - private val standingInstructionService: StandingInstructionService, - private val notificationService: NotificationService, - private val ktorSavingsAccountService: KtorSavingsAccountService, + private val ktorfitClient: KtorfitClient, ) { val authenticationApi: AuthenticationService - get() = authenticationService + get() = ktorfitClient.authenticationApi val clientsApi: ClientService - get() = clientService + get() = ktorfitClient.clientsApi val registrationAPi: RegistrationService - get() = registrationService + get() = ktorfitClient.registrationAPi val searchApi: SearchService - get() = searchService + get() = ktorfitClient.searchApi val documentApi: DocumentService - get() = documentService + get() = ktorfitClient.documentApi val runReportApi: RunReportService - get() = runReportService + get() = ktorfitClient.runReportApi val twoFactorAuthApi: TwoFactorAuthService - get() = twoFactorAuthService + get() = ktorfitClient.twoFactorAuthApi val accountTransfersApi: AccountTransfersService - get() = accountTransfersService + get() = ktorfitClient.accountTransfersApi val savedCardApi: SavedCardService - get() = savedCardService + get() = ktorfitClient.savedCardApi val kycLevel1Api: KYCLevel1Service - get() = kYCLevel1Service + get() = ktorfitClient.kycLevel1Api val invoiceApi: InvoiceService - get() = invoiceService + get() = ktorfitClient.invoiceApi val userApi: UserService - get() = userService + get() = ktorfitClient.userApi val thirdPartyTransferApi: ThirdPartyTransferService - get() = thirdPartyTransferService + get() = ktorfitClient.thirdPartyTransferApi val notificationApi: NotificationService - get() = notificationService + get() = ktorfitClient.notificationApi val savingsAccountsApi: SavingsAccountsService - get() = savingsAccountsService + get() = ktorfitClient.savingsAccountsApi val standingInstructionApi: StandingInstructionService - get() = standingInstructionService - - val ktorSavingsAccountApi: KtorSavingsAccountService - get() = ktorSavingsAccountService + get() = ktorfitClient.standingInstructionApi } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt new file mode 100644 index 000000000..86e5e5afa --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt @@ -0,0 +1,187 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import de.jensklingenberg.ktorfit.Ktorfit +import de.jensklingenberg.ktorfit.converter.CallConverterFactory +import de.jensklingenberg.ktorfit.converter.FlowConverterFactory +import io.ktor.client.HttpClient +import io.ktor.client.engine.cio.CIO +import io.ktor.client.plugins.DefaultRequest +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.http.ContentType +import io.ktor.http.contentType +import io.ktor.http.headers +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json +import org.mifospay.core.network.services.AccountTransfersService +import org.mifospay.core.network.services.AuthenticationService +import org.mifospay.core.network.services.BeneficiaryService +import org.mifospay.core.network.services.ClientService +import org.mifospay.core.network.services.DocumentService +import org.mifospay.core.network.services.InvoiceService +import org.mifospay.core.network.services.KYCLevel1Service +import org.mifospay.core.network.services.NotificationService +import org.mifospay.core.network.services.RegistrationService +import org.mifospay.core.network.services.RunReportService +import org.mifospay.core.network.services.SavedCardService +import org.mifospay.core.network.services.SavingsAccountsService +import org.mifospay.core.network.services.SearchService +import org.mifospay.core.network.services.StandingInstructionService +import org.mifospay.core.network.services.ThirdPartyTransferService +import org.mifospay.core.network.services.TwoFactorAuthService +import org.mifospay.core.network.services.UserService +import org.mifospay.core.network.services.createAccountTransfersService +import org.mifospay.core.network.services.createAuthenticationService +import org.mifospay.core.network.services.createBeneficiaryService +import org.mifospay.core.network.services.createClientService +import org.mifospay.core.network.services.createDocumentService +import org.mifospay.core.network.services.createInvoiceService +import org.mifospay.core.network.services.createKYCLevel1Service +import org.mifospay.core.network.services.createNotificationService +import org.mifospay.core.network.services.createRegistrationService +import org.mifospay.core.network.services.createRunReportService +import org.mifospay.core.network.services.createSavedCardService +import org.mifospay.core.network.services.createSavingsAccountsService +import org.mifospay.core.network.services.createSearchService +import org.mifospay.core.network.services.createStandingInstructionService +import org.mifospay.core.network.services.createThirdPartyTransferService +import org.mifospay.core.network.services.createTwoFactorAuthService +import org.mifospay.core.network.services.createUserService + +class KtorfitClient( + private val httpClient: HttpClient, + private val ktorfit: Ktorfit, +) { + internal val authenticationApi: AuthenticationService = ktorfit.createAuthenticationService() + + internal val clientsApi: ClientService = ktorfit.createClientService() + + internal val registrationAPi: RegistrationService = ktorfit.createRegistrationService() + + internal val searchApi: SearchService = ktorfit.createSearchService() + + internal val documentApi: DocumentService = ktorfit.createDocumentService() + + internal val runReportApi: RunReportService = ktorfit.createRunReportService() + + internal val twoFactorAuthApi: TwoFactorAuthService = ktorfit.createTwoFactorAuthService() + + internal val accountTransfersApi: AccountTransfersService = + ktorfit.createAccountTransfersService() + + internal val savedCardApi: SavedCardService = ktorfit.createSavedCardService() + + internal val kycLevel1Api: KYCLevel1Service = ktorfit.createKYCLevel1Service() + + internal val invoiceApi: InvoiceService = ktorfit.createInvoiceService() + + internal val userApi: UserService = ktorfit.createUserService() + + internal val thirdPartyTransferApi: ThirdPartyTransferService = + ktorfit.createThirdPartyTransferService() + + internal val notificationApi: NotificationService = ktorfit.createNotificationService() + + internal val savingsAccountsApi: SavingsAccountsService = ktorfit.createSavingsAccountsService() + + internal val standingInstructionApi: StandingInstructionService = + ktorfit.createStandingInstructionService() + + internal val beneficiaryApi: BeneficiaryService = ktorfit.createBeneficiaryService() + + class Builder internal constructor() { + private lateinit var baseURL: String + private var tenant: String? = BaseURL.DEFAULT + private var loginUsername: String? = null + private var loginPassword: String? = null + private var insecure: Boolean = false + private var token: String? = null + + fun baseURL(baseURL: String): Builder { + this.baseURL = baseURL + return this + } + + fun tenant(tenant: String?): Builder { + this.tenant = tenant + return this + } + + fun basicAuth(username: String?, password: String?): Builder { + this.loginUsername = username + this.loginPassword = password + return this + } + + fun inSecure(insecure: Boolean): Builder { + this.insecure = insecure + return this + } + + fun token(token: String?): Builder { + this.token = token + return this + } + + fun build(): KtorfitClient { + val ktorClient = HttpClient(CIO) { + install(ContentNegotiation) { + json( + Json { + isLenient = true + ignoreUnknownKeys = true + }, + ) + } + + install(DefaultRequest) + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.INFO + } + + defaultRequest { + contentType(ContentType.Application.Json) + headers { + append("Accept", "application/json") + tenant?.let { + append(BaseURL.HEADER_TENANT, it) + } + token?.let { + append(BaseURL.HEADER_AUTH, it) + } + } + } + } + + val ktorfitBuilder = Ktorfit.Builder() + .httpClient(ktorClient) + .baseUrl(baseURL) + .converterFactories(CallConverterFactory()) + .converterFactories(FlowConverterFactory()) + .build() + + return KtorfitClient(ktorClient, ktorfitBuilder) + } + } + + companion object { + fun builder(): Builder { + return Builder() + } + } +} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt similarity index 56% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt index 54ea9d17d..a2349b14e 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt @@ -12,32 +12,23 @@ package org.mifospay.core.network import org.mifospay.core.network.services.AuthenticationService import org.mifospay.core.network.services.BeneficiaryService import org.mifospay.core.network.services.ClientService -import org.mifospay.core.network.services.KtorSavingsAccountService import org.mifospay.core.network.services.RegistrationService import org.mifospay.core.network.services.SavingsAccountsService import org.mifospay.core.network.services.ThirdPartyTransferService class SelfServiceApiManager( - private val authenticationService: AuthenticationService, - private val clientService: ClientService, - private val savingsAccountsService: SavingsAccountsService, - private val registrationService: RegistrationService, - private val beneficiaryService: BeneficiaryService, - private val thirdPartyTransferService: ThirdPartyTransferService, - private val ktorSavingsAccountService: KtorSavingsAccountService, + private val ktorfitClient: KtorfitClient, ) { val authenticationApi: AuthenticationService - get() = authenticationService + get() = ktorfitClient.authenticationApi val clientsApi: ClientService - get() = clientService + get() = ktorfitClient.clientsApi val savingAccountsListApi: SavingsAccountsService - get() = savingsAccountsService + get() = ktorfitClient.savingsAccountsApi val registrationAPi: RegistrationService - get() = registrationService + get() = ktorfitClient.registrationAPi val beneficiaryApi: BeneficiaryService - get() = beneficiaryService + get() = ktorfitClient.beneficiaryApi val thirdPartyTransferApi: ThirdPartyTransferService - get() = thirdPartyTransferService - val ktorSavingsAccountApi: KtorSavingsAccountService - get() = ktorSavingsAccountService + get() = ktorfitClient.thirdPartyTransferApi } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/LocalModule.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/LocalModule.kt similarity index 77% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/di/LocalModule.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/di/LocalModule.kt index 484d2effe..73ab48acb 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/LocalModule.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/LocalModule.kt @@ -9,12 +9,12 @@ */ package org.mifospay.core.network.di -import org.koin.android.ext.koin.androidContext import org.koin.dsl.module +import org.mifospay.core.network.localAssets.JvmLocalAssetManager import org.mifospay.core.network.localAssets.LocalAssetManager val LocalModule = module { - single { - LocalAssetManager { fileName -> androidContext().assets.open(fileName) } + single { + JvmLocalAssetManager } } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt new file mode 100644 index 000000000..a40f51b42 --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt @@ -0,0 +1,50 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.di + +import kotlinx.serialization.json.Json +import org.koin.dsl.module +import org.mifospay.core.network.BaseURL +import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.KtorfitClient +import org.mifospay.core.network.SelfServiceApiManager + +val NetworkModule = module { + + single { + Json { + ignoreUnknownKeys = true + } + } + + single(BaseClient) { + KtorfitClient.builder() + .baseURL(BaseURL.url) + .build() + } + + single(SelfClient) { + KtorfitClient.builder() + .baseURL(BaseURL.selfServiceUrl) + .build() + } + + single { + FineractApiManager( + ktorfitClient = get(BaseClient), + ) + } + + single { + SelfServiceApiManager( + ktorfitClient = get(SelfClient), + ) + } +} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/Qualifier.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt similarity index 93% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/di/Qualifier.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt index ae0471f29..ce5bbce78 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/di/Qualifier.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt @@ -11,8 +11,8 @@ package org.mifospay.core.network.di import org.koin.core.qualifier.named -val SelfServiceApi = named("SelfServiceApi") -val FineractApi = named("FineractApi") +val SelfClient = named("SelfClient") +val BaseClient = named("BaseClient") val FineractAuthenticationService = named("FineractAuthenticationService") val FineractClientService = named("FineractClientService") diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt new file mode 100644 index 000000000..858c886f0 --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.localAssets + +import okio.FileHandle +import okio.FileSystem +import okio.Path.Companion.toPath +import okio.SYSTEM + +internal object JvmLocalAssetManager : LocalAssetManager { + override fun open(fileName: String): FileHandle { + val path = fileName.toPath() + return FileSystem.SYSTEM.openReadOnly(path) + } +} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt similarity index 100% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt similarity index 85% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt index 9930fbcf2..98f8b1138 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt @@ -9,8 +9,8 @@ */ package org.mifospay.core.network.localAssets -import java.io.InputStream +import okio.FileHandle fun interface LocalAssetManager { - fun open(fileName: String): InputStream + fun open(fileName: String): FileHandle } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt similarity index 61% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt index f14662124..78c4b9d60 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt @@ -9,14 +9,11 @@ */ package org.mifospay.core.network.localAssets +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.serialization.json.Json import org.mifospay.core.model.City import org.mifospay.core.model.Country import org.mifospay.core.model.State -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.withContext -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.json.Json -import kotlinx.serialization.json.decodeFromStream class MifosLocalAssetDataSource( private val ioDispatcher: CoroutineDispatcher, @@ -24,32 +21,20 @@ class MifosLocalAssetDataSource( private val assets: LocalAssetManager, ) : LocalAssetDataSource { - @OptIn(ExperimentalSerializationApi::class) override suspend fun getCountries(): List { - return withContext(ioDispatcher) { - assets.open(COUNTRIES_ASSET).use(networkJson::decodeFromStream) - } + return emptyList() } - @OptIn(ExperimentalSerializationApi::class) override suspend fun getStateList(): List { - return withContext(ioDispatcher) { - assets.open(STATES_ASSET).use(networkJson::decodeFromStream) - } + return emptyList() } - @OptIn(ExperimentalSerializationApi::class) override suspend fun getBanks(): List { - return withContext(ioDispatcher) { - assets.open(BANKS_ASSET).use(networkJson::decodeFromStream) - } + return emptyList() } - @OptIn(ExperimentalSerializationApi::class) override suspend fun getCities(): List { - return withContext(ioDispatcher) { - assets.open(CITIES_ASSET).use(networkJson::decodeFromStream) - } + return emptyList() } @Suppress("UnusedPrivateProperty") diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/CommonResponse.kt similarity index 68% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/CommonResponse.kt index 690658bce..2c2469a42 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/CommonResponse.kt @@ -7,6 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.network.services +package org.mifospay.core.network.model -interface SavingsAccountsService +import kotlinx.serialization.Serializable + +@Serializable +data class CommonResponse( + val resourceId: Int, +) diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/GenericResponse.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/GenericResponse.kt similarity index 91% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/GenericResponse.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/GenericResponse.kt index 59c2772f4..7d1ee084f 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/GenericResponse.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/GenericResponse.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.network +package org.mifospay.core.network.model data class GenericResponse( var responseFields: HashMap = hashMapOf(), diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt similarity index 74% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt index 731fb2795..16c31ed4d 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt @@ -9,16 +9,16 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.entity.accounts.savings.TransferDetail +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Path +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.entity.accounts.savings.TransferDetail import org.mifospay.core.network.ApiEndPoints -import retrofit2.http.GET -import retrofit2.http.Path -import rx.Observable /** * Created by ankur on 05/June/2018 */ interface AccountTransfersService { @GET(ApiEndPoints.ACCOUNT_TRANSFER + "/{transferId}") - fun getAccountTransfer(@Path("transferId") transferId: Long): Observable + fun getAccountTransfer(@Path("transferId") transferId: Long): Flow } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt similarity index 69% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt index c4706dc3c..61daeae86 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt @@ -9,14 +9,14 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.domain.user.User -import com.mifospay.core.model.entity.authentication.AuthenticationPayload +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.POST +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.entity.authentication.AuthenticationPayload import org.mifospay.core.network.ApiEndPoints -import retrofit2.http.Body -import retrofit2.http.POST -import rx.Observable interface AuthenticationService { @POST(ApiEndPoints.AUTHENTICATION) - fun authenticate(@Body authPayload: AuthenticationPayload): Observable + fun authenticate(@Body authPayload: AuthenticationPayload): Flow } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt similarity index 50% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt index 198e3bcd4..f3baaabcf 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt @@ -9,39 +9,36 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.entity.beneficary.Beneficiary +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.entity.beneficary.Beneficiary import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload -import com.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload -import com.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate -import okhttp3.ResponseBody +import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload +import org.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate import org.mifospay.core.network.ApiEndPoints -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path -import rx.Observable +import org.mifospay.core.network.model.CommonResponse -/** - * Created by dilpreet on 14/6/17. - */ interface BeneficiaryService { - @get:GET(ApiEndPoints.BENEFICIARIES + "/tpt") - val beneficiaryList: Observable> + @GET(ApiEndPoints.BENEFICIARIES + "/tpt") + fun beneficiaryList(): Flow> - @get:GET(ApiEndPoints.BENEFICIARIES + "/tpt/template") - val beneficiaryTemplate: Observable + @GET(ApiEndPoints.BENEFICIARIES + "/tpt/template") + fun beneficiaryTemplate(): Flow @POST(ApiEndPoints.BENEFICIARIES + "/tpt") - fun createBeneficiary(@Body beneficiaryPayload: org.mifospay.core.model.entity.beneficary.BeneficiaryPayload): Observable + fun createBeneficiary(@Body beneficiaryPayload: BeneficiaryPayload): Flow @PUT(ApiEndPoints.BENEFICIARIES + "/tpt/{beneficiaryId}") fun updateBeneficiary( @Path("beneficiaryId") beneficiaryId: Long, @Body payload: BeneficiaryUpdatePayload, - ): Observable + ): Flow @DELETE(ApiEndPoints.BENEFICIARIES + "/tpt/{beneficiaryId}") - fun deleteBeneficiary(@Path("beneficiaryId") beneficiaryId: Long): Observable + fun deleteBeneficiary(@Path("beneficiaryId") beneficiaryId: Long): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt new file mode 100644 index 000000000..fc8dee419 --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.services + +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Headers +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.domain.client.NewClient +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.client.ClientAccounts +import org.mifospay.core.model.entity.client.ClientEntity +import org.mifospay.core.network.ApiEndPoints + +interface ClientService { + @GET(ApiEndPoints.CLIENTS) + fun clients(): Flow> + + @GET(ApiEndPoints.CLIENTS + "/{clientId}") + fun getClientForId(@Path("clientId") clientId: Long): Flow + + @PUT(ApiEndPoints.CLIENTS + "/{clientId}") + fun updateClient( + @Path("clientId") clientId: Long, + @Body payload: Any, + ): Flow + + @GET(ApiEndPoints.CLIENTS + "/{clientId}/images") + @Headers("Accept: text/plain") + fun getClientImage(@Path("clientId") clientId: Long): Flow + + @PUT(ApiEndPoints.CLIENTS + "/{clientId}/images") + fun updateClientImage( + @Path("clientId") clientId: Long, + @Body typedFile: String?, + ): Flow + + @GET(ApiEndPoints.CLIENTS + "/{clientId}/accounts") + fun getClientAccounts(@Path("clientId") clientId: Long): Flow + + @GET(ApiEndPoints.CLIENTS + "/{clientId}/accounts") + fun getAccounts( + @Path("clientId") clientId: Long, + @Query("fields") accountType: String, + ): Flow + + @POST(ApiEndPoints.CLIENTS) + fun createClient(@Body newClient: NewClient): Flow +} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/DocumentService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt similarity index 82% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/DocumentService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt index f02c64ed9..43df8a93b 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/DocumentService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt @@ -9,29 +9,24 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.entity.noncore.Document -import okhttp3.MultipartBody -import okhttp3.ResponseBody +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Multipart +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Part +import de.jensklingenberg.ktorfit.http.Path +import io.ktor.http.content.PartData +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.entity.noncore.Document import org.mifospay.core.network.ApiEndPoints -import org.mifospay.core.network.GenericResponse -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.Multipart -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Part -import retrofit2.http.Path -import rx.Observable -/** - * @author fomenkoo - */ interface DocumentService { @GET("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS) fun getDocuments( - @Path("entityType") entityType: String?, + @Path("entityType") entityType: String, @Path("entityId") entityId: Int, - ): Observable> + ): Flow> /** * @param entityType - Type for which document is being uploaded (Client, Loan @@ -45,11 +40,11 @@ interface DocumentService { @Multipart fun createDocument( @Path("entityType") entityType: String, - @Path("entityId") entityId: Long, + @Path("entityId") entityId: Int, @Part("name") nameOfDocument: String, @Part("description") description: String, - @Part typedFile: MultipartBody.Part, - ): Observable + @Part typedFile: PartData, + ): Flow /** * This Service is for downloading the Document with EntityType and EntityId and Document Id @@ -68,7 +63,7 @@ interface DocumentService { @Path("entityType") entityType: String, @Path("entityId") entityId: Int, @Path("documentId") documentId: Int, - ): Observable + ): Flow /** * This Service is for Deleting the Document with EntityType and EntityId and Document Id. @@ -86,7 +81,7 @@ interface DocumentService { @Path("entityType") entityType: String, @Path("entityId") entityId: Int, @Path("documentId") documentId: Int, - ): Observable + ): Flow /** * This Service for Updating the Document with EntityType and EntityId and Document Id. @@ -111,6 +106,6 @@ interface DocumentService { @Path("documentId") documentId: Int, @Part("name") nameOfDocument: String, @Part("description") description: String, - @Part typedFile: MultipartBody.Part, - ): Observable + @Part typedFile: PartData, + ): Flow } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt similarity index 52% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt index 2a29470c0..7052adb17 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt @@ -9,46 +9,44 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.entity.Invoice +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.entity.Invoice import org.mifospay.core.network.ApiEndPoints -import org.mifospay.core.network.GenericResponse -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path -import rx.Observable +import org.mifospay.core.network.model.GenericResponse -/** - * Created by ankur on 07/June/2018 - */ +// TODO:: Fix this endpoints, there's no such endpoint for invoices interface InvoiceService { - @POST(ApiEndPoints.DATATABLES + "/invoices/{clientId}") - fun addInvoice( - @Path("clientId") clientId: String, - @Body invoice: Invoice?, - ): Observable - @GET(ApiEndPoints.DATATABLES + "/invoices/{clientId}") - fun getInvoices(@Path("clientId") clientId: String): Observable> + fun getInvoices(@Path("clientId") clientId: Int): Flow> @GET(ApiEndPoints.DATATABLES + "/invoices/{clientId}/{invoiceId}") fun getInvoice( - @Path("clientId") clientId: String, - @Path("invoiceId") invoiceId: String, - ): Observable> - - @DELETE(ApiEndPoints.DATATABLES + "/invoices/{clientId}/{invoiceId}") - fun deleteInvoice( - @Path("clientId") clientId: String, + @Path("clientId") clientId: Int, @Path("invoiceId") invoiceId: Int, - ): Observable + ): Flow + + @POST(ApiEndPoints.DATATABLES + "/invoices/{clientId}") + fun addInvoice( + @Path("clientId") clientId: Int, + @Body invoice: Invoice?, + ): Unit @PUT(ApiEndPoints.DATATABLES + "/invoices/{clientId}/{invoiceId}") fun updateInvoice( - @Path("clientId") clientId: String, - @Path("invoiceId") invoiceId: Long, + @Path("clientId") clientId: Int, + @Path("invoiceId") invoiceId: Int, @Body invoice: Invoice?, - ): Observable + ): Flow + + @DELETE(ApiEndPoints.DATATABLES + "/invoices/{clientId}/{invoiceId}") + fun deleteInvoice( + @Path("clientId") clientId: Int, + @Path("invoiceId") invoiceId: Int, + ): Flow } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt similarity index 64% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt index 1066b8e7e..07e63bcb4 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt @@ -9,29 +9,30 @@ */ package org.mifospay.core.network.services +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.mifospay.core.network.ApiEndPoints -import org.mifospay.core.network.GenericResponse -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path -import rx.Observable +import org.mifospay.core.network.model.GenericResponse interface KYCLevel1Service { + + @GET(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}") + fun fetchKYCLevel1Details(@Path("clientId") clientId: Int): Flow> + @POST(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}") fun addKYCLevel1Details( @Path("clientId") clientId: Int, - @Body kycLevel1Details: org.mifospay.core.model.entity.kyc.KYCLevel1Details, - ): Observable - - @GET(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}") - fun fetchKYCLevel1Details(@Path("clientId") clientId: Int): Observable> + @Body kycLevel1Details: KYCLevel1Details, + ): Flow @PUT(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}/") fun updateKYCLevel1Details( @Path("clientId") clientId: Int, - @Body kycLevel1Details: org.mifospay.core.model.entity.kyc.KYCLevel1Details, - ): Observable + @Body kycLevel1Details: KYCLevel1Details, + ): Flow } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/NotificationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt similarity index 64% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/NotificationService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt index 69528821d..33c1dc603 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/NotificationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt @@ -9,16 +9,13 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.domain.NotificationPayload +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Path +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.domain.NotificationPayload import org.mifospay.core.network.ApiEndPoints -import retrofit2.http.GET -import retrofit2.http.Path -import rx.Observable -/** - * Created by ankur on 24/July/2018 - */ interface NotificationService { @GET(ApiEndPoints.DATATABLES + "/notifications/{clientId}") - fun fetchNotifications(@Path("clientId") clientId: Long): Observable> + fun fetchNotifications(@Path("clientId") clientId: Long): Flow> } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt similarity index 57% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt index fa05bc240..d93401cf6 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt @@ -9,18 +9,16 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.entity.register.RegisterPayload -import com.mifospay.core.model.entity.register.UserVerify -import okhttp3.ResponseBody +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.POST +import org.mifospay.core.model.entity.register.RegisterPayload +import org.mifospay.core.model.entity.register.UserVerify import org.mifospay.core.network.ApiEndPoints -import retrofit2.http.Body -import retrofit2.http.POST -import rx.Observable interface RegistrationService { @POST(ApiEndPoints.REGISTRATION) - fun registerUser(@Body registerPayload: RegisterPayload): Observable + fun registerUser(@Body registerPayload: RegisterPayload) @POST(ApiEndPoints.REGISTRATION + "/user") - fun verifyUser(@Body userVerify: UserVerify): Observable + fun verifyUser(@Body userVerify: UserVerify) } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/RunReportService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt similarity index 67% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/RunReportService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt index 68c9d6d6e..c502d067f 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/RunReportService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt @@ -9,20 +9,16 @@ */ package org.mifospay.core.network.services -import okhttp3.ResponseBody +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Query +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity import org.mifospay.core.network.ApiEndPoints -import retrofit2.http.GET -import retrofit2.http.Query -import rx.Observable -/** - * Created by ankur on 06/June/2018 - */ -@Suppress("FunctionParameterNaming") interface RunReportService { @GET(ApiEndPoints.RUN_REPORT + "/Savings Transaction Receipt") fun getTransactionReceipt( @Query("output-type") outputType: String, - @Query("R_transactionId") R_transactionId: String, - ): Observable + @Query("R_transactionId") transactionId: String, + ): Flow } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt similarity index 64% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt index 916554e7c..dcf5e4a60 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt @@ -9,40 +9,37 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.entity.savedcards.Card +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.entity.savedcards.Card import org.mifospay.core.network.ApiEndPoints -import org.mifospay.core.network.GenericResponse -import retrofit2.http.Body -import retrofit2.http.DELETE -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path -import rx.Observable +import org.mifospay.core.network.model.GenericResponse -/** - * Created by ankur on 21/May/2018 - */ interface SavedCardService { @POST(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}") fun addSavedCard( @Path("clientId") clientId: Int, @Body card: Card, - ): Observable + ): Flow @GET(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}") - fun getSavedCards(@Path("clientId") clientId: Int): Observable> + fun getSavedCards(@Path("clientId") clientId: Int): Flow> @DELETE(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}/{cardId}") fun deleteCard( @Path("clientId") clientId: Int, @Path("cardId") cardId: Int, - ): Observable + ): Flow @PUT(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}/{cardId}") fun updateCard( @Path("clientId") clientId: Int, @Path("cardId") cardId: Int, @Body card: Card, - ): Observable + ): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt new file mode 100644 index 000000000..7927c84cd --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.services + +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.accounts.savings.SavingAccount +import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity +import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity +import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.model.GenericResponse + +interface SavingsAccountsService { + @GET(ApiEndPoints.SAVINGS_ACCOUNTS + "/{accountId}") + suspend fun getSavingsWithAssociations( + @Path("accountId") accountId: Long, + @Query("associations") associationType: String, + ): Flow + + @GET(ApiEndPoints.SAVINGS_ACCOUNTS) + suspend fun getSavingsAccounts( + @Query("limit") limit: Int, + ): Flow> + + @POST(ApiEndPoints.SAVINGS_ACCOUNTS) + suspend fun createSavingsAccount(@Body savingAccount: SavingAccount): Flow + + @POST(ApiEndPoints.SAVINGS_ACCOUNTS + "/{accountId}") + suspend fun blockUnblockAccount( + @Path("accountId") accountId: Long, + @Query("command") command: String?, + ): Flow + + @GET( + ApiEndPoints.SAVINGS_ACCOUNTS + "/{accountId}/" + ApiEndPoints.TRANSACTIONS + + "/{transactionId}", + ) + suspend fun getSavingAccountTransaction( + @Path("accountId") accountId: Long, + @Path("transactionId") transactionId: Long, + ): Flow + + @POST( + ApiEndPoints.SAVINGS_ACCOUNTS + + "/{accountId}/" + ApiEndPoints.TRANSACTIONS + "?command=deposit", + ) + suspend fun payViaMobile(@Path("accountId") accountId: Long): Flow +} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SearchService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt similarity index 71% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SearchService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt index a11f281e0..c80edd09c 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/SearchService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt @@ -9,17 +9,17 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.entity.SearchedEntity +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.Query +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.entity.SearchedEntity import org.mifospay.core.network.ApiEndPoints -import retrofit2.http.GET -import retrofit2.http.Query -import rx.Observable interface SearchService { @GET(ApiEndPoints.SEARCH) - fun searchResources( + suspend fun searchResources( @Query("query") query: String, @Query("resource") resources: String, @Query("exactMatch") exactMatch: Boolean, - ): Observable> + ): Flow> } diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt similarity index 72% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt index 13426e54a..2fbd5cbe7 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt @@ -9,19 +9,19 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.entity.Page -import com.mifospay.core.model.entity.payload.StandingInstructionPayload -import com.mifospay.core.model.entity.standinginstruction.SDIResponse -import com.mifospay.core.model.entity.standinginstruction.StandingInstruction +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import de.jensklingenberg.ktorfit.http.Query +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.entity.Page +import org.mifospay.core.model.entity.payload.StandingInstructionPayload +import org.mifospay.core.model.entity.standinginstruction.SDIResponse +import org.mifospay.core.model.entity.standinginstruction.StandingInstruction import org.mifospay.core.network.ApiEndPoints -import org.mifospay.core.network.GenericResponse -import retrofit2.http.Body -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.PUT -import retrofit2.http.Path -import retrofit2.http.Query -import rx.Observable +import org.mifospay.core.network.model.GenericResponse interface StandingInstructionService { @@ -29,7 +29,7 @@ interface StandingInstructionService { fun createStandingInstruction( @Body standingInstructionPayload: StandingInstructionPayload, - ): Observable + ): Flow /** * @param clientId - passed as Query to limit the response to client specific response @@ -37,13 +37,13 @@ interface StandingInstructionService { @GET(ApiEndPoints.STANDING_INSTRUCTION) fun getAllStandingInstructions( @Query("clientId") clientId: Long, - ): Observable> + ): Flow> @GET("${ApiEndPoints.STANDING_INSTRUCTION}/{standingInstructionId}") fun getStandingInstruction( @Path("standingInstructionId") standingInstructionId: Long, - ): Observable + ): Flow /** * @param command - if command is passed as "update" then the corresponding standing instruction @@ -56,12 +56,12 @@ interface StandingInstructionService { fun deleteStandingInstruction( @Path("standingInstructionId") standingInstructionId: Long, @Query("command") command: String, - ): Observable + ): Flow @PUT("${ApiEndPoints.STANDING_INSTRUCTION}/{standingInstructionId}") fun updateStandingInstruction( @Path("standingInstructionId") standingInstructionId: Long, @Body standingInstructionPayload: StandingInstructionPayload, @Query("command") command: String, - ): Observable + ): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt new file mode 100644 index 000000000..601234d2d --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.services + +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.entity.TPTResponse +import org.mifospay.core.model.entity.payload.TransferPayload +import org.mifospay.core.model.entity.templates.account.AccountOptionsTemplate +import org.mifospay.core.network.ApiEndPoints + +interface ThirdPartyTransferService { + @GET(ApiEndPoints.ACCOUNT_TRANSFER + "/template?type=tpt") + fun accountTransferTemplate(): Flow + + @POST(ApiEndPoints.ACCOUNT_TRANSFER + "?type=tpt") + fun makeTransfer(@Body transferPayload: TransferPayload): Flow +} diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt similarity index 59% rename from core/network/src/androidMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt index 968c5a6b9..c3defdb53 100644 --- a/core/network/src/androidMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt @@ -9,24 +9,21 @@ */ package org.mifospay.core.network.services -import com.mifospay.core.model.domain.twofactor.AccessToken +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.Query +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.domain.twofactor.AccessToken import org.mifospay.core.model.domain.twofactor.DeliveryMethod import org.mifospay.core.network.ApiEndPoints -import retrofit2.http.GET -import retrofit2.http.POST -import retrofit2.http.Query -import rx.Observable -/** - * Created by ankur on 01/June/2018 - */ interface TwoFactorAuthService { - @get:GET(ApiEndPoints.TWOFACTOR) - val deliveryMethods: Observable> + @GET(ApiEndPoints.TWOFACTOR) + fun deliveryMethods(): Flow> @POST(ApiEndPoints.TWOFACTOR) - fun requestOTP(@Query("deliveryMethod") deliveryMethod: String): Observable + fun requestOTP(@Query("deliveryMethod") deliveryMethod: String): Flow @POST(ApiEndPoints.TWOFACTOR + "/validate") - fun validateToken(@Query("token") token: String): Observable + fun validateToken(@Query("token") token: String): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt new file mode 100644 index 000000000..2a6c585f7 --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.services + +import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE +import de.jensklingenberg.ktorfit.http.GET +import de.jensklingenberg.ktorfit.http.POST +import de.jensklingenberg.ktorfit.http.PUT +import de.jensklingenberg.ktorfit.http.Path +import kotlinx.coroutines.flow.Flow +import org.mifospay.core.model.domain.user.NewUser +import org.mifospay.core.model.entity.UserWithRole +import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.model.CommonResponse +import org.mifospay.core.network.model.GenericResponse + +interface UserService { + @GET(ApiEndPoints.USER) + fun users(): Flow> + + @POST(ApiEndPoints.USER) + fun createUser(@Body user: NewUser): Flow + + @PUT(ApiEndPoints.USER + "/{userId}") + fun updateUser( + @Path("userId") userId: Int, + @Body updateUserEntity: NewUser, + ): Flow + + @DELETE(ApiEndPoints.USER + "/{userId}") + fun deleteUser( + @Path("userId") userId: Int, + ): Flow + + @GET("self/userdetails") + fun getUser(): Flow +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1f7d9e375..582e711b8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -30,7 +30,7 @@ datastore = "1.1.1" dependencyGuard = "0.5.0" detekt = "1.23.7" espresso-core = "3.6.1" -fineractSdk = "1.06" +fineractSdk = "1.0.3" firebaseBom = "33.3.0" firebaseCrashlyticsPlugin = "3.0.2" firebasePerfPlugin = "1.4.2" @@ -188,6 +188,8 @@ kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx- ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } ktlint-gradlePlugin = { group = "org.jlleitschuh.gradle", name = "ktlint-gradle", version.ref = "ktlint" } ktor-client-android = { group = "io.ktor", name = "ktor-client-android", version.ref = "ktorVersion" } +ktor-client-auth = { group = "io.ktor", name = "ktor-client-auth", version.ref = "ktorVersion" } +ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktorVersion" } ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktorVersion" } ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktorVersion" } ktor-client-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktorVersion" } @@ -231,6 +233,7 @@ squareup-retrofit2 = { group = "com.squareup.retrofit2", name = "retrofit", vers truth = { group = "com.google.truth", name = "truth", version.ref = "truth" } twitter-detekt-compose = { group = "com.twitter.compose.rules", name = "detekt", version.ref = "twitter-detekt-compose" } zxing = { group = "com.google.zxing", name = "core", version.ref = "zxingVersion" } +fineract-api = { group = "io.github.niyajali", name = "fineract-client-kmp", version.ref = "fineractSdk" } [bundles] androidx-compose-ui-test = [ @@ -276,6 +279,7 @@ mifospay-cmp-feature = { id = "mifospay.cmp.feature", version = "unspecified" } mifospay-jvm-library = { id = "mifospay.jvm.library", version = "unspecified" } mifospay-kmp-koin = { id = "mifospay.kmp.koin", version = "unspecified" } mifospay-kmp-library = { id = "mifospay.kmp.library", version = "unspecified" } +mifospay-kotlin-inject = { id = "mifospay.kmp.inject", version = "unspecified" } module-graph = { id = "com.jraska.module.graph.assertion", version.ref = "moduleGraph" } protobuf = { id = "com.google.protobuf", version.ref = "protobufPlugin" } roborazzi = { id = "io.github.takahirom.roborazzi", version.ref = "roborazzi" } diff --git a/settings.gradle.kts b/settings.gradle.kts index 9cb771d36..f43a17c79 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -17,7 +17,7 @@ dependencyResolutionManagement { } } - plugins { +plugins { id("org.gradle.toolchains.foojay-resolver-convention") version("0.8.0") id("org.ajoberstar.reckon.settings") version("0.18.3") } From d5b7c52e65167959158db5c5545cebe8002f2703 Mon Sep 17 00:00:00 2001 From: Sk Niyaj Ali Date: Mon, 30 Sep 2024 13:43:13 +0530 Subject: [PATCH 06/31] Feat: [:core:designsystem] - Migrated to KMP with CMP Library (#1774) --- core/designsystem/build.gradle.kts | 9 +++ .../{main => androidMain}/AndroidManifest.xml | 0 .../designsystem/component/PermissionBox.kt | 9 +-- .../designsystem/component/AlertDialog.kt | 19 +++--- .../core/designsystem/component/Background.kt | 58 ++----------------- .../designsystem/component/BottomSheet.kt | 19 +++--- .../core/designsystem/component/Button.kt | 0 .../core/designsystem/component/Card.kt | 0 .../designsystem/component/LoadingWheel.kt | 5 +- .../designsystem/component/MifosScaffold.kt | 2 +- .../core/designsystem/component/MifosTab.kt | 0 .../designsystem/component/MifosTopBar.kt | 7 +-- .../core/designsystem/component/Navigation.kt | 0 .../component/OutlineTextField.kt | 31 ++++------ .../core/designsystem/component/TextField.kt | 47 +++++---------- .../designsystem/component/TextUserImage.kt | 3 +- .../core/designsystem/component/TopAppBar.kt | 18 ++---- .../core/designsystem/icon/MifosIcons.kt | 0 .../designsystem/theme/BackgroundTheme.kt | 0 .../mifospay/core/designsystem/theme/Color.kt | 0 .../core/designsystem/theme/GradientColors.kt | 0 .../core/designsystem/theme/MifosTextStyle.kt | 0 .../mifospay/core/designsystem/theme/Theme.kt | 0 .../core/designsystem/theme/TintTheme.kt | 0 .../mifospay/core/designsystem/theme/Type.kt | 0 .../designsystem/utils/ExpirationDateMask.kt | 0 .../commonMain/resources/values/values.xml | 0 gradle/libs.versions.toml | 5 ++ 28 files changed, 83 insertions(+), 149 deletions(-) rename core/designsystem/src/{main => androidMain}/AndroidManifest.xml (100%) rename core/designsystem/src/{main => androidMain}/kotlin/org/mifospay/core/designsystem/component/PermissionBox.kt (97%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/AlertDialog.kt (80%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/Background.kt (60%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/BottomSheet.kt (87%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/Button.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/Card.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt (99%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt (98%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/MifosTab.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt (93%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/Navigation.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/OutlineTextField.kt (73%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/TextField.kt (85%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/TextUserImage.kt (97%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt (88%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/icon/MifosIcons.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/theme/BackgroundTheme.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/theme/Color.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/theme/GradientColors.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/theme/MifosTextStyle.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/theme/Theme.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/theme/TintTheme.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/theme/Type.kt (100%) rename core/designsystem/src/{main => commonMain}/kotlin/org/mifospay/core/designsystem/utils/ExpirationDateMask.kt (100%) create mode 100644 core/designsystem/src/commonMain/resources/values/values.xml diff --git a/core/designsystem/build.gradle.kts b/core/designsystem/build.gradle.kts index d776a2ebe..c361c81d8 100644 --- a/core/designsystem/build.gradle.kts +++ b/core/designsystem/build.gradle.kts @@ -74,10 +74,19 @@ kotlin { implementation(compose.uiUtil) implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) + implementation(libs.back.handler) + implementation(libs.moko.permission) + implementation(libs.moko.permission.compose) } } } +compose.resources { + publicResClass = true + packageOfResClass = "org.mifospay.core.designsystem.resources" + generateResClass = always +} + dependencies { lintPublish(projects.lint) } \ No newline at end of file diff --git a/core/designsystem/src/main/AndroidManifest.xml b/core/designsystem/src/androidMain/AndroidManifest.xml similarity index 100% rename from core/designsystem/src/main/AndroidManifest.xml rename to core/designsystem/src/androidMain/AndroidManifest.xml diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/PermissionBox.kt b/core/designsystem/src/androidMain/kotlin/org/mifospay/core/designsystem/component/PermissionBox.kt similarity index 97% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/PermissionBox.kt rename to core/designsystem/src/androidMain/kotlin/org/mifospay/core/designsystem/component/PermissionBox.kt index afff02d09..023fcca45 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/PermissionBox.kt +++ b/core/designsystem/src/androidMain/kotlin/org/mifospay/core/designsystem/component/PermissionBox.kt @@ -30,15 +30,16 @@ import androidx.core.content.ContextCompat import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleEventObserver +// TODO:: Support for compose multiplatform @Suppress("LongMethod", "CyclomaticComplexMethod") @Composable fun PermissionBox( + title: String, + confirmButtonText: String, + dismissButtonText: String, requiredPermissions: List, - title: Int, - confirmButtonText: Int, - dismissButtonText: Int, modifier: Modifier = Modifier, - description: Int? = null, + description: String? = null, onGranted: @Composable (() -> Unit)? = null, ) { val context = LocalContext.current diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/AlertDialog.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/AlertDialog.kt similarity index 80% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/AlertDialog.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/AlertDialog.kt index 76268649d..8a0115a0f 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/AlertDialog.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/AlertDialog.kt @@ -16,27 +16,26 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource @Composable fun MifosDialogBox( + title: String, showDialogState: Boolean, - onDismiss: () -> Unit, - title: Int, - confirmButtonText: Int, + confirmButtonText: String, + dismissButtonText: String, onConfirm: () -> Unit, - dismissButtonText: Int, + onDismiss: () -> Unit, modifier: Modifier = Modifier, - message: Int? = null, + message: String? = null, ) { if (showDialogState) { AlertDialog( modifier = modifier, onDismissRequest = onDismiss, - title = { Text(text = stringResource(id = title)) }, + title = { Text(text = title) }, text = { if (message != null) { - Text(text = stringResource(id = message)) + Text(text = message) } }, confirmButton = { @@ -45,12 +44,12 @@ fun MifosDialogBox( onConfirm() }, ) { - Text(stringResource(id = confirmButtonText)) + Text(text = confirmButtonText) } }, dismissButton = { TextButton(onClick = onDismiss) { - Text(stringResource(id = dismissButtonText)) + Text(text = dismissButtonText) } }, ) diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/Background.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Background.kt similarity index 60% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/Background.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Background.kt index a4fb548ca..012f0c038 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/Background.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Background.kt @@ -9,7 +9,6 @@ */ package org.mifospay.core.designsystem.component -import android.content.res.Configuration import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size @@ -17,21 +16,15 @@ import androidx.compose.material3.LocalAbsoluteTonalElevation import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.getValue -import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.drawWithCache -import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview import org.mifospay.core.designsystem.theme.GradientColors import org.mifospay.core.designsystem.theme.LocalBackgroundTheme import org.mifospay.core.designsystem.theme.LocalGradientColors import org.mifospay.core.designsystem.theme.MifosTheme -import kotlin.math.tan /** * The main background for the app. @@ -66,14 +59,13 @@ fun MifosBackground( * @param gradientColors The gradient colors to be rendered. * @param content The background content. */ +// TODO:: Fix the gradient background based on NewUI @Composable fun MifosGradientBackground( modifier: Modifier = Modifier, gradientColors: GradientColors = LocalGradientColors.current, content: @Composable () -> Unit, ) { - val currentTopColor by rememberUpdatedState(gradientColors.top) - val currentBottomColor by rememberUpdatedState(gradientColors.bottom) Surface( color = if (gradientColors.container == Color.Unspecified) { Color.Transparent @@ -84,48 +76,7 @@ fun MifosGradientBackground( ) { Box( Modifier - .fillMaxSize() - .drawWithCache { - // Compute the start and end coordinates such that the gradients are angled 11.06 - // degrees off the vertical axis - val offset = size.height * tan( - Math - .toRadians(11.06) - .toFloat(), - ) - - val start = Offset(size.width / 2 + offset / 2, 0f) - val end = Offset(size.width / 2 - offset / 2, size.height) - - // Create the top gradient that fades out after the halfway point vertically - val topGradient = Brush.linearGradient( - 0f to if (currentTopColor == Color.Unspecified) { - Color.Transparent - } else { - currentTopColor - }, - 0.724f to Color.Transparent, - start = start, - end = end, - ) - // Create the bottom gradient that fades in before the halfway point vertically - val bottomGradient = Brush.linearGradient( - 0.2552f to Color.Transparent, - 1f to if (currentBottomColor == Color.Unspecified) { - Color.Transparent - } else { - currentBottomColor - }, - start = start, - end = end, - ) - - onDrawBehind { - // There is overlap here, so order is important - drawRect(topGradient) - drawRect(bottomGradient) - } - }, + .fillMaxSize(), ) { content() } @@ -136,8 +87,7 @@ fun MifosGradientBackground( * Multipreview annotation that represents light and dark themes. Add this annotation to a * composable to render the both themes. */ -@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Light theme") -@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Dark theme") +@Preview annotation class ThemePreviews @ThemePreviews diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/BottomSheet.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/BottomSheet.kt similarity index 87% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/BottomSheet.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/BottomSheet.kt index 7270d4b22..c1bc5bf8f 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/BottomSheet.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/BottomSheet.kt @@ -9,7 +9,6 @@ */ package org.mifospay.core.designsystem.component -import androidx.activity.compose.BackHandler import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.height @@ -24,9 +23,10 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.arkivanov.essenty.backhandler.BackCallback import kotlinx.coroutines.launch +import org.jetbrains.compose.ui.tooling.preview.Preview @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -48,7 +48,7 @@ fun MifosBottomSheet( onDismiss.invoke() } - BackHandler(modalSheetState.isVisible) { + BackCallback(modalSheetState.isVisible) { dismissSheet() } @@ -70,9 +70,12 @@ fun MifosBottomSheet( @Preview @Composable fun MifosBottomSheetPreview() { - MifosBottomSheet({ - Box { - Modifier.height(100.dp) - } - }, {}) + MifosBottomSheet( + content = { + Box { + Modifier.height(100.dp) + } + }, + onDismiss = {}, + ) } diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/Button.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Button.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/Button.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Button.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/Card.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Card.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/Card.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Card.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt similarity index 99% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt index db89435de..89853c26c 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt @@ -46,7 +46,6 @@ import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.platform.testTag import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch import org.mifospay.core.designsystem.theme.MifosTheme @@ -189,7 +188,7 @@ fun MfLoadingWheel( } } -@Preview +@ThemePreviews @Composable fun MifosLoadingWheelPreview() { MifosTheme { @@ -199,7 +198,7 @@ fun MifosLoadingWheelPreview() { } } -@Preview +@ThemePreviews @Composable fun NiaOverlayLoadingWheelPreview() { MifosTheme { diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt similarity index 98% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt index bdcb53837..6c62f4028 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt @@ -21,7 +21,7 @@ import androidx.compose.ui.graphics.Color fun MifosScaffold( backPress: () -> Unit, modifier: Modifier = Modifier, - topBarTitle: Int? = null, + topBarTitle: String? = null, floatingActionButtonContent: FloatingActionButtonContent? = null, snackbarHost: @Composable () -> Unit = {}, scaffoldContent: @Composable (PaddingValues) -> Unit = {}, diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/MifosTab.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTab.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/MifosTab.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTab.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt similarity index 93% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt index 63fa5ea20..a03847ea5 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt @@ -19,13 +19,12 @@ import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import org.mifospay.core.designsystem.icon.MifosIcons @OptIn(ExperimentalMaterial3Api::class) @Composable fun MifosTopBar( - topBarTitle: Int, + topBarTitle: String, backPress: () -> Unit, modifier: Modifier = Modifier, actions: @Composable RowScope.() -> Unit = {}, @@ -33,7 +32,7 @@ fun MifosTopBar( TopAppBar( title = { Text( - text = stringResource(id = topBarTitle), + text = topBarTitle, style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onSurface, ) @@ -54,4 +53,4 @@ fun MifosTopBar( actions = actions, modifier = modifier, ) -} +} \ No newline at end of file diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/Navigation.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Navigation.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/Navigation.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Navigation.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/OutlineTextField.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/OutlineTextField.kt similarity index 73% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/OutlineTextField.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/OutlineTextField.kt index 360cc1484..e5e1313f4 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/OutlineTextField.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/OutlineTextField.kt @@ -9,18 +9,16 @@ */ package org.mifospay.core.designsystem.component -import androidx.compose.foundation.Image import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextFieldDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.VisualTransformation @@ -28,13 +26,13 @@ import androidx.compose.ui.unit.sp @Composable fun MifosOutlinedTextField( - label: Int, + label: String, value: String, onValueChange: (String) -> Unit, modifier: Modifier = Modifier, maxLines: Int = 1, singleLine: Boolean = true, - icon: Int? = null, + icon: ImageVector? = null, error: Boolean = false, visualTransformation: VisualTransformation = VisualTransformation.None, trailingIcon: @Composable (() -> Unit)? = null, @@ -43,18 +41,13 @@ fun MifosOutlinedTextField( OutlinedTextField( value = value, onValueChange = onValueChange, - label = { Text(stringResource(id = label)) }, + label = { Text(label) }, modifier = modifier, - leadingIcon = - if (icon != null) { + leadingIcon = if (icon != null) { { - Image( - painter = painterResource(id = icon), - contentDescription = null, - colorFilter = - ColorFilter.tint( - MaterialTheme.colorScheme.onSurface, - ), + Icon( + imageVector = icon, + contentDescription = icon.name, ) } } else { @@ -63,13 +56,11 @@ fun MifosOutlinedTextField( trailingIcon = trailingIcon, maxLines = maxLines, singleLine = singleLine, - colors = - OutlinedTextFieldDefaults.colors( + colors = OutlinedTextFieldDefaults.colors( focusedBorderColor = MaterialTheme.colorScheme.onSurface, focusedLabelColor = MaterialTheme.colorScheme.onSurface, ), - textStyle = - LocalDensity.current.run { + textStyle = LocalDensity.current.run { TextStyle(fontSize = 18.sp, color = MaterialTheme.colorScheme.onSurface) }, keyboardOptions = keyboardOptions, diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/TextField.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TextField.kt similarity index 85% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/TextField.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TextField.kt index 096c206da..a98e8e8ab 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/TextField.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TextField.kt @@ -9,7 +9,6 @@ */ package org.mifospay.core.designsystem.component -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth @@ -27,16 +26,13 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.ColorFilter +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalDensity -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.ImeAction 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.sp import org.mifospay.core.designsystem.theme.MifosTheme @@ -65,18 +61,15 @@ fun MfOutlinedTextField( }, singleLine = singleLine, trailingIcon = trailingIcon, - keyboardActions = - KeyboardActions { + keyboardActions = KeyboardActions { onKeyboardActions?.invoke() }, keyboardOptions = keyboardOptions, - colors = - OutlinedTextFieldDefaults.colors( + colors = OutlinedTextFieldDefaults.colors( focusedBorderColor = MaterialTheme.colorScheme.onSurface, focusedLabelColor = MaterialTheme.colorScheme.onSurface, ), - textStyle = - LocalDensity.current.run { + textStyle = LocalDensity.current.run { TextStyle(fontSize = 18.sp, color = MaterialTheme.colorScheme.onSurface) }, ) @@ -99,8 +92,7 @@ fun MfPasswordTextField( onValueChange = onPasswordChange, label = { Text(label) }, isError = isError, - visualTransformation = - if (isPasswordVisible) { + visualTransformation = if (isPasswordVisible) { VisualTransformation.None } else { PasswordVisualTransformation() @@ -121,13 +113,13 @@ fun MfPasswordTextField( @Composable fun MifosOutlinedTextField( - label: Int, + label: String, value: TextFieldValue, onValueChange: (TextFieldValue) -> Unit, modifier: Modifier = Modifier, maxLines: Int = 1, singleLine: Boolean = true, - icon: Int? = null, + icon: ImageVector? = null, visualTransformation: VisualTransformation = VisualTransformation.None, trailingIcon: @Composable (() -> Unit)? = null, keyboardActions: KeyboardActions = KeyboardActions.Default, @@ -136,18 +128,13 @@ fun MifosOutlinedTextField( OutlinedTextField( value = value, onValueChange = onValueChange, - label = { Text(stringResource(id = label)) }, + label = { Text(label) }, modifier = modifier, - leadingIcon = - if (icon != null) { + leadingIcon = if (icon != null) { { - Image( - painter = painterResource(id = icon), - contentDescription = null, - colorFilter = - ColorFilter.tint( - MaterialTheme.colorScheme.onSurface, - ), + Icon( + imageVector = icon, + contentDescription = icon.name, ) } } else { @@ -156,13 +143,11 @@ fun MifosOutlinedTextField( trailingIcon = trailingIcon, maxLines = maxLines, singleLine = singleLine, - colors = - OutlinedTextFieldDefaults.colors( + colors = OutlinedTextFieldDefaults.colors( focusedBorderColor = MaterialTheme.colorScheme.onSurface, focusedLabelColor = MaterialTheme.colorScheme.onSurface, ), - textStyle = - LocalDensity.current.run { + textStyle = LocalDensity.current.run { TextStyle(fontSize = 18.sp, color = MaterialTheme.colorScheme.onSurface) }, keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next), @@ -172,7 +157,7 @@ fun MifosOutlinedTextField( ) } -@Preview +@ThemePreviews @Composable fun MfOutlinedTextFieldPreview() { MifosTheme { @@ -192,7 +177,7 @@ fun MfOutlinedTextFieldPreview() { } } -@Preview +@ThemePreviews @Composable fun MfPasswordTextFieldPreview() { MifosTheme { diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/TextUserImage.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TextUserImage.kt similarity index 97% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/TextUserImage.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TextUserImage.kt index 6be7620d3..a607c6b6f 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/TextUserImage.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TextUserImage.kt @@ -30,8 +30,7 @@ fun MifosTextUserImage( size: Dp = 100.dp, ) { Box( - modifier = - modifier + modifier = modifier .size(size) .clip(CircleShape) .background(color = MaterialTheme.colorScheme.primary), diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt similarity index 88% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt index a2a25b3d3..14ba54e2b 100644 --- a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt @@ -11,7 +11,6 @@ package org.mifospay.core.designsystem.component -import androidx.annotation.StringRes import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon @@ -25,15 +24,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.MifosTheme @OptIn(ExperimentalMaterial3Api::class) @Composable fun MifosTopAppBar( - @StringRes titleRes: Int, + titleRes: String, modifier: Modifier = Modifier, navigationIcon: ImageVector? = null, navigationIconContentDescription: String? = null, @@ -44,7 +41,7 @@ fun MifosTopAppBar( onActionClick: (() -> Unit)? = null, ) { CenterAlignedTopAppBar( - title = { Text(text = stringResource(id = titleRes)) }, + title = { Text(text = titleRes) }, navigationIcon = { navigationIcon?.let { IconButton(onClick = onNavigationClick!!) { @@ -74,16 +71,13 @@ fun MifosTopAppBar( @Composable fun MifosNavigationTopAppBar( - @StringRes titleRes: Int, + titleRes: String, onNavigationClick: (() -> Unit)?, ) { MifosTopAppBar( titleRes = titleRes, navigationIcon = MifosIcons.Back, - navigationIconContentDescription = - stringResource( - id = titleRes, - ), + navigationIconContentDescription = titleRes, colors = TopAppBarDefaults.centerAlignedTopAppBarColors( containerColor = Color.Transparent, @@ -93,12 +87,12 @@ fun MifosNavigationTopAppBar( } @OptIn(ExperimentalMaterial3Api::class) -@Preview("Top App Bar") +@ThemePreviews @Composable private fun MifosTopAppBarPreview() { MifosTheme { MifosTopAppBar( - titleRes = android.R.string.untitled, + titleRes = "Demo Preview", navigationIcon = MifosIcons.Search, navigationIconContentDescription = "Navigation icon", actionIcon = MifosIcons.MoreVert, diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/icon/MifosIcons.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/icon/MifosIcons.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/icon/MifosIcons.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/icon/MifosIcons.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/BackgroundTheme.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/BackgroundTheme.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/BackgroundTheme.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/BackgroundTheme.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/Color.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Color.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/Color.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Color.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/GradientColors.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/GradientColors.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/GradientColors.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/GradientColors.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/MifosTextStyle.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/MifosTextStyle.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/MifosTextStyle.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/MifosTextStyle.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/Theme.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Theme.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/Theme.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Theme.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/TintTheme.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/TintTheme.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/TintTheme.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/TintTheme.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/Type.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Type.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/theme/Type.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Type.kt diff --git a/core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/utils/ExpirationDateMask.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/utils/ExpirationDateMask.kt similarity index 100% rename from core/designsystem/src/main/kotlin/org/mifospay/core/designsystem/utils/ExpirationDateMask.kt rename to core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/utils/ExpirationDateMask.kt diff --git a/core/designsystem/src/commonMain/resources/values/values.xml b/core/designsystem/src/commonMain/resources/values/values.xml new file mode 100644 index 000000000..e69de29bb diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 582e711b8..fa9c118ff 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -19,6 +19,7 @@ androidxNavigation = "2.8.1" androidxProfileinstaller = "1.4.0" androidxTracing = "1.3.0-alpha02" appcompatVersion = "1.7.0" +backHandlerVersion = "2.1.0" cameraLifecycleVersion = "1.3.4" cameraViewVersion = "1.3.4" coil = "3.0.0-alpha10" @@ -63,6 +64,7 @@ logbackClassicVersion = "1.3.14" minSdk = "24" moduleGraph = "2.5.0" multiplatformSettings = "1.2.0" +mokoPermission="0.18.0" okHttp3Version = "4.12.0" okioVersion = "3.9.1" playServicesAuthVersion = "21.2.0" @@ -133,6 +135,7 @@ androidx-profileinstaller = { group = "androidx.profileinstaller", name = "profi androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" } androidx-tracing-ktx = { group = "androidx.tracing", name = "tracing-ktx", version.ref = "androidxTracing" } androidx-ui-desktop = { group = "androidx.compose.ui", name = "ui-desktop", version.ref = "uiDesktopVersion" } +back-handler= {group="com.arkivanov.essenty", name="back-handler",version.ref="backHandlerVersion"} coil-core = { group = "io.coil-kt.coil3", name = "coil-core", version.ref = "coil" } coil-kt = { group = "io.coil-kt.coil3", name = "coil", version.ref = "coil" } coil-kt-compose = { group = "io.coil-kt.coil3", name = "coil-compose-core", version.ref = "coil" } @@ -214,6 +217,8 @@ multiplatform-settings = { group = "com.russhwolf", name = "multiplatform-settin multiplatform-settings-coroutines = { group = "com.russhwolf", name = "multiplatform-settings-coroutines", version.ref = "multiplatformSettings" } multiplatform-settings-serialization = { group = "com.russhwolf", name = "multiplatform-settings-serialization", version.ref = "multiplatformSettings" } multiplatform-settings-test = { group = "com.russhwolf", name = "multiplatform-settings-test", version.ref = "multiplatformSettings" } +moko-permission = {group="dev.icerock.moko", name="permissions", version.ref="mokoPermission"} +moko-permission-compose = {group="dev.icerock.moko", name="permissions-compose", version.ref="mokoPermission"} play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "playServicesAuthVersion" } protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version.ref = "protobuf" } protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" } From 69a04d86398eae83e1d106404048ba276599b401 Mon Sep 17 00:00:00 2001 From: Sk Niyaj Ali Date: Mon, 30 Sep 2024 14:48:48 +0530 Subject: [PATCH 07/31] Feat: [:core:ui] - Migrated to KMP with CMP Library (#1775) --- .../main/kotlin/KMPLibraryConventionPlugin.kt | 1 - core/analytics/consumer-rules.pro | 0 core/analytics/proguard-rules.pro | 21 --------------- core/common/consumer-rules.pro | 0 core/common/proguard-rules.pro | 21 --------------- ...ndroid.kt => CurrencyFormatter.android.kt} | 13 +++++++-- .../mifospay/core/common/FileUtils.android.kt | 12 +++++++-- .../mifospay/core/common/CurrencyFormatter.kt | 18 +++++++++++++ .../org/mifospay/core/common/FileUtils.kt | 12 +++++++-- .../kotlin/org/mifospay/core/common/Result.kt | 11 +++++++- .../kotlin/org/mifospay/core/common/Utils.kt | 9 ------- ...{Utils.jvm.kt => CurrencyFormatter.jvm.kt} | 13 +++++++-- .../org/mifospay/core/common/FileUtils.jvm.kt | 10 ++++++- ....native.kt => CurrencyFormatter.native.kt} | 13 +++++++-- .../mifospay/core/common/FileUtils.native.kt | 11 +++++++- core/datastore-proto/consumer-rules.pro | 0 core/datastore-proto/proguard-rules.pro | 21 --------------- core/datastore/proguard-rules.pro | 21 --------------- .../core/datastore/PreferencesMapper.kt | 11 +++++++- .../datastore/UserPreferencesDataSource.kt | 9 +++++++ .../core/datastore/di/PreferenceModule.kt | 11 +++++++- core/designsystem/build.gradle.kts | 2 -- .../designsystem/component/MifosTopBar.kt | 2 +- .../commonMain/resources/values/values.xml | 0 .../org/mifospay/core/model/ClientInfo.kt | 9 +++++++ .../org/mifospay/core/model/RoleInfo.kt | 11 +++++++- .../org/mifospay/core/model/UserInfo.kt | 11 +++++++- .../core/model/domain/client/Client.kt | 2 +- .../org/mifospay/core/model/entity/Invoice.kt | 2 +- .../model/entity/accounts/savings/Currency.kt | 2 +- .../accounts/savings/TransactionType.kt | 2 +- .../accounts/savings/TransactionsEntity.kt | 2 +- .../core/model/entity/client/DepositType.kt | 2 +- .../entity/templates/account/AccountType.kt | 2 +- .../mifospay/core/model/utils/DateHelper.kt | 2 +- core/ui/build.gradle.kts | 1 + core/ui/consumer-rules.pro | 0 core/ui/proguard-rules.pro | 21 --------------- .../{main => androidMain}/AndroidManifest.xml | 0 .../mifospay/core/ui/JankStatsExtensions.kt | 0 .../drawable/core_ui_info_outline.xml} | 0 .../drawable/core_ui_money_in.png | Bin .../drawable/core_ui_money_out.png | Bin .../composeResources}/values/strings.xml | 2 +- .../org/mifospay/core/ui/DevicePreviews.kt | 7 ++--- .../mifospay/core/ui/EmptyContentScreen.kt | 16 ++++++----- .../mifospay/core/ui/ErrorScreenContent.kt | 15 ++++++----- .../org/mifospay/core/ui/ExpiryDateInput.kt | 3 +-- .../org/mifospay/core/ui/FaqItemScreen.kt | 0 .../org/mifospay/core/ui/HeadingTitile.kt | 2 +- .../org/mifospay/core/ui/LocalTimeZone.kt | 0 .../org/mifospay/core/ui/MifosUserImage.kt | 7 +++-- .../org/mifospay/core/ui/OtpTextField.kt | 2 +- .../core/ui/ProfileConcentricImage.kt | 4 +-- .../org/mifospay/core/ui/ScrollableTabRow.kt | 7 ++--- .../mifospay/core/ui/TransactionItemScreen.kt | 23 +++++++++------- .../mifospay/core/ui/utility/AddBtnChip.kt | 9 +++---- .../mifospay/core/ui/utility/DialogState.kt | 0 .../mifospay/core/ui/utility/DialogType.kt | 0 .../mifospay/core/ui/utility/TabContent.kt | 0 .../mifospay/ui/ExampleUnitTest.kt | 25 ------------------ .../feature/invoices/InvoiceDetailScreen.kt | 1 - .../feature/kyc/KYCDescriptionScreen.kt | 1 - 63 files changed, 218 insertions(+), 217 deletions(-) delete mode 100644 core/analytics/consumer-rules.pro delete mode 100644 core/analytics/proguard-rules.pro delete mode 100644 core/common/consumer-rules.pro delete mode 100644 core/common/proguard-rules.pro rename core/common/src/androidMain/kotlin/org/mifospay/core/common/{Utils.android.kt => CurrencyFormatter.android.kt} (57%) create mode 100644 core/common/src/commonMain/kotlin/org/mifospay/core/common/CurrencyFormatter.kt delete mode 100644 core/common/src/commonMain/kotlin/org/mifospay/core/common/Utils.kt rename core/common/src/jvmMain/kotlin/org/mifospay/core/common/{Utils.jvm.kt => CurrencyFormatter.jvm.kt} (57%) rename core/common/src/nativeMain/kotlin/org/mifospay/core/common/{Utils.native.kt => CurrencyFormatter.native.kt} (59%) delete mode 100644 core/datastore-proto/consumer-rules.pro delete mode 100644 core/datastore-proto/proguard-rules.pro delete mode 100644 core/datastore/proguard-rules.pro delete mode 100644 core/designsystem/src/commonMain/resources/values/values.xml delete mode 100644 core/ui/consumer-rules.pro delete mode 100644 core/ui/proguard-rules.pro rename core/ui/src/{main => androidMain}/AndroidManifest.xml (100%) rename core/ui/src/{main => androidMain}/kotlin/org/mifospay/core/ui/JankStatsExtensions.kt (100%) rename core/ui/src/{main/res/drawable/core_ui_baseline_info_outline_24.xml => commonMain/composeResources/drawable/core_ui_info_outline.xml} (100%) rename core/ui/src/{main/res => commonMain/composeResources}/drawable/core_ui_money_in.png (100%) rename core/ui/src/{main/res => commonMain/composeResources}/drawable/core_ui_money_out.png (100%) rename core/ui/src/{main/res => commonMain/composeResources}/values/strings.xml (80%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/DevicePreviews.kt (59%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/EmptyContentScreen.kt (92%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/ErrorScreenContent.kt (84%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/ExpiryDateInput.kt (98%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/FaqItemScreen.kt (100%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/HeadingTitile.kt (97%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/LocalTimeZone.kt (100%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/MifosUserImage.kt (89%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/OtpTextField.kt (98%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/ProfileConcentricImage.kt (95%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/ScrollableTabRow.kt (90%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt (81%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/utility/AddBtnChip.kt (90%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/utility/DialogState.kt (100%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/utility/DialogType.kt (100%) rename core/ui/src/{main => commonMain}/kotlin/org/mifospay/core/ui/utility/TabContent.kt (100%) delete mode 100644 core/ui/src/test/java/org/mifospay/mobilewallet/mifospay/ui/ExampleUnitTest.kt diff --git a/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt index 678e698f2..8f2e00185 100644 --- a/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt @@ -18,7 +18,6 @@ class KMPLibraryConventionPlugin: Plugin { apply("mifospay.kmp.koin") apply("mifos.detekt.plugin") apply("mifos.spotless.plugin") - apply("mifos.ktlint.plugin") } configureKotlinMultiplatform() diff --git a/core/analytics/consumer-rules.pro b/core/analytics/consumer-rules.pro deleted file mode 100644 index e69de29bb..000000000 diff --git a/core/analytics/proguard-rules.pro b/core/analytics/proguard-rules.pro deleted file mode 100644 index 481bb4348..000000000 --- a/core/analytics/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/core/common/consumer-rules.pro b/core/common/consumer-rules.pro deleted file mode 100644 index e69de29bb..000000000 diff --git a/core/common/proguard-rules.pro b/core/common/proguard-rules.pro deleted file mode 100644 index 481bb4348..000000000 --- a/core/common/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/common/Utils.android.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/common/CurrencyFormatter.android.kt similarity index 57% rename from core/common/src/androidMain/kotlin/org/mifospay/core/common/Utils.android.kt rename to core/common/src/androidMain/kotlin/org/mifospay/core/common/CurrencyFormatter.android.kt index 9ece3cb54..4fee020b7 100644 --- a/core/common/src/androidMain/kotlin/org/mifospay/core/common/Utils.android.kt +++ b/core/common/src/androidMain/kotlin/org/mifospay/core/common/CurrencyFormatter.android.kt @@ -1,9 +1,18 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.common import java.text.NumberFormat import java.util.Currency -actual class CurrencyFormatter { +actual object CurrencyFormatter { actual fun format( balance: Double?, currencyCode: String?, @@ -14,4 +23,4 @@ actual class CurrencyFormatter { balanceFormatter.currency = Currency.getInstance(currencyCode) return balanceFormatter.format(balance) } -} \ No newline at end of file +} diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/common/FileUtils.android.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/common/FileUtils.android.kt index 53d528d60..83a3f6ff1 100644 --- a/core/common/src/androidMain/kotlin/org/mifospay/core/common/FileUtils.android.kt +++ b/core/common/src/androidMain/kotlin/org/mifospay/core/common/FileUtils.android.kt @@ -1,5 +1,13 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.common - // JVM and Android implementation -actual fun createPlatformFileUtils(): FileUtils = CommonFileUtils() \ No newline at end of file +actual fun createPlatformFileUtils(): FileUtils = CommonFileUtils() diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/CurrencyFormatter.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/CurrencyFormatter.kt new file mode 100644 index 000000000..9ef39ab76 --- /dev/null +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/CurrencyFormatter.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +expect object CurrencyFormatter { + fun format(balance: Double?, currencyCode: String?, maximumFractionDigits: Int?): String +} + +fun List.toArrayList(): ArrayList { + return ArrayList(this) +} diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt index 1c664646e..26b62d47f 100644 --- a/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.common import co.touchlab.kermit.Logger @@ -7,7 +16,6 @@ import okio.FileSystem import okio.Path.Companion.toPath import okio.SYSTEM - interface FileUtils { suspend fun writeInputStreamDataToFile(inputStream: ByteArray, filePath: String): Boolean @@ -36,4 +44,4 @@ class CommonFileUtils : FileUtils { false } } -} \ No newline at end of file +} diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/Result.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Result.kt index 19a72890e..fbc2e14ef 100644 --- a/core/common/src/commonMain/kotlin/org/mifospay/core/common/Result.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Result.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.common import kotlinx.coroutines.flow.Flow @@ -13,4 +22,4 @@ sealed interface Result { fun Flow.asResult(): Flow> = map> { Result.Success(it) } .onStart { emit(Result.Loading) } - .catch { emit(Result.Error(it)) } \ No newline at end of file + .catch { emit(Result.Error(it)) } diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/Utils.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Utils.kt deleted file mode 100644 index faa6d8f50..000000000 --- a/core/common/src/commonMain/kotlin/org/mifospay/core/common/Utils.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.mifospay.core.common - -expect class CurrencyFormatter { - fun format(balance: Double?, currencyCode: String?, maximumFractionDigits: Int?): String -} - -fun List.toArrayList(): ArrayList { - return ArrayList(this) -} \ No newline at end of file diff --git a/core/common/src/jvmMain/kotlin/org/mifospay/core/common/Utils.jvm.kt b/core/common/src/jvmMain/kotlin/org/mifospay/core/common/CurrencyFormatter.jvm.kt similarity index 57% rename from core/common/src/jvmMain/kotlin/org/mifospay/core/common/Utils.jvm.kt rename to core/common/src/jvmMain/kotlin/org/mifospay/core/common/CurrencyFormatter.jvm.kt index 806fd7af7..ce7c14600 100644 --- a/core/common/src/jvmMain/kotlin/org/mifospay/core/common/Utils.jvm.kt +++ b/core/common/src/jvmMain/kotlin/org/mifospay/core/common/CurrencyFormatter.jvm.kt @@ -1,9 +1,18 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.common import java.text.NumberFormat import java.util.Currency -actual class CurrencyFormatter { +actual object CurrencyFormatter { actual fun format( balance: Double?, currencyCode: String?, @@ -14,4 +23,4 @@ actual class CurrencyFormatter { numberFormat.currency = Currency.getInstance(currencyCode) return numberFormat.format(balance) } -} \ No newline at end of file +} diff --git a/core/common/src/jvmMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt b/core/common/src/jvmMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt index a619afac0..83a3f6ff1 100644 --- a/core/common/src/jvmMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt +++ b/core/common/src/jvmMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt @@ -1,5 +1,13 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.common // JVM and Android implementation actual fun createPlatformFileUtils(): FileUtils = CommonFileUtils() - diff --git a/core/common/src/nativeMain/kotlin/org/mifospay/core/common/Utils.native.kt b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/CurrencyFormatter.native.kt similarity index 59% rename from core/common/src/nativeMain/kotlin/org/mifospay/core/common/Utils.native.kt rename to core/common/src/nativeMain/kotlin/org/mifospay/core/common/CurrencyFormatter.native.kt index a7c68ea45..f42222181 100644 --- a/core/common/src/nativeMain/kotlin/org/mifospay/core/common/Utils.native.kt +++ b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/CurrencyFormatter.native.kt @@ -1,8 +1,17 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.common import platform.Foundation.NSNumberFormatter -actual class CurrencyFormatter { +actual object CurrencyFormatter { actual fun format( balance: Double?, currencyCode: String?, @@ -14,4 +23,4 @@ actual class CurrencyFormatter { numberFormatter.maximumFractionDigits = maximumFractionDigits ?: 0 return numberFormatter.stringFromNumber(balance ?: 0.0) ?: "" } -} \ No newline at end of file +} diff --git a/core/common/src/nativeMain/kotlin/org/mifospay/core/common/FileUtils.native.kt b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/FileUtils.native.kt index d60f3b49e..ae5069aa3 100644 --- a/core/common/src/nativeMain/kotlin/org/mifospay/core/common/FileUtils.native.kt +++ b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/FileUtils.native.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.common import kotlinx.cinterop.ExperimentalForeignApi @@ -21,4 +30,4 @@ actual fun createPlatformFileUtils(): FileUtils = object : FileUtils { } private fun ByteArray.toNSData(): NSData = NSData.create(bytes = this.refTo(0), length = this.size.toULong()) -} \ No newline at end of file +} diff --git a/core/datastore-proto/consumer-rules.pro b/core/datastore-proto/consumer-rules.pro deleted file mode 100644 index e69de29bb..000000000 diff --git a/core/datastore-proto/proguard-rules.pro b/core/datastore-proto/proguard-rules.pro deleted file mode 100644 index 481bb4348..000000000 --- a/core/datastore-proto/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/core/datastore/proguard-rules.pro b/core/datastore/proguard-rules.pro deleted file mode 100644 index 481bb4348..000000000 --- a/core/datastore/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt index a1fc33861..cd67a1dfc 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.datastore import org.mifospay.core.datastore.proto.ClientPreferences @@ -113,4 +122,4 @@ fun UserData.toUserPreferences(): UserPreferences { client = client.toClientPreferences(), user = user.toUserInfoPreferences(), ) -} \ No newline at end of file +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt index a15d60c56..36a76f39a 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ @file:OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) package org.mifospay.core.datastore diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt index fb8139122..d3b57761f 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.datastore.di import com.russhwolf.settings.Settings @@ -9,4 +18,4 @@ val PreferencesModule = module { factory { Settings() } // Use the IO dispatcher name - MifosDispatchers.IO.name factory { UserPreferencesDataSource(get(), get(named("IO"))) } -} \ No newline at end of file +} diff --git a/core/designsystem/build.gradle.kts b/core/designsystem/build.gradle.kts index c361c81d8..fc4ae96c9 100644 --- a/core/designsystem/build.gradle.kts +++ b/core/designsystem/build.gradle.kts @@ -75,8 +75,6 @@ kotlin { implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) implementation(libs.back.handler) - implementation(libs.moko.permission) - implementation(libs.moko.permission.compose) } } } diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt index a03847ea5..beabb5148 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopBar.kt @@ -53,4 +53,4 @@ fun MifosTopBar( actions = actions, modifier = modifier, ) -} \ No newline at end of file +} diff --git a/core/designsystem/src/commonMain/resources/values/values.xml b/core/designsystem/src/commonMain/resources/values/values.xml deleted file mode 100644 index e69de29bb..000000000 diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt index 54213d788..6a9bf7701 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.model data class ClientInfo( diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt index c100f8e69..224b9ad7a 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt @@ -1,8 +1,17 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.model data class RoleInfo( val id: String, val name: String, val description: String, - val disabled: Boolean + val disabled: Boolean, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt index c5274d25d..d34179e07 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ package org.mifospay.core.model data class UserInfo( @@ -11,5 +20,5 @@ data class UserInfo( val permissions: List, val clients: List, val shouldRenewPassword: Boolean, - val isTwoFactorAuthenticationRequired: Boolean + val isTwoFactorAuthenticationRequired: Boolean, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt index 00eb538fe..151fd5a2e 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt @@ -19,4 +19,4 @@ data class Client( val clientId: Long = 0L, val displayName: String? = null, val mobileNo: String? = null, -) \ No newline at end of file +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt index cf0093f03..f14092bf9 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt @@ -23,7 +23,7 @@ data class Invoice( val title: String? = null, val date: List = ArrayList(), - ) { +) { constructor() : this( consumerId = null, consumerName = null, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt index 1d9824bc7..abc0bc9ae 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt @@ -19,7 +19,7 @@ data class Currency( val inMultiplesOf: Int? = null, val displaySymbol: String = "", val nameCode: String = "", - val displayLabel: String = "" + val displayLabel: String = "", ) { constructor() : this( code = "", diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt index baed86912..975a3018d 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt @@ -32,4 +32,4 @@ data class TransactionType( val escheat: Boolean? = null, val amountHold: Boolean = false, val amountRelease: Boolean = false, -) \ No newline at end of file +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionsEntity.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionsEntity.kt index 45c081985..6407fcf72 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionsEntity.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionsEntity.kt @@ -32,4 +32,4 @@ data class TransactionsEntity( val originalTransactionId: Long? = null, val lienTransaction: Boolean = false, val releaseTransactionId: Long? = null, -) \ No newline at end of file +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt index ed8887621..2ef4b138f 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt @@ -30,7 +30,7 @@ data class DepositType( RECURRING( id = 300, code = "depositAccountType.recurringDeposit", - endpoint = "recurringdepositaccounts" + endpoint = "recurringdepositaccounts", ), ; diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt index 5eaaa3da7..e9eab35bd 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt @@ -16,4 +16,4 @@ data class AccountType( val id: Int? = null, val code: String? = null, val value: String? = null, -) \ No newline at end of file +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt index a5d0b223b..981e3d6eb 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt @@ -146,4 +146,4 @@ object DateHelper { val currentDate = Clock.System.now().toEpochMilliseconds().toString() val formattedDate = fullMonthFormat.parse(currentDate).toString() -} \ No newline at end of file +} diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index 3426567e3..ae180d6af 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -29,6 +29,7 @@ kotlin { api(projects.core.analytics) api(projects.core.designsystem) api(projects.core.model) + api(projects.core.common) implementation(libs.coil.kt) implementation(libs.coil.kt.compose) implementation(compose.material3) diff --git a/core/ui/consumer-rules.pro b/core/ui/consumer-rules.pro deleted file mode 100644 index e69de29bb..000000000 diff --git a/core/ui/proguard-rules.pro b/core/ui/proguard-rules.pro deleted file mode 100644 index 481bb4348..000000000 --- a/core/ui/proguard-rules.pro +++ /dev/null @@ -1,21 +0,0 @@ -# Add project specific ProGuard rules here. -# You can control the set of applied configuration files using the -# proguardFiles setting in build.gradle. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} - -# Uncomment this to preserve the line number information for -# debugging stack traces. -#-keepattributes SourceFile,LineNumberTable - -# If you keep the line number information, uncomment this to -# hide the original source file name. -#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/core/ui/src/main/AndroidManifest.xml b/core/ui/src/androidMain/AndroidManifest.xml similarity index 100% rename from core/ui/src/main/AndroidManifest.xml rename to core/ui/src/androidMain/AndroidManifest.xml diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/JankStatsExtensions.kt b/core/ui/src/androidMain/kotlin/org/mifospay/core/ui/JankStatsExtensions.kt similarity index 100% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/JankStatsExtensions.kt rename to core/ui/src/androidMain/kotlin/org/mifospay/core/ui/JankStatsExtensions.kt diff --git a/core/ui/src/main/res/drawable/core_ui_baseline_info_outline_24.xml b/core/ui/src/commonMain/composeResources/drawable/core_ui_info_outline.xml similarity index 100% rename from core/ui/src/main/res/drawable/core_ui_baseline_info_outline_24.xml rename to core/ui/src/commonMain/composeResources/drawable/core_ui_info_outline.xml diff --git a/core/ui/src/main/res/drawable/core_ui_money_in.png b/core/ui/src/commonMain/composeResources/drawable/core_ui_money_in.png similarity index 100% rename from core/ui/src/main/res/drawable/core_ui_money_in.png rename to core/ui/src/commonMain/composeResources/drawable/core_ui_money_in.png diff --git a/core/ui/src/main/res/drawable/core_ui_money_out.png b/core/ui/src/commonMain/composeResources/drawable/core_ui_money_out.png similarity index 100% rename from core/ui/src/main/res/drawable/core_ui_money_out.png rename to core/ui/src/commonMain/composeResources/drawable/core_ui_money_out.png diff --git a/core/ui/src/main/res/values/strings.xml b/core/ui/src/commonMain/composeResources/values/strings.xml similarity index 80% rename from core/ui/src/main/res/values/strings.xml rename to core/ui/src/commonMain/composeResources/values/strings.xml index 6ac6f61e8..bb6e8fb48 100644 --- a/core/ui/src/main/res/values/strings.xml +++ b/core/ui/src/commonMain/composeResources/values/strings.xml @@ -11,5 +11,5 @@ Retry Error Occurred! - Please check your connection or try again + Please check your connection or try again \ No newline at end of file diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/DevicePreviews.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/DevicePreviews.kt similarity index 59% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/DevicePreviews.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/DevicePreviews.kt index 6e15874c9..c573a6297 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/DevicePreviews.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/DevicePreviews.kt @@ -9,14 +9,11 @@ */ package org.mifospay.core.ui -import androidx.compose.ui.tooling.preview.Preview +import org.jetbrains.compose.ui.tooling.preview.Preview /** * Multipreview annotation that represents various device sizes. Add this annotation to a composable * to render various devices. */ -@Preview(name = "phone", device = "spec:width=360dp,height=640dp,dpi=480") -@Preview(name = "landscape", device = "spec:width=640dp,height=360dp,dpi=480") -@Preview(name = "foldable", device = "spec:width=673dp,height=841dp,dpi=480") -@Preview(name = "tablet", device = "spec:width=1280dp,height=800dp,dpi=480") +@Preview annotation class DevicePreviews diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/EmptyContentScreen.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/EmptyContentScreen.kt similarity index 92% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/EmptyContentScreen.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/EmptyContentScreen.kt index 1441d645c..fe2adb76c 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/EmptyContentScreen.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/EmptyContentScreen.kt @@ -28,11 +28,13 @@ import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import mobile_wallet.core.ui.generated.resources.Res +import mobile_wallet.core.ui.generated.resources.core_ui_money_in +import org.jetbrains.compose.resources.DrawableResource +import org.jetbrains.compose.resources.painterResource import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.MifosTheme @@ -89,7 +91,7 @@ fun EmptyContentScreen( fun EmptyContentScreen( title: String, subTitle: String, - iconDrawable: Int, + iconDrawable: DrawableResource, modifier: Modifier = Modifier, iconTint: Color = MaterialTheme.colorScheme.surfaceTint, ) { @@ -99,7 +101,7 @@ fun EmptyContentScreen( imageContent = { Image( modifier = Modifier.size(64.dp), - painter = painterResource(id = iconDrawable), + painter = painterResource(iconDrawable), colorFilter = if (iconTint != Color.Unspecified) ColorFilter.tint(iconTint) else null, contentDescription = null, ) @@ -131,21 +133,21 @@ fun EmptyContentScreen( ) } -@Preview(device = "id:pixel_5") +@DevicePreviews @Composable fun EmptyContentScreenDrawableImagePreview() { MifosTheme { EmptyContentScreen( title = "No data found", subTitle = "Please check you connection or try again", - iconDrawable = R.drawable.core_ui_baseline_info_outline_24, + iconDrawable = Res.drawable.core_ui_money_in, modifier = Modifier, iconTint = MaterialTheme.colorScheme.primary, ) } } -@Preview(device = "id:pixel_5") +@DevicePreviews @Composable fun EmptyContentScreenImageVectorPreview() { MifosTheme { diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/ErrorScreenContent.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ErrorScreenContent.kt similarity index 84% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/ErrorScreenContent.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ErrorScreenContent.kt index da9b7c755..fb91d0759 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/ErrorScreenContent.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ErrorScreenContent.kt @@ -23,19 +23,22 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import mobile_wallet.core.ui.generated.resources.Res +import mobile_wallet.core.ui.generated.resources.core_ui_error_occurred +import mobile_wallet.core.ui.generated.resources.core_ui_retry +import mobile_wallet.core.ui.generated.resources.core_ui_try_again +import org.jetbrains.compose.resources.stringResource import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.theme.MifosTheme @Composable fun ErrorScreenContent( modifier: Modifier = Modifier, - title: String = stringResource(id = R.string.core_ui_error_occurred), - subTitle: String = stringResource(id = R.string.core_ui_please_check_your_connection_or_try_again), + title: String = stringResource(resource = Res.string.core_ui_error_occurred), + subTitle: String = stringResource(resource = Res.string.core_ui_try_again), onClickRetry: () -> Unit = { }, ) { Column( @@ -80,13 +83,13 @@ fun ErrorScreenContent( .padding(top = 16.dp), onClick = onClickRetry, ) { - Text(text = stringResource(id = R.string.core_ui_retry)) + Text(text = stringResource(resource = Res.string.core_ui_retry)) } } } } -@Preview(device = "id:pixel_5") +@DevicePreviews @Composable fun ErrorContentScreenDrawableImagePreview() { MifosTheme { diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/ExpiryDateInput.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ExpiryDateInput.kt similarity index 98% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/ExpiryDateInput.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ExpiryDateInput.kt index a758f3bc6..42098cf56 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/ExpiryDateInput.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ExpiryDateInput.kt @@ -34,7 +34,6 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @OptIn(ExperimentalComposeUiApi::class) @@ -128,7 +127,7 @@ fun FormattedDateView( ) } -@Preview(showBackground = true) +@DevicePreviews @Composable fun ExpiryDateInputPreview() { ExpiryDateInput(date = "", onDateChange = {}, onDone = {}) diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/FaqItemScreen.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/FaqItemScreen.kt similarity index 100% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/FaqItemScreen.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/FaqItemScreen.kt diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/HeadingTitile.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/HeadingTitile.kt similarity index 97% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/HeadingTitile.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/HeadingTitile.kt index 891347c2e..0f31c6762 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/HeadingTitile.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/HeadingTitile.kt @@ -24,9 +24,9 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import org.jetbrains.compose.ui.tooling.preview.Preview import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.MifosTheme diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/LocalTimeZone.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/LocalTimeZone.kt similarity index 100% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/LocalTimeZone.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/LocalTimeZone.kt diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/MifosUserImage.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/MifosUserImage.kt similarity index 89% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/MifosUserImage.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/MifosUserImage.kt index 84f4ad55e..9db2430d2 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/MifosUserImage.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/MifosUserImage.kt @@ -9,7 +9,6 @@ */ package org.mifospay.core.ui -import android.graphics.Bitmap import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.shape.CircleShape @@ -17,14 +16,14 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.layout.ContentScale import org.mifospay.core.designsystem.component.MifosTextUserImage @Composable fun MifosUserImage( modifier: Modifier = Modifier, - bitmap: Bitmap? = null, + bitmap: ImageBitmap? = null, username: String? = null, ) { if (bitmap == null) { @@ -37,7 +36,7 @@ fun MifosUserImage( modifier = modifier .clip(CircleShape) .background(MaterialTheme.colorScheme.primary), - bitmap = bitmap.asImageBitmap(), + bitmap = bitmap, contentDescription = "Profile Image", contentScale = ContentScale.Crop, ) diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/OtpTextField.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/OtpTextField.kt similarity index 98% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/OtpTextField.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/OtpTextField.kt index 59b034b7d..abb1b40ec 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/OtpTextField.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/OtpTextField.kt @@ -35,8 +35,8 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview @Composable fun OtpTextField( diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/ProfileConcentricImage.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ProfileConcentricImage.kt similarity index 95% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/ProfileConcentricImage.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ProfileConcentricImage.kt index 79ca16e76..0ed47bb10 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/ProfileConcentricImage.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ProfileConcentricImage.kt @@ -9,7 +9,6 @@ */ package org.mifospay.core.ui -import android.graphics.Bitmap import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -22,12 +21,13 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ImageBitmap import androidx.compose.ui.unit.dp @Composable fun ProfileImage( modifier: Modifier = Modifier, - bitmap: Bitmap? = null, + bitmap: ImageBitmap? = null, ) { Row( modifier = modifier diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/ScrollableTabRow.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ScrollableTabRow.kt similarity index 90% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/ScrollableTabRow.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ScrollableTabRow.kt index b806e14fb..b668cc682 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/ScrollableTabRow.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/ScrollableTabRow.kt @@ -9,6 +9,9 @@ */ package org.mifospay.core.ui +import androidx.compose.foundation.ExperimentalFoundationApi +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.PagerState import androidx.compose.material3.MaterialTheme import androidx.compose.material3.ScrollableTabRow import androidx.compose.runtime.Composable @@ -17,12 +20,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import com.google.accompanist.pager.HorizontalPager -import com.google.accompanist.pager.PagerState import kotlinx.coroutines.launch import org.mifospay.core.designsystem.component.MifosTab import org.mifospay.core.ui.utility.TabContent +@OptIn(ExperimentalFoundationApi::class) @Suppress("MultipleEmitters") @Composable fun MifosScrollableTabRow( @@ -58,7 +60,6 @@ fun MifosScrollableTabRow( } HorizontalPager( - count = tabContents.size, state = pagerState, ) { tabContents[it].content.invoke() diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt similarity index 81% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt index cb9c5bc71..c97fe367e 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt @@ -22,18 +22,21 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter -import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.mifospay.core.model.domain.Transaction -import com.mifospay.core.model.domain.TransactionType -import org.mifospay.common.Utils.getFormattedAccountBalance +import mobile_wallet.core.ui.generated.resources.Res +import mobile_wallet.core.ui.generated.resources.core_ui_money_in +import mobile_wallet.core.ui.generated.resources.core_ui_money_out +import org.jetbrains.compose.resources.painterResource +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.common.CurrencyFormatter import org.mifospay.core.designsystem.theme.green import org.mifospay.core.designsystem.theme.red +import org.mifospay.core.model.domain.Transaction +import org.mifospay.core.model.domain.TransactionType @Composable fun TransactionItemScreen( @@ -51,10 +54,10 @@ fun TransactionItemScreen( .size(20.dp) .padding(top = 2.dp), painter = painterResource( - id = when (transaction.transactionType) { - TransactionType.DEBIT -> R.drawable.core_ui_money_out - TransactionType.CREDIT -> R.drawable.core_ui_money_in - else -> R.drawable.core_ui_money_in + resource = when (transaction.transactionType) { + TransactionType.DEBIT -> Res.drawable.core_ui_money_out + TransactionType.CREDIT -> Res.drawable.core_ui_money_in + else -> Res.drawable.core_ui_money_in }, ), contentDescription = null, @@ -83,7 +86,7 @@ fun TransactionItemScreen( ), ) } - val formattedAmount = getFormattedAccountBalance( + val formattedAmount = CurrencyFormatter.format( balance = transaction.amount, currencyCode = transaction.currency.code, maximumFractionDigits = 2, diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/utility/AddBtnChip.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utility/AddBtnChip.kt similarity index 90% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/utility/AddBtnChip.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utility/AddBtnChip.kt index 8d094a6ca..410d4a54a 100644 --- a/core/ui/src/main/kotlin/org/mifospay/core/ui/utility/AddBtnChip.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utility/AddBtnChip.kt @@ -18,15 +18,14 @@ 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.stringResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import org.mifospay.core.designsystem.icon.MifosIcons @Composable fun AddCardChip( - text: Int, - btnText: Int, + text: String, + btnText: String, onAddBtn: () -> Unit, modifier: Modifier = Modifier, ) { @@ -35,7 +34,7 @@ fun AddCardChip( onClick = onAddBtn, label = { Text( - stringResource(text), + text = text, style = MaterialTheme.typography.bodyLarge.copy( fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onPrimary, @@ -46,7 +45,7 @@ fun AddCardChip( leadingIcon = { Icon( imageVector = MifosIcons.Add, - contentDescription = stringResource(btnText), + contentDescription = btnText, modifier = Modifier.size(16.dp), tint = MaterialTheme.colorScheme.onPrimary, ) diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/utility/DialogState.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utility/DialogState.kt similarity index 100% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/utility/DialogState.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utility/DialogState.kt diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/utility/DialogType.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utility/DialogType.kt similarity index 100% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/utility/DialogType.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utility/DialogType.kt diff --git a/core/ui/src/main/kotlin/org/mifospay/core/ui/utility/TabContent.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utility/TabContent.kt similarity index 100% rename from core/ui/src/main/kotlin/org/mifospay/core/ui/utility/TabContent.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utility/TabContent.kt diff --git a/core/ui/src/test/java/org/mifospay/mobilewallet/mifospay/ui/ExampleUnitTest.kt b/core/ui/src/test/java/org/mifospay/mobilewallet/mifospay/ui/ExampleUnitTest.kt deleted file mode 100644 index 45d28910b..000000000 --- a/core/ui/src/test/java/org/mifospay/mobilewallet/mifospay/ui/ExampleUnitTest.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.mobilewallet.mifospay.ui - -import org.junit.Assert.assertEquals -import org.junit.Test - -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) - } -} diff --git a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt index eec164824..555a2b1f1 100644 --- a/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt +++ b/feature/invoices/src/main/kotlin/org/mifospay/feature/invoices/InvoiceDetailScreen.kt @@ -37,7 +37,6 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifospay.core.model.entity.Invoice -import org.mifospay.core.model.utils.DateHelper import org.koin.androidx.compose.koinViewModel import org.mifospay.core.common.Constants import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt index 45db65ee7..e69d5b565 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionScreen.kt @@ -45,7 +45,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mifos.library.pullrefresh.PullRefreshIndicator import com.mifos.library.pullrefresh.pullRefresh import com.mifos.library.pullrefresh.rememberPullRefreshState -import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.koin.androidx.compose.koinViewModel import org.mifospay.core.designsystem.component.MifosButton import org.mifospay.core.designsystem.component.MifosOverlayLoadingWheel From ae2b15b88348d11773df71d9b31a1421ef041ded Mon Sep 17 00:00:00 2001 From: Sk Niyaj Ali Date: Mon, 7 Oct 2024 19:59:20 +0530 Subject: [PATCH 08/31] Feat: [:feature:auth] - Migrated to Kotlin Multiplatform (#1782) * Feat: [:feature:auth] - Migrated to Kotlin Multiplatform * Added Support For Web --- .github/workflows/feature_branch_ci.yml | 32 - .github/workflows/master_dev_ci.yml | 11 +- .run/mifospay-android.run.xml | 70 + .run/mifospay-desktop.run.xml | 24 + .run/mifospay-web-js.run.xml | 24 + .run/mifospay-web-wasm.run.xml | 24 + .../main/kotlin/CMPFeatureConventionPlugin.kt | 20 +- .../main/kotlin/KMPKoinConventionPlugin.kt | 4 +- .../main/kotlin/KMPLibraryConventionPlugin.kt | 6 +- .../kotlin/KotlinInjectConventionPlugin.kt | 2 +- .../org/mifospay/KotlinMultiplatform.kt | 11 +- ci-prepush.bat | 6 +- ci-prepush.sh | 6 +- core/common/build.gradle.kts | 13 +- .../org/mifospay/core/common/Parcelize.kt | 29 + .../common/di/DispatchersModule.android.kt | 22 + .../org/mifospay/core/common/FileUtils.kt | 8 - .../mifospay/core/common/MifosDispatchers.kt | 1 + .../org/mifospay/core/common/Parcelize.kt | 41 + .../core/common/di/DispatchersModule.kt | 7 +- .../core/common/utils/StringExtensions.kt | 15 +- .../core/common/CurrencyFormatter.jvm.kt | 0 .../org/mifospay/core/common/FileUtils.jvm.kt | 0 .../org/mifospay/core/common/Parcelize.kt | 46 + .../common/di/DispatchersModule.desktop.kt | 22 + .../core/common/CurrencyFormatter.js.kt | 36 + .../org/mifospay/core/common/FileUtils.js.kt | 7 +- .../org/mifospay/core/common/Parcelize.kt | 46 + .../core/common/di/DispatchersModule.js.kt | 22 + .../org/mifospay/core/common/Parcelize.kt | 46 + .../common/di/DispatchersModule.native.kt | 22 + .../core/common/CurrencyFormatter.js.kt | 35 + .../org/mifospay/core/common/FileUtils.js.kt | 8 +- .../org/mifospay/core/common/Parcelize.kt | 46 + .../core/common/di/DispatchersModule.js.kt | 22 + .../di/AndroidPlatformDependentDataModule.kt | 10 +- .../core/data/di/AndroidPlatformModule.kt | 8 +- .../core/data/util/ErrorJsonMessageHelper.kt | 36 - .../data/di/PlatformDependentDataModule.kt | 11 +- .../mifospay/core/data/di/RepositoryModule.kt | 15 +- .../repository/AuthenticationRepository.kt | 4 +- .../data/repository/BeneficiaryRepository.kt | 10 +- .../core/data/repository/ClientRepository.kt | 7 +- .../data/repository/DocumentRepository.kt | 10 +- .../core/data/repository/SearchRepository.kt | 3 +- .../data/repository/SelfServiceRepository.kt | 4 +- .../core/data/repository/UserRepository.kt | 12 +- .../AuthenticationRepositoryImpl.kt | 18 +- .../BeneficiaryRepositoryImpl.kt | 10 +- .../repositoryImp/ClientRepositoryImpl.kt | 45 +- .../repositoryImp/DocumentRepositoryImpl.kt | 10 +- .../repositoryImp/SearchRepositoryImpl.kt | 18 +- .../SelfServiceRepositoryImpl.kt | 23 +- .../data/repositoryImp/UserRepositoryImpl.kt | 46 +- .../org/mifospay/core/data/util/Constants.kt | 2 +- .../data/JsPlatformDependentDataModule.kt} | 16 +- .../di/PlatformDependentDataModule.jvm.kt | 13 +- .../data/JsPlatformDependentDataModule.kt | 31 + .../di/PlatformDependentDataModule.jvm.kt | 22 + .../data/NativePlatformDependentDataModule.kt | 16 +- .../di/PlatformDependentDataModule.native.kt | 22 + .../data/JsPlatformDependentDataModule.kt | 31 + .../di/PlatformDependentDataModule.jvm.kt | 22 + .../datastore/proto/UserInfoPreferences.kt | 2 +- .../core/datastore/proto/UserPreferences.kt | 45 - .../datastore/proto/user_preference.proto | 22 - core/datastore/build.gradle.kts | 5 + .../core/datastore/PreferencesMapper.kt | 36 - .../datastore/UserPreferencesDataSource.kt | 71 +- .../datastore/UserPreferencesRepository.kt | 32 + .../UserPreferencesRepositoryImpl.kt | 69 + .../core/datastore/di/PreferenceModule.kt | 13 +- .../core/datastore/utils/UserMapper.kt | 47 + core/designsystem/build.gradle.kts | 19 - .../component/MifosBasicDialog.kt | 90 + .../component/MifosLoadingDialog.kt | 107 + .../designsystem/component/MifosScaffold.kt | 41 + .../designsystem/component/MifosTopAppBar.kt | 275 ++ .../core/designsystem/utils/ModifierExt.kt | 54 + {mifospay => core/domain}/.gitignore | 0 core/domain/README.md | 3 + .../domain/build.gradle.kts | 22 +- core/domain/proguard-rules.pro | 25 + .../org/mifospay/core/domain/LoginUseCase.kt | 64 + .../mifospay/core/domain/di/DomainModule.kt | 26 + .../org/mifospay/core/model/UserInfo.kt | 2 +- .../core/model/domain/client/NewClient.kt | 90 +- .../core/model/domain/user/NewUser.kt | 52 +- .../mifospay/core/model/domain/user/User.kt | 8 +- .../core/model/entity/SearchedEntity.kt | 8 +- .../mifospay/core/model/utils/DateHelper.kt | 9 +- core/network/build.gradle.kts | 32 +- .../src/androidMain/AndroidManifest.xml | 2 +- .../core/network/KtorAndroidHttpClient.kt | 53 + .../mifospay/core/network/KtorHttpClient.kt | 7 +- .../mifospay/core/network/KtorfitClient.kt | 135 +- .../mifospay/core/network/di/NetworkModule.kt | 55 +- .../org/mifospay/core/network/di/Qualifier.kt | 14 +- .../localAssets/JvmLocalAssetManager.kt | 10 +- .../network/localAssets/LocalAssetManager.kt | 4 +- .../localAssets/MifosLocalAssetDataSource.kt | 1 - .../core/network/model/ClientResponse.kt | 15 +- .../services/AccountTransfersService.kt | 4 +- .../network/services/AuthenticationService.kt | 5 +- .../network/services/BeneficiaryService.kt | 12 +- .../core/network/services/ClientService.kt | 23 +- .../core/network/services/DocumentService.kt | 12 +- .../core/network/services/InvoiceService.kt | 12 +- .../core/network/services/KYCLevel1Service.kt | 8 +- .../network/services/NotificationService.kt | 4 +- .../network/services/RegistrationService.kt | 6 +- .../core/network/services/RunReportService.kt | 4 +- .../core/network/services/SavedCardService.kt | 10 +- .../services/SavingsAccountsService.kt | 2 +- .../core/network/services/SearchService.kt | 5 +- .../services/StandingInstructionService.kt | 12 +- .../services/ThirdPartyTransferService.kt | 6 +- .../network/services/TwoFactorAuthService.kt | 8 +- .../core/network/services/UserService.kt | 20 +- .../core/network/{ => utils}/ApiEndPoints.kt | 3 +- .../core/network/{ => utils}/BaseURL.kt | 2 +- .../network/utils/FlowConverterFactory.kt | 52 + .../core/network/utils/KtorInterceptor.kt | 51 + .../core/network/KtorJvmHttpClient.kt | 52 + .../mifospay/core/network/KtorJsHttpClient.kt | 52 + .../core/network/KtorNativeHttpClient.kt | 52 + .../mifospay/core/network/KtorJsHttpClient.kt | 52 + core/ui/build.gradle.kts | 3 + .../feature_receipt_mifospay_round_logo.png | Bin .../mifospay/core/ui/MifosPasswordField.kt | 189 ++ .../ui/NonLetterColorVisualTransformation.kt | 61 + .../mifospay/core/ui/utils/BackgroundEvent.kt | 17 + .../mifospay/core/ui/utils/BaseViewModel.kt | 100 + .../mifospay/core/ui/utils/EventsEffect.kt | 42 + .../core/ui/utils/LifecycleEventEffect.kt | 41 + .../mifospay/core/ui/utils/PasswordChecker.kt | 94 + .../core/ui/utils}/PasswordStrength.kt | 14 +- .../ui/utils/PasswordStrengthExtensions.kt | 40 + feature/auth/build.gradle.kts | 40 +- .../{main => androidMain}/AndroidManifest.xml | 0 .../composeResources}/values/strings.xml | 6 +- .../mifospay/feature/auth/di/AuthModule.kt | 22 + .../feature/auth/login/LoginScreen.kt | 252 ++ .../feature/auth/login/LoginViewModel.kt | 154 + .../mobileVerify/MobileVerificationScreen.kt | 291 ++ .../MobileVerificationViewModel.kt | 287 ++ .../auth/navigation/LoginScreenNavigation.kt | 18 +- .../MobileVerificationScreenNavigation.kt | 37 + .../auth/navigation/SignupScreenNavigation.kt | 61 + .../auth/signup/PasswordStrengthIndicator.kt | 217 ++ .../feature/auth/signup/SignupScreen.kt | 308 ++ .../feature/auth/signup/SignupViewModel.kt | 591 ++++ .../socialSignup/SignupMethodNavigation.kt | 34 + .../auth/socialSignup/SignupMethodScreen.kt | 175 + .../mifospay/feature/auth/di/AuthModule.kt | 49 - .../feature/auth/login/LoginScreen.kt | 251 -- .../feature/auth/login/LoginViewModel.kt | 157 - .../mobileVerify/MobileVerificationScreen.kt | 289 -- .../MobileVerificationViewModel.kt | 92 - .../MobileVerificationScreenNavigation.kt | 83 - .../auth/navigation/SignupScreenNavigation.kt | 107 - .../feature/auth/signup/SignupScreen.kt | 531 --- .../feature/auth/signup/SignupViewModel.kt | 294 -- .../socialSignup/SocialSignupMethodScreen.kt | 350 -- .../feature/auth/utils/ValidateUtil.kt | 16 - .../feature/kyc/KYCDescriptionViewModel.kt | 4 +- .../feature/kyc/KYCLevel1ViewModel.kt | 2 +- gradle.properties | 1 + gradle/libs.versions.toml | 109 +- kotlin-js-store/yarn.lock | 2882 +++++++++++++++++ mifospay-android/.gitignore | 1 + {mifospay => mifospay-android}/README.md | 0 .../build.gradle.kts | 43 +- .../prodReleaseRuntimeClasspath.tree.txt | 2022 ++++++++++++ .../prodReleaseRuntimeClasspath.txt | 248 +- .../google-services.json | 0 .../lint-baseline.xml | 0 .../prodRelease-badging.txt | 16 +- .../proguard-rules.pro | 0 .../release_keystore.keystore | Bin .../org/mifospay/ExampleInstrumentedTest.kt | 0 .../src/main/AndroidManifest.xml | 4 - .../main/kotlin/org/mifospay/MainActivity.kt | 70 + .../main/kotlin/org/mifospay/MifosPayApp.kt | 16 +- .../api/services/MifosPayMessagingService.kt | 0 .../org/mifospay/utils/NotificationUtils.kt | 0 .../src/main/res/drawable/bg_splash.xml | 0 .../src/main/res/drawable/bg_splash_12.xml | 0 .../res/drawable/feature_accounts_ic_bank.xml | 28 + .../feature_receipt_mifospay_round_logo.png | Bin 0 -> 39075 bytes .../src/main/res/drawable/ic_finance.xml | 0 .../src/main/res/drawable/ic_home.xml | 0 .../src/main/res/drawable/ic_person.xml | 0 .../src/main/res/drawable/ic_swap_horiz.xml | 0 .../src/main/res/drawable/logo_axis.png | Bin .../src/main/res/drawable/logo_hdfc.png | Bin .../src/main/res/drawable/logo_icici.png | Bin .../src/main/res/drawable/logo_pnb.png | Bin .../src/main/res/drawable/logo_rbl.png | Bin .../src/main/res/drawable/logo_sbi.png | Bin .../main/res/drawable/mifospay_round_logo.png | Bin 0 -> 39075 bytes .../src/main/res/drawable/money_in.png | Bin .../src/main/res/drawable/money_out.png | Bin .../src/main/res/drawable/splash_icon.png | Bin .../res/drawable/splash_screen_background.xml | 0 .../src/main/res/mipmap/ic_launcher.png | Bin .../src/main/res/mipmap/ic_launcher_round.png | Bin .../src/main/res/values/colors.xml | 0 .../src/main/res/values/splash.xml | 0 .../src/main/res/values/strings.xml | 0 .../src/main/res/xml/provider_paths.xml | 0 .../java/org/mifospay/KoinModulesCheck.kt | 0 mifospay-desktop/.gitignore | 1 + mifospay-desktop/README.md | 1 + .../build.gradle.kts | 18 +- .../src/desktopMain/kotlin/main.kt | 5 +- .../iosApp.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../UserInterfaceState.xcuserstate | Bin .../xcschemes/xcschememanagement.plist | 0 .../xcschemes/iosApp.xcscheme | 0 .../xcschemes/xcschememanagement.plist | 0 .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../iosApp/Assets.xcassets/Contents.json | 0 .../iosApp/ContentView.swift | 2 +- .../Preview Assets.xcassets/Contents.json | 0 .../iosApp/iosAppApp.swift | 2 +- mifospay-shared/build.gradle.kts | 70 + .../composeResources/values/strings.xml | 21 + .../kotlin/org/mifospay/shared/MifosPayApp.kt | 89 + .../org/mifospay/shared/MifosPayViewModel.kt | 27 +- .../org/mifospay/shared/di/KoinModules.kt | 71 + .../shared}/navigation/LoginNavGraph.kt | 37 +- .../shared}/navigation/MifosNavGraph.kt | 2 +- .../shared/navigation/MifosNavHost.kt | 85 + .../shared}/navigation/RootNavGraph.kt | 8 +- .../org/mifospay/shared}/ui/MifosApp.kt | 201 +- .../org/mifospay/shared}/ui/MifosAppState.kt | 77 +- .../shared/utils}/TopLevelDestination.kt | 32 +- mifospay-web/.gitignore | 1 + mifospay-web/README.md | 3 + mifospay-web/build.gradle.kts | 62 + mifospay-web/src/jsMain/kotlin/Application.kt | 15 + mifospay-web/src/jsMain/resources/index.html | 15 + mifospay-web/src/jsMain/resources/styles.css | 14 + mifospay-web/src/wasmJsMain/kotlin/Main.kt | 16 + .../src/wasmJsMain/resources/index.html | 27 + .../src/wasmJsMain/resources/load.mjs | 5 + .../prodReleaseRuntimeClasspath.tree.txt | 2352 -------------- .../main/java/org/mifospay/MainActivity.kt | 145 - .../src/main/java/org/mifospay/MifosPayApp.kt | 42 - .../java/org/mifospay/di/JankStatsModule.kt | 36 - .../main/java/org/mifospay/di/KoinModules.kt | 76 - .../org/mifospay/navigation/MifosNavHost.kt | 306 -- .../mifospay/navigation/PasscodeNavGraph.kt | 42 - scripts/pre-commit.sh | 21 - scripts/pre-push.sh | 24 - settings.gradle.kts | 14 +- shared/build.gradle.kts | 119 - .../org/mifospay/shared/MainActivity.kt | 32 - .../org/mifospay/shared/Platform.android.kt | 22 - .../di/AndroidPlatformContextProvider.kt | 23 - .../preferences/DataStoreModule.android.kt | 23 - .../kotlin/org/mifospay/shared/App.kt | 37 - .../kotlin/org/mifospay/shared/Platform.kt | 26 - .../mifospay/shared/modal/domain/Client.kt | 19 - .../org/mifospay/shared/modal/domain/User.kt | 24 - .../mifospay/shared/modal/domain/UserData.kt | 17 - .../shared/preferences/DataStoreModule.kt | 32 - .../preferences/UserPreferenceRepository.kt | 169 - .../preferences/UserPreferenceSerializer.kt | 33 - .../commonMain/proto/user_preferences.proto | 49 - .../org/mifospay/shared/Platform.desktop.kt | 23 - .../preferences/DataStoreModule.desktop.kt | 25 - .../org/mifospay/shared/MainViewController.kt | 21 - .../org/mifospay/shared/Platform.ios.kt | 20 - .../shared/preferences/DataStoreModule.ios.kt | 33 - 279 files changed, 11515 insertions(+), 7199 deletions(-) delete mode 100644 .github/workflows/feature_branch_ci.yml create mode 100644 .run/mifospay-android.run.xml create mode 100644 .run/mifospay-desktop.run.xml create mode 100644 .run/mifospay-web-js.run.xml create mode 100644 .run/mifospay-web-wasm.run.xml create mode 100644 core/common/src/androidMain/kotlin/org/mifospay/core/common/Parcelize.kt create mode 100644 core/common/src/androidMain/kotlin/org/mifospay/core/common/di/DispatchersModule.android.kt create mode 100644 core/common/src/commonMain/kotlin/org/mifospay/core/common/Parcelize.kt rename shared/src/commonMain/kotlin/org/mifospay/shared/Greeting.kt => core/common/src/commonMain/kotlin/org/mifospay/core/common/utils/StringExtensions.kt (60%) rename core/common/src/{jvmMain => desktopMain}/kotlin/org/mifospay/core/common/CurrencyFormatter.jvm.kt (100%) rename core/common/src/{jvmMain => desktopMain}/kotlin/org/mifospay/core/common/FileUtils.jvm.kt (100%) create mode 100644 core/common/src/desktopMain/kotlin/org/mifospay/core/common/Parcelize.kt create mode 100644 core/common/src/desktopMain/kotlin/org/mifospay/core/common/di/DispatchersModule.desktop.kt create mode 100644 core/common/src/jsMain/kotlin/org/mifospay/core/common/CurrencyFormatter.js.kt rename shared/src/androidMain/kotlin/org/mifospay/shared/di/Modules.android.kt => core/common/src/jsMain/kotlin/org/mifospay/core/common/FileUtils.js.kt (76%) create mode 100644 core/common/src/jsMain/kotlin/org/mifospay/core/common/Parcelize.kt create mode 100644 core/common/src/jsMain/kotlin/org/mifospay/core/common/di/DispatchersModule.js.kt create mode 100644 core/common/src/nativeMain/kotlin/org/mifospay/core/common/Parcelize.kt create mode 100644 core/common/src/nativeMain/kotlin/org/mifospay/core/common/di/DispatchersModule.native.kt create mode 100644 core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/CurrencyFormatter.js.kt rename shared/src/desktopMain/kotlin/org/mifospay/shared/di/Modules.desktop.kt => core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/FileUtils.js.kt (66%) create mode 100644 core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/Parcelize.kt create mode 100644 core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/di/DispatchersModule.js.kt delete mode 100644 core/data/src/androidMain/kotlin/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt rename core/data/src/{jvmMain/kotlin/org/mifospay/core/data/JvmPlatformDependentDataModule.kt => desktopMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt} (57%) rename shared/src/commonMain/kotlin/org/mifospay/shared/di/Modules.kt => core/data/src/desktopMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt (53%) create mode 100644 core/data/src/jsMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt create mode 100644 core/data/src/jsMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt create mode 100644 core/data/src/nativeMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.native.kt create mode 100644 core/data/src/wasmJsMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt create mode 100644 core/data/src/wasmJsMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt delete mode 100644 core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt delete mode 100644 core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto create mode 100644 core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepository.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepositoryImpl.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/utils/UserMapper.kt create mode 100644 core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosBasicDialog.kt create mode 100644 core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosLoadingDialog.kt create mode 100644 core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopAppBar.kt create mode 100644 core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/utils/ModifierExt.kt rename {mifospay => core/domain}/.gitignore (100%) create mode 100644 core/domain/README.md rename shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModule.kt => core/domain/build.gradle.kts (50%) create mode 100644 core/domain/proguard-rules.pro create mode 100644 core/domain/src/commonMain/kotlin/org/mifospay/core/domain/LoginUseCase.kt create mode 100644 core/domain/src/commonMain/kotlin/org/mifospay/core/domain/di/DomainModule.kt create mode 100644 core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorAndroidHttpClient.kt rename shared/src/iosMain/kotlin/org/mifospay/shared/di/Modules.ios.kt => core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorHttpClient.kt (69%) rename shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Role.kt => core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponse.kt (59%) rename core/network/src/commonMain/kotlin/org/mifospay/core/network/{ => utils}/ApiEndPoints.kt (92%) rename core/network/src/commonMain/kotlin/org/mifospay/core/network/{ => utils}/BaseURL.kt (96%) create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/FlowConverterFactory.kt create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt create mode 100644 core/network/src/desktopMain/kotlin/org/mifospay/core/network/KtorJvmHttpClient.kt create mode 100644 core/network/src/jsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt create mode 100644 core/network/src/nativeMain/kotlin/org/mifospay/core/network/KtorNativeHttpClient.kt create mode 100644 core/network/src/wasmJsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt rename mifospay/src/main/res/drawable/mifospay_round_logo.png => core/ui/src/commonMain/composeResources/drawable/feature_receipt_mifospay_round_logo.png (100%) create mode 100644 core/ui/src/commonMain/kotlin/org/mifospay/core/ui/MifosPasswordField.kt create mode 100644 core/ui/src/commonMain/kotlin/org/mifospay/core/ui/NonLetterColorVisualTransformation.kt create mode 100644 core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BackgroundEvent.kt create mode 100644 core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BaseViewModel.kt create mode 100644 core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/EventsEffect.kt create mode 100644 core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/LifecycleEventEffect.kt create mode 100644 core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordChecker.kt rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/signup => ui/src/commonMain/kotlin/org/mifospay/core/ui/utils}/PasswordStrength.kt (74%) create mode 100644 core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrengthExtensions.kt rename feature/auth/src/{main => androidMain}/AndroidManifest.xml (100%) rename feature/auth/src/{main/res => commonMain/composeResources}/values/strings.xml (91%) create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/di/AuthModule.kt create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt rename feature/auth/src/{main => commonMain}/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt (63%) create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/PasswordStrengthIndicator.kt create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodNavigation.kt create mode 100644 feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodScreen.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt delete mode 100644 feature/auth/src/main/kotlin/org/mifospay/feature/auth/utils/ValidateUtil.kt create mode 100644 kotlin-js-store/yarn.lock create mode 100644 mifospay-android/.gitignore rename {mifospay => mifospay-android}/README.md (100%) rename {mifospay => mifospay-android}/build.gradle.kts (76%) create mode 100644 mifospay-android/dependencies/prodReleaseRuntimeClasspath.tree.txt rename {mifospay => mifospay-android}/dependencies/prodReleaseRuntimeClasspath.txt (69%) rename {mifospay => mifospay-android}/google-services.json (100%) rename {mifospay => mifospay-android}/lint-baseline.xml (100%) rename {mifospay => mifospay-android}/prodRelease-badging.txt (81%) rename {mifospay => mifospay-android}/proguard-rules.pro (100%) rename {mifospay => mifospay-android}/release_keystore.keystore (100%) rename {mifospay => mifospay-android}/src/androidTest/java/org/mifospay/ExampleInstrumentedTest.kt (100%) rename {mifospay => mifospay-android}/src/main/AndroidManifest.xml (94%) create mode 100644 mifospay-android/src/main/kotlin/org/mifospay/MainActivity.kt rename shared/src/androidMain/kotlin/org/mifospay/shared/MyApplication.kt => mifospay-android/src/main/kotlin/org/mifospay/MifosPayApp.kt (58%) rename {mifospay/src/main/java => mifospay-android/src/main/kotlin}/org/mifospay/data/firebase/api/services/MifosPayMessagingService.kt (100%) rename {mifospay/src/main/java => mifospay-android/src/main/kotlin}/org/mifospay/utils/NotificationUtils.kt (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/bg_splash.xml (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/bg_splash_12.xml (100%) create mode 100644 mifospay-android/src/main/res/drawable/feature_accounts_ic_bank.xml create mode 100644 mifospay-android/src/main/res/drawable/feature_receipt_mifospay_round_logo.png rename {mifospay => mifospay-android}/src/main/res/drawable/ic_finance.xml (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/ic_home.xml (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/ic_person.xml (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/ic_swap_horiz.xml (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/logo_axis.png (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/logo_hdfc.png (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/logo_icici.png (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/logo_pnb.png (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/logo_rbl.png (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/logo_sbi.png (100%) create mode 100644 mifospay-android/src/main/res/drawable/mifospay_round_logo.png rename {mifospay => mifospay-android}/src/main/res/drawable/money_in.png (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/money_out.png (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/splash_icon.png (100%) rename {mifospay => mifospay-android}/src/main/res/drawable/splash_screen_background.xml (100%) rename {mifospay => mifospay-android}/src/main/res/mipmap/ic_launcher.png (100%) rename {mifospay => mifospay-android}/src/main/res/mipmap/ic_launcher_round.png (100%) rename {mifospay => mifospay-android}/src/main/res/values/colors.xml (100%) rename {mifospay => mifospay-android}/src/main/res/values/splash.xml (100%) rename {mifospay => mifospay-android}/src/main/res/values/strings.xml (100%) rename {mifospay => mifospay-android}/src/main/res/xml/provider_paths.xml (100%) rename {mifospay => mifospay-android}/src/test/java/org/mifospay/KoinModulesCheck.kt (100%) create mode 100644 mifospay-desktop/.gitignore create mode 100644 mifospay-desktop/README.md rename {desktop => mifospay-desktop}/build.gradle.kts (69%) rename desktop/src/jvmMain/kotlin/Main.kt => mifospay-desktop/src/desktopMain/kotlin/main.kt (90%) rename {iosApp => mifospay-ios}/iosApp.xcodeproj/project.pbxproj (100%) rename {iosApp => mifospay-ios}/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename {iosApp => mifospay-ios}/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename {iosApp => mifospay-ios}/iosApp.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate (100%) rename {iosApp => mifospay-ios}/iosApp.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist (100%) rename {iosApp => mifospay-ios}/iosApp.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/iosApp.xcscheme (100%) rename {iosApp => mifospay-ios}/iosApp.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist (100%) rename {iosApp => mifospay-ios}/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename {iosApp => mifospay-ios}/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {iosApp => mifospay-ios}/iosApp/Assets.xcassets/Contents.json (100%) rename {iosApp => mifospay-ios}/iosApp/ContentView.swift (93%) rename {iosApp => mifospay-ios}/iosApp/Preview Content/Preview Assets.xcassets/Contents.json (100%) rename {iosApp => mifospay-ios}/iosApp/iosAppApp.swift (92%) create mode 100644 mifospay-shared/build.gradle.kts create mode 100644 mifospay-shared/src/commonMain/composeResources/values/strings.xml create mode 100644 mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt rename mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt => mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt (54%) create mode 100644 mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt rename {mifospay/src/main/java/org/mifospay => mifospay-shared/src/commonMain/kotlin/org/mifospay/shared}/navigation/LoginNavGraph.kt (55%) rename {mifospay/src/main/java/org/mifospay => mifospay-shared/src/commonMain/kotlin/org/mifospay/shared}/navigation/MifosNavGraph.kt (93%) create mode 100644 mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavHost.kt rename {mifospay/src/main/java/org/mifospay => mifospay-shared/src/commonMain/kotlin/org/mifospay/shared}/navigation/RootNavGraph.kt (87%) rename {mifospay/src/main/java/org/mifospay => mifospay-shared/src/commonMain/kotlin/org/mifospay/shared}/ui/MifosApp.kt (72%) rename {mifospay/src/main/java/org/mifospay => mifospay-shared/src/commonMain/kotlin/org/mifospay/shared}/ui/MifosAppState.kt (57%) rename {mifospay/src/main/java/org/mifospay/navigation => mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/utils}/TopLevelDestination.kt (57%) create mode 100644 mifospay-web/.gitignore create mode 100644 mifospay-web/README.md create mode 100644 mifospay-web/build.gradle.kts create mode 100644 mifospay-web/src/jsMain/kotlin/Application.kt create mode 100644 mifospay-web/src/jsMain/resources/index.html create mode 100644 mifospay-web/src/jsMain/resources/styles.css create mode 100644 mifospay-web/src/wasmJsMain/kotlin/Main.kt create mode 100644 mifospay-web/src/wasmJsMain/resources/index.html create mode 100644 mifospay-web/src/wasmJsMain/resources/load.mjs delete mode 100644 mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt delete mode 100644 mifospay/src/main/java/org/mifospay/MainActivity.kt delete mode 100644 mifospay/src/main/java/org/mifospay/MifosPayApp.kt delete mode 100644 mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt delete mode 100644 mifospay/src/main/java/org/mifospay/di/KoinModules.kt delete mode 100644 mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt delete mode 100644 mifospay/src/main/java/org/mifospay/navigation/PasscodeNavGraph.kt delete mode 100644 shared/build.gradle.kts delete mode 100644 shared/src/androidMain/kotlin/org/mifospay/shared/MainActivity.kt delete mode 100644 shared/src/androidMain/kotlin/org/mifospay/shared/Platform.android.kt delete mode 100644 shared/src/androidMain/kotlin/org/mifospay/shared/di/AndroidPlatformContextProvider.kt delete mode 100644 shared/src/androidMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.android.kt delete mode 100644 shared/src/commonMain/kotlin/org/mifospay/shared/App.kt delete mode 100644 shared/src/commonMain/kotlin/org/mifospay/shared/Platform.kt delete mode 100644 shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Client.kt delete mode 100644 shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/User.kt delete mode 100644 shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/UserData.kt delete mode 100644 shared/src/commonMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.kt delete mode 100644 shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceRepository.kt delete mode 100644 shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceSerializer.kt delete mode 100644 shared/src/commonMain/proto/user_preferences.proto delete mode 100644 shared/src/desktopMain/kotlin/org/mifospay/shared/Platform.desktop.kt delete mode 100644 shared/src/desktopMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.desktop.kt delete mode 100644 shared/src/iosMain/kotlin/org/mifospay/shared/MainViewController.kt delete mode 100644 shared/src/iosMain/kotlin/org/mifospay/shared/Platform.ios.kt delete mode 100644 shared/src/iosMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.ios.kt diff --git a/.github/workflows/feature_branch_ci.yml b/.github/workflows/feature_branch_ci.yml deleted file mode 100644 index 64dffd00a..000000000 --- a/.github/workflows/feature_branch_ci.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Mobile-Wallet CI[Feature] - -on: - push: - branches: - - '*' - - '!dev' - - '!master' -jobs: - build: - name: Build APK - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - # Set up JDK - - name: Set Up JDK 17 - uses: actions/setup-java@v1 - with: - java-version: 17 - - # Install NDK - - name: Install NDK - run: echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;20.0.5594570" --sdk_root=${ANDROID_SDK_ROOT} - - # Update Gradle Permission - - name: Change gradlew Permission - run: chmod +x gradlew - - # Build App - - name: Build with Gradle - run: ./gradlew assemble diff --git a/.github/workflows/master_dev_ci.yml b/.github/workflows/master_dev_ci.yml index 88fe178ef..ba41c9883 100644 --- a/.github/workflows/master_dev_ci.yml +++ b/.github/workflows/master_dev_ci.yml @@ -75,7 +75,7 @@ jobs: - name: Check Dependency Guard id: dependencyguard_verify continue-on-error: true - run: ./gradlew dependencyGuard + run: ./gradlew :mifospay-android:dependencyGuard - name: Prevent updating Dependency Guard baselines if this is a fork id: checkfork_dependencyguard @@ -88,7 +88,7 @@ jobs: id: dependencyguard_baseline if: steps.dependencyguard_verify.outcome == 'failure' && github.event_name == 'pull_request' run: | - ./gradlew dependencyGuardBaseline + ./gradlew :mifospay-android:dependencyGuardBaseline - name: Push new Dependency Guard baselines if available uses: stefanzweifel/git-auto-commit-action@v5 @@ -109,7 +109,8 @@ jobs: java-version: 17 - name: Run tests run: | - ./gradlew testDemoDebug :lint:test :mifospay:lintProdRelease :lint:lint + ./gradlew :mifospay-android:testDemoDebug +# ./gradlew testDemoDebug :lint:test :mifospay-android:lintProdRelease :lint:lint - name: Upload reports if: always() uses: actions/upload-artifact@v4 @@ -130,12 +131,12 @@ jobs: java-version: 17 - name: Build APKs - run: ./gradlew :mifospay:assembleDemoDebug + run: ./gradlew :mifospay-android:assembleDemoDebug - name: Check badging # This step is allowed to fail, as it's not critical for the build continue-on-error: true - run: ./gradlew :mifospay:checkProdReleaseBadging + run: ./gradlew :mifospay-android:checkProdReleaseBadging - name: Upload APKs uses: actions/upload-artifact@v4 diff --git a/.run/mifospay-android.run.xml b/.run/mifospay-android.run.xml new file mode 100644 index 000000000..2b81165ce --- /dev/null +++ b/.run/mifospay-android.run.xml @@ -0,0 +1,70 @@ + + + + + \ No newline at end of file diff --git a/.run/mifospay-desktop.run.xml b/.run/mifospay-desktop.run.xml new file mode 100644 index 000000000..6044007fa --- /dev/null +++ b/.run/mifospay-desktop.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/mifospay-web-js.run.xml b/.run/mifospay-web-js.run.xml new file mode 100644 index 000000000..d6b902502 --- /dev/null +++ b/.run/mifospay-web-js.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/mifospay-web-wasm.run.xml b/.run/mifospay-web-wasm.run.xml new file mode 100644 index 000000000..6bdae484b --- /dev/null +++ b/.run/mifospay-web-wasm.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt index c57ee23b3..f4f34d30a 100644 --- a/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt @@ -9,7 +9,7 @@ class CMPFeatureConventionPlugin : Plugin { with(target) { pluginManager.apply { apply("mifospay.kmp.library") - apply("mifospay.kmp.inject") + apply("mifospay.kmp.koin") apply("org.jetbrains.kotlin.plugin.compose") apply("org.jetbrains.compose") } @@ -18,11 +18,15 @@ class CMPFeatureConventionPlugin : Plugin { add("commonMainImplementation", project(":core:ui")) add("commonMainImplementation", project(":core:designsystem")) add("commonMainImplementation", project(":core:data")) - add("commonMainImplementation", libs.findLibrary("jetbrains.compose.viewmodel").get()) - add("commonMainImplementation", libs.findLibrary("jetbrains.compose.navigation").get()) - add("commonMainImplementation", libs.findLibrary("kotlinx.collections.immutable").get()) - add("androidMainImplementation", project(":libs:material3-navigation")) + add("commonMainImplementation", libs.findLibrary("jb.composeRuntime").get()) + add("commonMainImplementation", libs.findLibrary("jb.composeViewmodel").get()) + add("commonMainImplementation", libs.findLibrary("jb.lifecycleViewmodel").get()) + add("commonMainImplementation", libs.findLibrary("jb.lifecycleViewmodelSavedState").get()) + add("commonMainImplementation", libs.findLibrary("jb.savedstate").get()) + add("commonMainImplementation", libs.findLibrary("jb.bundle").get()) + add("commonMainImplementation", libs.findLibrary("jb.composeNavigation").get()) + add("commonMainImplementation", libs.findLibrary("kotlinx.collections.immutable").get()) add("androidMainImplementation", libs.findLibrary("androidx.lifecycle.runtimeCompose").get()) add("androidMainImplementation", libs.findLibrary("androidx.lifecycle.viewModelCompose").get()) @@ -39,15 +43,9 @@ class CMPFeatureConventionPlugin : Plugin { add("androidTestImplementation", libs.findLibrary("koin.test.junit4").get()) - add("androidDebugImplementation", libs.findLibrary("androidx.compose.ui.test.manifest").get()) add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.navigation.testing").get()) add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.compose.ui.test").get()) add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.lifecycle.runtimeTesting").get()) - add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.core").get()) - add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.ext").get()) - add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.junit").get()) - add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.runner").get()) - add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.espresso.core").get()) } } } diff --git a/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt index ca6cf9a78..f529f6e72 100644 --- a/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt @@ -20,7 +20,7 @@ class KMPKoinConventionPlugin : Plugin { add("commonMainImplementation", libs.findLibrary("koin.annotations").get()) add("kspCommonMainMetadata", libs.findLibrary("koin.ksp.compiler").get()) - add("ksp", libs.findLibrary("koin.ksp.compiler").get()) +// add("kspAndroid", libs.findLibrary("koin.ksp.compiler").get()) // add("kspWasmJs", libs.findLibrary("koin.ksp.compiler").get()) // add("kspJvm", libs.findLibrary("koin.ksp.compiler").get()) // add("kspIosX64", libs.findLibrary("koin.ksp.compiler").get()) @@ -32,8 +32,6 @@ class KMPKoinConventionPlugin : Plugin { extensions.configure { arg("KOIN_CONFIG_CHECK","true") - arg("USE_COMPOSE_VIEWMODEL", "false") - arg("KOIN_USE_COMPOSE_VIEWMODEL", "true") } } } diff --git a/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt index 8f2e00185..23d0a8913 100644 --- a/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt @@ -28,7 +28,11 @@ class KMPLibraryConventionPlugin: Plugin { configureFlavors(this) // The resource prefix is derived from the module name, // so resources inside ":core:module1" must be prefixed with "core_module1_" - resourcePrefix = path.split("""\W""".toRegex()).drop(1).distinct().joinToString(separator = "_").lowercase() + "_" + resourcePrefix = path + .split("""\W""".toRegex()) + .drop(1).distinct() + .joinToString(separator = "_") + .lowercase() + "_" } dependencies { diff --git a/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt index cb89515b6..8d7583134 100644 --- a/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt @@ -20,7 +20,7 @@ class KotlinInjectConventionPlugin: Plugin { add("kspIosSimulatorArm64", libs.findLibrary("kotlin.inject.compiler.ksp").get()) // add("kspWasmJs", libs.findLibrary("kotlin.inject.compiler.ksp").get()) add("kspAndroid", libs.findLibrary("kotlin.inject.compiler.ksp").get()) - add("kspJvm", libs.findLibrary("kotlin.inject.compiler.ksp").get()) + add("kspDesktop", libs.findLibrary("kotlin.inject.compiler.ksp").get()) } } } diff --git a/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt b/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt index 9d6ee74bf..755cc0009 100644 --- a/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt +++ b/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt @@ -9,12 +9,19 @@ internal fun Project.configureKotlinMultiplatform() { extensions.configure { applyDefaultHierarchyTemplate() - jvm() + jvm("desktop") androidTarget() iosSimulatorArm64() iosX64() iosArm64() - + js(IR) { + this.nodejs() + binaries.executable() + } + wasmJs() { + browser() + nodejs() + } // Suppress 'expect'/'actual' classes are in Beta. targets.configureEach { compilations.configureEach { diff --git a/ci-prepush.bat b/ci-prepush.bat index 60ffba915..49298e3e7 100644 --- a/ci-prepush.bat +++ b/ci-prepush.bat @@ -12,11 +12,9 @@ echo Starting all checks and tests... call :run_gradle_task "check -p build-logic" call :run_gradle_task "spotlessApply --no-configuration-cache" call :run_gradle_task "dependencyGuardBaseline" -call :run_gradle_task "formatVersionCatalog" call :run_gradle_task "detekt" -call :run_gradle_task "testDemoDebug :lint:test :mifospay:lintProdRelease :lint:lint" -call :run_gradle_task "build" -call :run_gradle_task "updateProdReleaseBadging" +call :run_gradle_task ":mifospay-android:build" +call :run_gradle_task ":mifospay-android:updateProdReleaseBadging" echo All checks and tests completed successfully. exit /b 0 diff --git a/ci-prepush.sh b/ci-prepush.sh index 95cc04913..6689fd494 100644 --- a/ci-prepush.sh +++ b/ci-prepush.sh @@ -28,10 +28,8 @@ tasks=( "spotlessApply --no-configuration-cache" "dependencyGuardBaseline" "detekt" - "formatVersionCatalog" - "testDemoDebug :lint:test :lint:lint :mifospay:lintProdRelease" - "build" - "updateProdReleaseBadging" + ":mifospay-android:build" + ":mifospay-android:updateProdReleaseBadging" ) for task in "${tasks[@]}"; do diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index bc93c368a..58ae08079 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -9,6 +9,7 @@ */ plugins { alias(libs.plugins.mifospay.kmp.library) + alias(libs.plugins.kotlin.parcelize) } android { @@ -20,7 +21,7 @@ kotlin { listOf( iosX64(), iosArm64(), - iosSimulatorArm64() + iosSimulatorArm64(), ).forEach { it.binaries.framework { isStatic = false @@ -37,7 +38,9 @@ kotlin { api(libs.coil.network.ktor) api(libs.kermit.logging) api(libs.squareup.okio) + api(libs.jb.kotlin.stdlib) } + androidMain.dependencies { implementation(libs.kotlinx.coroutines.android) } @@ -47,5 +50,13 @@ kotlin { iosMain.dependencies { api(libs.kermit.simple) } + desktopMain.dependencies { + implementation(libs.kotlinx.coroutines.swing) + implementation(libs.kotlin.reflect) + } + jsMain.dependencies { + api(libs.jb.kotlin.stdlib.js) + api(libs.jb.kotlin.dom) + } } } \ No newline at end of file diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/common/Parcelize.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/common/Parcelize.kt new file mode 100644 index 000000000..d76561bc8 --- /dev/null +++ b/core/common/src/androidMain/kotlin/org/mifospay/core/common/Parcelize.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +import android.os.Parcel +import android.os.Parcelable +import kotlinx.parcelize.IgnoredOnParcel +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize +import kotlinx.parcelize.TypeParceler + +actual typealias Parcelize = Parcelize + +actual typealias Parcelable = Parcelable + +actual typealias IgnoredOnParcel = IgnoredOnParcel + +actual typealias Parceler

= Parceler

+ +actual typealias TypeParceler = TypeParceler + +actual typealias Parcel = Parcel diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/common/di/DispatchersModule.android.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/common/di/DispatchersModule.android.kt new file mode 100644 index 000000000..f7f54ce0c --- /dev/null +++ b/core/common/src/androidMain/kotlin/org/mifospay/core/common/di/DispatchersModule.android.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common.di + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import org.koin.core.module.Module +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.common.MifosDispatchers + +actual val ioDispatcherModule: Module + get() = module { + single(named(MifosDispatchers.IO.name)) { Dispatchers.IO } + } diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt index 26b62d47f..3bb4cdfe1 100644 --- a/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/FileUtils.kt @@ -12,9 +12,6 @@ package org.mifospay.core.common import co.touchlab.kermit.Logger import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import okio.FileSystem -import okio.Path.Companion.toPath -import okio.SYSTEM interface FileUtils { suspend fun writeInputStreamDataToFile(inputStream: ByteArray, filePath: String): Boolean @@ -33,11 +30,6 @@ class CommonFileUtils : FileUtils { ): Boolean = withContext(Dispatchers.Default) { try { - val path = filePath.toPath() - FileSystem.SYSTEM.write(path) { - write(inputStream) - } - true } catch (e: Exception) { FileUtils.logger.e { "Error writing file: ${e.message}" } diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/MifosDispatchers.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/MifosDispatchers.kt index c692ec1bc..7f3002ba5 100644 --- a/core/common/src/commonMain/kotlin/org/mifospay/core/common/MifosDispatchers.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/MifosDispatchers.kt @@ -18,6 +18,7 @@ annotation class Dispatcher(val mifosDispatcher: MifosDispatchers) enum class MifosDispatchers { Default, IO, + Unconfined, } @Qualifier diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/Parcelize.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Parcelize.kt new file mode 100644 index 000000000..576822cb7 --- /dev/null +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/Parcelize.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +expect annotation class Parcelize() + +expect interface Parcelable + +expect annotation class IgnoredOnParcel() + +expect interface Parceler

{ + fun create(parcel: Parcel): P + + fun P.write(parcel: Parcel, flags: Int) +} + +expect annotation class TypeParceler>() + +expect class Parcel { + fun readByte(): Byte + fun readInt(): Int + + fun readFloat(): Float + fun readDouble(): Double + fun readString(): String? + + fun writeByte(value: Byte) + fun writeInt(value: Int) + + fun writeFloat(value: Float) + + fun writeDouble(value: Double) + fun writeString(value: String?) +} diff --git a/core/common/src/commonMain/kotlin/org/mifospay/core/common/di/DispatchersModule.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/di/DispatchersModule.kt index a41d60920..4bf17cc0c 100644 --- a/core/common/src/commonMain/kotlin/org/mifospay/core/common/di/DispatchersModule.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/di/DispatchersModule.kt @@ -12,16 +12,19 @@ package org.mifospay.core.common.di import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.IO import kotlinx.coroutines.SupervisorJob +import org.koin.core.module.Module import org.koin.core.qualifier.named import org.koin.dsl.module import org.mifospay.core.common.MifosDispatchers val DispatchersModule = module { - single(named(MifosDispatchers.IO.name)) { Dispatchers.IO } + includes(ioDispatcherModule) single(named(MifosDispatchers.Default.name)) { Dispatchers.Default } + single(named(MifosDispatchers.Unconfined.name)) { Dispatchers.Unconfined } single(named("ApplicationScope")) { CoroutineScope(SupervisorJob() + Dispatchers.Default) } } + +expect val ioDispatcherModule: Module diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/Greeting.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/utils/StringExtensions.kt similarity index 60% rename from shared/src/commonMain/kotlin/org/mifospay/shared/Greeting.kt rename to core/common/src/commonMain/kotlin/org/mifospay/core/common/utils/StringExtensions.kt index 8f97567fd..6daf487b2 100644 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/Greeting.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/utils/StringExtensions.kt @@ -7,12 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared +package org.mifospay.core.common.utils -class Greeting { - private val platform: Platform = getPlatform() - - fun greet(): String { - return "Hello, ${platform.name}!" - } -} +/** + * Whether or not string is a valid email address. + * + * This just checks if the string contains the "@" symbol. + */ +fun String.isValidEmail(): Boolean = contains("@") diff --git a/core/common/src/jvmMain/kotlin/org/mifospay/core/common/CurrencyFormatter.jvm.kt b/core/common/src/desktopMain/kotlin/org/mifospay/core/common/CurrencyFormatter.jvm.kt similarity index 100% rename from core/common/src/jvmMain/kotlin/org/mifospay/core/common/CurrencyFormatter.jvm.kt rename to core/common/src/desktopMain/kotlin/org/mifospay/core/common/CurrencyFormatter.jvm.kt diff --git a/core/common/src/jvmMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt b/core/common/src/desktopMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt similarity index 100% rename from core/common/src/jvmMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt rename to core/common/src/desktopMain/kotlin/org/mifospay/core/common/FileUtils.jvm.kt diff --git a/core/common/src/desktopMain/kotlin/org/mifospay/core/common/Parcelize.kt b/core/common/src/desktopMain/kotlin/org/mifospay/core/common/Parcelize.kt new file mode 100644 index 000000000..addff633c --- /dev/null +++ b/core/common/src/desktopMain/kotlin/org/mifospay/core/common/Parcelize.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +actual interface Parcelable +actual annotation class IgnoredOnParcel +actual annotation class Parcelize +actual interface Parceler

{ + actual fun create(parcel: Parcel): P + actual fun P.write(parcel: Parcel, flags: Int) +} + +actual annotation class TypeParceler> + +actual class Parcel { + actual fun readString(): String? = null + actual fun readByte(): Byte = 1 + + actual fun readInt(): Int = 1 + + actual fun readFloat(): Float = 1f + + actual fun readDouble(): Double = 1.0 + + actual fun writeByte(value: Byte) { + } + + actual fun writeInt(value: Int) { + } + + actual fun writeFloat(value: Float) { + } + + actual fun writeDouble(value: Double) { + } + + actual fun writeString(value: String?) { + } +} diff --git a/core/common/src/desktopMain/kotlin/org/mifospay/core/common/di/DispatchersModule.desktop.kt b/core/common/src/desktopMain/kotlin/org/mifospay/core/common/di/DispatchersModule.desktop.kt new file mode 100644 index 000000000..52d18ff45 --- /dev/null +++ b/core/common/src/desktopMain/kotlin/org/mifospay/core/common/di/DispatchersModule.desktop.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common.di + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import org.koin.core.module.Module +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.common.MifosDispatchers + +actual val ioDispatcherModule: Module + get() = module { + single(named(MifosDispatchers.IO.name)) { Dispatchers.Default } + } diff --git a/core/common/src/jsMain/kotlin/org/mifospay/core/common/CurrencyFormatter.js.kt b/core/common/src/jsMain/kotlin/org/mifospay/core/common/CurrencyFormatter.js.kt new file mode 100644 index 000000000..54fbc2601 --- /dev/null +++ b/core/common/src/jsMain/kotlin/org/mifospay/core/common/CurrencyFormatter.js.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +actual object CurrencyFormatter { + actual fun format( + balance: Double?, + currencyCode: String?, + maximumFractionDigits: Int?, + ): String { + if (balance == null || currencyCode == null) { + return "" + } + + val options = js("{}").unsafeCast() + options.style = "currency" + options.currency = currencyCode + if (maximumFractionDigits != null) { + options.maximumFractionDigits = maximumFractionDigits + } + + return try { + js("new Intl.NumberFormat('en-US', options).format(balance)").toString() + } catch (e: Exception) { + console.error("Error formatting currency: ${e.message}") + balance.toString() + } + } +} diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/di/Modules.android.kt b/core/common/src/jsMain/kotlin/org/mifospay/core/common/FileUtils.js.kt similarity index 76% rename from shared/src/androidMain/kotlin/org/mifospay/shared/di/Modules.android.kt rename to core/common/src/jsMain/kotlin/org/mifospay/core/common/FileUtils.js.kt index 8d463b4df..018f0cd7d 100644 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/di/Modules.android.kt +++ b/core/common/src/jsMain/kotlin/org/mifospay/core/common/FileUtils.js.kt @@ -7,9 +7,6 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared.di +package org.mifospay.core.common -import org.koin.dsl.module - -actual val platformModule = module { -} +actual fun createPlatformFileUtils(): FileUtils = CommonFileUtils() diff --git a/core/common/src/jsMain/kotlin/org/mifospay/core/common/Parcelize.kt b/core/common/src/jsMain/kotlin/org/mifospay/core/common/Parcelize.kt new file mode 100644 index 000000000..addff633c --- /dev/null +++ b/core/common/src/jsMain/kotlin/org/mifospay/core/common/Parcelize.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +actual interface Parcelable +actual annotation class IgnoredOnParcel +actual annotation class Parcelize +actual interface Parceler

{ + actual fun create(parcel: Parcel): P + actual fun P.write(parcel: Parcel, flags: Int) +} + +actual annotation class TypeParceler> + +actual class Parcel { + actual fun readString(): String? = null + actual fun readByte(): Byte = 1 + + actual fun readInt(): Int = 1 + + actual fun readFloat(): Float = 1f + + actual fun readDouble(): Double = 1.0 + + actual fun writeByte(value: Byte) { + } + + actual fun writeInt(value: Int) { + } + + actual fun writeFloat(value: Float) { + } + + actual fun writeDouble(value: Double) { + } + + actual fun writeString(value: String?) { + } +} diff --git a/core/common/src/jsMain/kotlin/org/mifospay/core/common/di/DispatchersModule.js.kt b/core/common/src/jsMain/kotlin/org/mifospay/core/common/di/DispatchersModule.js.kt new file mode 100644 index 000000000..52d18ff45 --- /dev/null +++ b/core/common/src/jsMain/kotlin/org/mifospay/core/common/di/DispatchersModule.js.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common.di + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import org.koin.core.module.Module +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.common.MifosDispatchers + +actual val ioDispatcherModule: Module + get() = module { + single(named(MifosDispatchers.IO.name)) { Dispatchers.Default } + } diff --git a/core/common/src/nativeMain/kotlin/org/mifospay/core/common/Parcelize.kt b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/Parcelize.kt new file mode 100644 index 000000000..addff633c --- /dev/null +++ b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/Parcelize.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +actual interface Parcelable +actual annotation class IgnoredOnParcel +actual annotation class Parcelize +actual interface Parceler

{ + actual fun create(parcel: Parcel): P + actual fun P.write(parcel: Parcel, flags: Int) +} + +actual annotation class TypeParceler> + +actual class Parcel { + actual fun readString(): String? = null + actual fun readByte(): Byte = 1 + + actual fun readInt(): Int = 1 + + actual fun readFloat(): Float = 1f + + actual fun readDouble(): Double = 1.0 + + actual fun writeByte(value: Byte) { + } + + actual fun writeInt(value: Int) { + } + + actual fun writeFloat(value: Float) { + } + + actual fun writeDouble(value: Double) { + } + + actual fun writeString(value: String?) { + } +} diff --git a/core/common/src/nativeMain/kotlin/org/mifospay/core/common/di/DispatchersModule.native.kt b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/di/DispatchersModule.native.kt new file mode 100644 index 000000000..52d18ff45 --- /dev/null +++ b/core/common/src/nativeMain/kotlin/org/mifospay/core/common/di/DispatchersModule.native.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common.di + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import org.koin.core.module.Module +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.common.MifosDispatchers + +actual val ioDispatcherModule: Module + get() = module { + single(named(MifosDispatchers.IO.name)) { Dispatchers.Default } + } diff --git a/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/CurrencyFormatter.js.kt b/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/CurrencyFormatter.js.kt new file mode 100644 index 000000000..21d949d99 --- /dev/null +++ b/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/CurrencyFormatter.js.kt @@ -0,0 +1,35 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +actual object CurrencyFormatter { + actual fun format( + balance: Double?, + currencyCode: String?, + maximumFractionDigits: Int?, + ): String { + return "$currencyCode ${ + balance?.let { + val formattedBalance = balance.toString() + val fractionDigits = formattedBalance.substringAfterLast(".") + val fractionDigitsLength = fractionDigits.length + val fractionDigitsToDisplay = if (fractionDigitsLength > maximumFractionDigits!!) { + fractionDigits.substring(0, maximumFractionDigits) + } else { + fractionDigits + } + val integerDigits = formattedBalance.substringBeforeLast(".") + val integerDigitsWithCommas = + integerDigits.reversed().chunked(3).joinToString(",").reversed() + "$integerDigitsWithCommas.$fractionDigitsToDisplay" + } ?: "0.00" + }" + } +} diff --git a/shared/src/desktopMain/kotlin/org/mifospay/shared/di/Modules.desktop.kt b/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/FileUtils.js.kt similarity index 66% rename from shared/src/desktopMain/kotlin/org/mifospay/shared/di/Modules.desktop.kt rename to core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/FileUtils.js.kt index d861dacc2..018f0cd7d 100644 --- a/shared/src/desktopMain/kotlin/org/mifospay/shared/di/Modules.desktop.kt +++ b/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/FileUtils.js.kt @@ -7,10 +7,6 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared.di +package org.mifospay.core.common -import org.koin.core.module.Module -import org.koin.dsl.module - -actual val platformModule: Module - get() = module { single {} } +actual fun createPlatformFileUtils(): FileUtils = CommonFileUtils() diff --git a/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/Parcelize.kt b/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/Parcelize.kt new file mode 100644 index 000000000..addff633c --- /dev/null +++ b/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/Parcelize.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +actual interface Parcelable +actual annotation class IgnoredOnParcel +actual annotation class Parcelize +actual interface Parceler

{ + actual fun create(parcel: Parcel): P + actual fun P.write(parcel: Parcel, flags: Int) +} + +actual annotation class TypeParceler> + +actual class Parcel { + actual fun readString(): String? = null + actual fun readByte(): Byte = 1 + + actual fun readInt(): Int = 1 + + actual fun readFloat(): Float = 1f + + actual fun readDouble(): Double = 1.0 + + actual fun writeByte(value: Byte) { + } + + actual fun writeInt(value: Int) { + } + + actual fun writeFloat(value: Float) { + } + + actual fun writeDouble(value: Double) { + } + + actual fun writeString(value: String?) { + } +} diff --git a/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/di/DispatchersModule.js.kt b/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/di/DispatchersModule.js.kt new file mode 100644 index 000000000..52d18ff45 --- /dev/null +++ b/core/common/src/wasmJsMain/kotlin/org/mifospay/core/common/di/DispatchersModule.js.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common.di + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import org.koin.core.module.Module +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.common.MifosDispatchers + +actual val ioDispatcherModule: Module + get() = module { + single(named(MifosDispatchers.IO.name)) { Dispatchers.Default } + } diff --git a/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformDependentDataModule.kt b/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformDependentDataModule.kt index 8d825d28b..3aeddba79 100644 --- a/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformDependentDataModule.kt +++ b/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformDependentDataModule.kt @@ -21,12 +21,12 @@ class AndroidPlatformDependentDataModule( private val context: Context, private val dispatcher: CoroutineDispatcher, private val scope: CoroutineScope, -) : PlatformDependentDataModule() { - override fun bindsNetworkMonitor(): NetworkMonitor { - return ConnectivityManagerNetworkMonitor(context, dispatcher) +) : PlatformDependentDataModule { + override val networkMonitor: NetworkMonitor by lazy { + ConnectivityManagerNetworkMonitor(context, dispatcher) } - override fun bindsTimeZoneMonitor(): TimeZoneMonitor { - return TimeZoneBroadcastMonitor(context, scope, dispatcher) + override val timeZoneMonitor: TimeZoneMonitor by lazy { + TimeZoneBroadcastMonitor(context, scope, dispatcher) } } diff --git a/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformModule.kt b/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformModule.kt index f975f2d91..1a45dea18 100644 --- a/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformModule.kt +++ b/core/data/src/androidMain/kotlin/org/mifospay/core/data/di/AndroidPlatformModule.kt @@ -10,6 +10,7 @@ package org.mifospay.core.data.di import org.koin.android.ext.koin.androidContext +import org.koin.core.module.Module import org.koin.core.qualifier.named import org.koin.dsl.module import org.mifospay.core.common.MifosDispatchers @@ -18,7 +19,7 @@ import org.mifospay.core.data.util.NetworkMonitor import org.mifospay.core.data.util.TimeZoneBroadcastMonitor import org.mifospay.core.data.util.TimeZoneMonitor -val androidDataModule = module { +val AndroidDataModule = module { single { ConnectivityManagerNetworkMonitor(androidContext(), get(named(MifosDispatchers.IO.name))) } @@ -39,3 +40,8 @@ val androidDataModule = module { ) } } + +actual val platformModule: Module = AndroidDataModule + +actual val getPlatformDataModule: PlatformDependentDataModule + get() = org.koin.core.context.GlobalContext.get().get() diff --git a/core/data/src/androidMain/kotlin/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt b/core/data/src/androidMain/kotlin/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt deleted file mode 100644 index db17053e7..000000000 --- a/core/data/src/androidMain/kotlin/org/mifospay/core/data/util/ErrorJsonMessageHelper.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.data.util - -import org.json.JSONException -import org.json.JSONObject -import retrofit2.HttpException - -object ErrorJsonMessageHelper { - @JvmStatic - @Throws(JSONException::class) - fun getUserMessage(message: String?): String { - val jsonObject = JSONObject(message) - return jsonObject.getJSONArray("errors") - .getJSONObject(0).getString("defaultUserMessage") - } - - @JvmStatic - fun getUserMessage(e: Throwable): String? { - var message: String? - try { - message = (e as HttpException).response()?.errorBody()?.string().toString() - message = getUserMessage(message) - } catch (e1: Exception) { - message = e1.message.toString() - } - return message - } -} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.kt index 0a635a1f7..7b2a0a087 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.kt @@ -9,11 +9,16 @@ */ package org.mifospay.core.data.di +import org.koin.core.module.Module import org.mifospay.core.data.util.NetworkMonitor import org.mifospay.core.data.util.TimeZoneMonitor -abstract class PlatformDependentDataModule { - abstract fun bindsNetworkMonitor(): NetworkMonitor +interface PlatformDependentDataModule { + val networkMonitor: NetworkMonitor - abstract fun bindsTimeZoneMonitor(): TimeZoneMonitor + val timeZoneMonitor: TimeZoneMonitor } + +expect val platformModule: Module + +expect val getPlatformDataModule: PlatformDependentDataModule diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/RepositoryModule.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/RepositoryModule.kt index c551d41d4..80064d7ed 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/RepositoryModule.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/di/RepositoryModule.kt @@ -48,14 +48,18 @@ import org.mifospay.core.data.repositoryImp.StandingInstructionRepositoryImpl import org.mifospay.core.data.repositoryImp.ThirdPartyTransferRepositoryImpl import org.mifospay.core.data.repositoryImp.TwoFactorAuthRepositoryImpl import org.mifospay.core.data.repositoryImp.UserRepositoryImpl +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneMonitor private val ioDispatcher = named(MifosDispatchers.IO.name) -val repositoryModule = module { +val RepositoryModule = module { single { AccountRepositoryImpl(get(), get(ioDispatcher)) } - single { AuthenticationRepositoryImpl(get(), get(ioDispatcher)) } + single { + AuthenticationRepositoryImpl(get(), get(ioDispatcher)) + } single { BeneficiaryRepositoryImpl(get(), get(ioDispatcher)) } - single { ClientRepositoryImpl(get(), get(ioDispatcher)) } + single { ClientRepositoryImpl(get(), get(), get(ioDispatcher)) } single { DocumentRepositoryImpl(get(), get(ioDispatcher)) } single { InvoiceRepositoryImpl(get(), get(ioDispatcher)) } single { KycLevelRepositoryImpl(get(), get(ioDispatcher)) } @@ -74,4 +78,9 @@ val repositoryModule = module { } single { TwoFactorAuthRepositoryImpl(get(), get(ioDispatcher)) } single { UserRepositoryImpl(get(), get(ioDispatcher)) } + + includes(platformModule) + single { getPlatformDataModule } + single { getPlatformDataModule.networkMonitor } + single { getPlatformDataModule.timeZoneMonitor } } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt index a8102a1db..a2c53f0fe 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt @@ -9,11 +9,9 @@ */ package org.mifospay.core.data.repository -import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result import org.mifospay.core.model.domain.user.User -import org.mifospay.core.model.entity.authentication.AuthenticationPayload interface AuthenticationRepository { - suspend fun authenticate(payload: AuthenticationPayload): Flow> + suspend fun authenticate(username: String, password: String): Result } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt index d21675c7b..de31cc9ec 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt @@ -18,16 +18,16 @@ import org.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate import org.mifospay.core.network.model.CommonResponse interface BeneficiaryRepository { - fun getBeneficiaryList(): Flow>> + suspend fun getBeneficiaryList(): Flow>> - fun getBeneficiaryTemplate(): Flow> + suspend fun getBeneficiaryTemplate(): Flow> - fun createBeneficiary(beneficiaryPayload: BeneficiaryPayload): Flow> + suspend fun createBeneficiary(beneficiaryPayload: BeneficiaryPayload): Flow> - fun updateBeneficiary( + suspend fun updateBeneficiary( beneficiaryId: Long, payload: BeneficiaryUpdatePayload, ): Flow> - fun deleteBeneficiary(beneficiaryId: Long): Flow> + suspend fun deleteBeneficiary(beneficiaryId: Long): Flow> } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt index a9657874e..b5481f0bd 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt @@ -15,12 +15,13 @@ import org.mifospay.core.model.domain.client.Client import org.mifospay.core.model.domain.client.NewClient import org.mifospay.core.model.entity.Page import org.mifospay.core.model.entity.client.ClientAccounts +import org.mifospay.core.network.model.ClientResponse interface ClientRepository { suspend fun getClients(): Flow>> - suspend fun getClient(clientId: Long): Flow> + suspend fun getClient(clientId: Long): Result suspend fun updateClient(clientId: Long, client: Client): Flow> @@ -32,5 +33,7 @@ interface ClientRepository { suspend fun getAccounts(clientId: Long, accountType: String): Flow> - suspend fun createClient(newClient: NewClient): Flow> + suspend fun createClient(newClient: NewClient): Result + + suspend fun deleteClient(clientId: Int): Result } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt index ec54d64b6..e524862d2 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt @@ -15,9 +15,9 @@ import org.mifospay.core.common.Result import org.mifospay.core.model.entity.noncore.Document interface DocumentRepository { - fun getDocuments(entityType: String, entityId: Int): Flow>> + suspend fun getDocuments(entityType: String, entityId: Int): Flow>> - fun createDocument( + suspend fun createDocument( entityType: String, entityId: Int, name: String, @@ -25,11 +25,11 @@ interface DocumentRepository { fileName: PartData.FileItem, ): Flow> - fun downloadDocument(entityType: String, entityId: Int, documentId: Int): Flow> + suspend fun downloadDocument(entityType: String, entityId: Int, documentId: Int): Flow> - fun deleteDocument(entityType: String, entityId: Int, documentId: Int): Flow> + suspend fun deleteDocument(entityType: String, entityId: Int, documentId: Int): Flow> - fun updateDocument( + suspend fun updateDocument( entityType: String, entityId: Int, documentId: Int, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt index bd7ee0656..1dfec0479 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt @@ -9,7 +9,6 @@ */ package org.mifospay.core.data.repository -import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result import org.mifospay.core.model.entity.SearchedEntity @@ -18,5 +17,5 @@ interface SearchRepository { query: String, resources: String, exactMatch: Boolean, - ): Flow>> + ): Result> } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt index 307bfad04..dc0c437ff 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt @@ -24,9 +24,9 @@ import org.mifospay.core.model.entity.client.ClientAccounts import org.mifospay.core.network.model.CommonResponse interface SelfServiceRepository { - suspend fun loginSelf(payload: AuthenticationPayload): Flow> + suspend fun loginSelf(payload: AuthenticationPayload): Result - suspend fun getSelfClientDetails(clientId: Long): Flow> + suspend fun getSelfClientDetails(clientId: Long): Result suspend fun getSelfClientDetails(): Flow>> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt index 6367b63b2..8cabf58e1 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt @@ -17,13 +17,15 @@ import org.mifospay.core.network.model.CommonResponse import org.mifospay.core.network.model.GenericResponse interface UserRepository { - fun getUsers(): Flow>> + suspend fun getUsers(): Flow>> - fun getUser(): Flow> + suspend fun getUser(): Flow> - fun createUser(newUser: NewUser): Flow> + suspend fun createUser(newUser: NewUser): Result - fun updateUser(userId: Int, updatedUser: NewUser): Flow> + suspend fun updateUser(userId: Int, updatedUser: NewUser): Flow> - fun deleteUser(userId: Int): Flow> + suspend fun deleteUser(userId: Int): Result + + suspend fun assignClientToUser(userId: Int, clientId: Int): Result } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt index ee6a28d0a..0a9ed9fa6 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt @@ -10,10 +10,8 @@ package org.mifospay.core.data.repositoryImp import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.withContext import org.mifospay.core.common.Result -import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.AuthenticationRepository import org.mifospay.core.model.domain.user.User import org.mifospay.core.model.entity.authentication.AuthenticationPayload @@ -23,7 +21,17 @@ class AuthenticationRepositoryImpl( private val apiManager: SelfServiceApiManager, private val ioDispatcher: CoroutineDispatcher, ) : AuthenticationRepository { - override suspend fun authenticate(payload: AuthenticationPayload): Flow> { - return apiManager.authenticationApi.authenticate(payload).asResult().flowOn(ioDispatcher) + override suspend fun authenticate(username: String, password: String): Result { + return try { + val payload = AuthenticationPayload(username, password) + + val result = withContext(ioDispatcher) { + apiManager.authenticationApi.authenticate(payload) + } + + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } } } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt index 66f88ba01..49e3e1a2c 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt @@ -26,15 +26,15 @@ class BeneficiaryRepositoryImpl( private val apiManager: SelfServiceApiManager, private val ioDispatcher: CoroutineDispatcher, ) : BeneficiaryRepository { - override fun getBeneficiaryList(): Flow>> { + override suspend fun getBeneficiaryList(): Flow>> { return apiManager.beneficiaryApi.beneficiaryList().asResult().flowOn(ioDispatcher) } - override fun getBeneficiaryTemplate(): Flow> { + override suspend fun getBeneficiaryTemplate(): Flow> { return apiManager.beneficiaryApi.beneficiaryTemplate().asResult().flowOn(ioDispatcher) } - override fun createBeneficiary( + override suspend fun createBeneficiary( beneficiaryPayload: BeneficiaryPayload, ): Flow> { return apiManager @@ -43,7 +43,7 @@ class BeneficiaryRepositoryImpl( .asResult().flowOn(ioDispatcher) } - override fun updateBeneficiary( + override suspend fun updateBeneficiary( beneficiaryId: Long, payload: BeneficiaryUpdatePayload, ): Flow> { @@ -52,7 +52,7 @@ class BeneficiaryRepositoryImpl( .asResult().flowOn(ioDispatcher) } - override fun deleteBeneficiary(beneficiaryId: Long): Flow> { + override suspend fun deleteBeneficiary(beneficiaryId: Long): Flow> { return apiManager.beneficiaryApi .deleteBeneficiary(beneficiaryId) .asResult().flowOn(ioDispatcher) diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt index c463bc478..62d0b01b4 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.mapper.toModel @@ -22,20 +23,25 @@ import org.mifospay.core.model.domain.client.NewClient import org.mifospay.core.model.entity.Page import org.mifospay.core.model.entity.client.ClientAccounts import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.SelfServiceApiManager +import org.mifospay.core.network.model.ClientResponse class ClientRepositoryImpl( - private val apiManager: FineractApiManager, + private val apiManager: SelfServiceApiManager, + private val fineractApiManager: FineractApiManager, private val ioDispatcher: CoroutineDispatcher, ) : ClientRepository { override suspend fun getClients(): Flow>> { return apiManager.clientsApi.clients().map { it.toModel() }.asResult().flowOn(ioDispatcher) } - override suspend fun getClient(clientId: Long): Flow> { - return apiManager.clientsApi - .getClientForId(clientId) - .map { it.toModel() } - .asResult().flowOn(ioDispatcher) + override suspend fun getClient(clientId: Long): Result { + return try { + val result = apiManager.clientsApi.getClientForId(clientId).toModel() + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } } override suspend fun updateClient(clientId: Long, client: Client): Flow> { @@ -69,10 +75,27 @@ class ClientRepositoryImpl( .asResult().flowOn(ioDispatcher) } - override suspend fun createClient(newClient: NewClient): Flow> { - return apiManager.clientsApi - .createClient(newClient) - .map { it.toModel() } - .asResult().flowOn(ioDispatcher) + override suspend fun createClient(newClient: NewClient): Result { + return try { + val result = withContext(ioDispatcher) { + fineractApiManager.clientsApi.createClient(newClient) + } + + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } + } + + override suspend fun deleteClient(clientId: Int): Result { + return try { + val result = withContext(ioDispatcher) { + fineractApiManager.clientsApi.deleteClient(clientId) + } + + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } } } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt index 38a51d15a..ec4108358 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt @@ -23,13 +23,13 @@ class DocumentRepositoryImpl( private val apiManager: FineractApiManager, private val ioDispatcher: CoroutineDispatcher, ) : DocumentRepository { - override fun getDocuments(entityType: String, entityId: Int): Flow>> { + override suspend fun getDocuments(entityType: String, entityId: Int): Flow>> { return apiManager.documentApi .getDocuments(entityType, entityId) .asResult().flowOn(ioDispatcher) } - override fun createDocument( + override suspend fun createDocument( entityType: String, entityId: Int, name: String, @@ -41,7 +41,7 @@ class DocumentRepositoryImpl( .asResult().flowOn(ioDispatcher) } - override fun downloadDocument( + override suspend fun downloadDocument( entityType: String, entityId: Int, documentId: Int, @@ -51,7 +51,7 @@ class DocumentRepositoryImpl( .asResult().flowOn(ioDispatcher) } - override fun deleteDocument( + override suspend fun deleteDocument( entityType: String, entityId: Int, documentId: Int, @@ -61,7 +61,7 @@ class DocumentRepositoryImpl( .asResult().flowOn(ioDispatcher) } - override fun updateDocument( + override suspend fun updateDocument( entityType: String, entityId: Int, documentId: Int, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt index fc2aa0571..93f5bd9c6 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt @@ -10,10 +10,8 @@ package org.mifospay.core.data.repositoryImp import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.withContext import org.mifospay.core.common.Result -import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.SearchRepository import org.mifospay.core.model.entity.SearchedEntity import org.mifospay.core.network.FineractApiManager @@ -26,9 +24,15 @@ class SearchRepositoryImpl( query: String, resources: String, exactMatch: Boolean, - ): Flow>> { - return apiManager.searchApi - .searchResources(query, resources, exactMatch) - .asResult().flowOn(ioDispatcher) + ): Result> { + return try { + val result = withContext(ioDispatcher) { + apiManager.searchApi.searchResources(query, resources, exactMatch) + } + + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } } } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt index 32d33bac5..66b287fd2 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt @@ -36,15 +36,24 @@ class SelfServiceRepositoryImpl( private val dispatcher: CoroutineDispatcher, ) : SelfServiceRepository { - override suspend fun loginSelf(payload: AuthenticationPayload): Flow> { - return apiManager.authenticationApi.authenticate(payload).asResult().flowOn(dispatcher) + override suspend fun loginSelf(payload: AuthenticationPayload): Result { + return try { + val result = apiManager.authenticationApi.authenticate(payload) + ?: return Result.Error(Exception("Authentication failed")) + + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } } - override suspend fun getSelfClientDetails(clientId: Long): Flow> { - return apiManager.clientsApi - .getClientForId(clientId) - .map { it.toModel() } - .asResult().flowOn(dispatcher) + override suspend fun getSelfClientDetails(clientId: Long): Result { + return try { + val result = apiManager.clientsApi.getClientForId(clientId).toModel() + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } } override suspend fun getSelfClientDetails(): Flow>> { diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt index 7cac96cd9..e9edf0086 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt @@ -12,6 +12,7 @@ package org.mifospay.core.data.repositoryImp import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.withContext import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.UserRepository @@ -25,23 +26,54 @@ class UserRepositoryImpl( private val apiManager: FineractApiManager, private val ioDispatcher: CoroutineDispatcher, ) : UserRepository { - override fun getUsers(): Flow>> { + override suspend fun getUsers(): Flow>> { return apiManager.userApi.users().asResult().flowOn(ioDispatcher) } - override fun getUser(): Flow> { + override suspend fun getUser(): Flow> { return apiManager.userApi.getUser().asResult().flowOn(ioDispatcher) } - override fun createUser(newUser: NewUser): Flow> { - return apiManager.userApi.createUser(newUser).asResult().flowOn(ioDispatcher) + override suspend fun createUser(newUser: NewUser): Result { + return try { + val result = withContext(ioDispatcher) { + apiManager.userApi.createUser(newUser) + } + + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } } - override fun updateUser(userId: Int, updatedUser: NewUser): Flow> { + override suspend fun updateUser( + userId: Int, + updatedUser: NewUser, + ): Flow> { return apiManager.userApi.updateUser(userId, updatedUser).asResult().flowOn(ioDispatcher) } - override fun deleteUser(userId: Int): Flow> { - return apiManager.userApi.deleteUser(userId).asResult().flowOn(ioDispatcher) + override suspend fun deleteUser(userId: Int): Result { + return try { + val result = withContext(ioDispatcher) { + apiManager.userApi.deleteUser(userId) + } + + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } + } + + override suspend fun assignClientToUser(userId: Int, clientId: Int): Result { + return try { + val result = withContext(ioDispatcher) { + apiManager.userApi.assignClientToUser(userId, mapOf("clients" to listOf(clientId))) + } + + Result.Success(Unit) + } catch (e: Exception) { + Result.Error(e) + } } } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/util/Constants.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/util/Constants.kt index 669234b76..4c5e6d58b 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/util/Constants.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/util/Constants.kt @@ -16,7 +16,7 @@ object Constants { const val WALLET_ACCOUNT_SAVINGS_PRODUCT_ID = 1 const val MIFOS_MERCHANT_SAVINGS_PRODUCT_ID = 165 // 372 const val MIFOS_CONSUMER_SAVINGS_PRODUCT_ID = 165 // 373 - private const val MOBILE_WALLET_ROLE_ID = 471 + private const val MOBILE_WALLET_ROLE_ID = 2 private const val SUPER_USER_ROLE_ID = 1 val NEW_USER_ROLE_IDS: List = listOf(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID) diff --git a/core/data/src/jvmMain/kotlin/org/mifospay/core/data/JvmPlatformDependentDataModule.kt b/core/data/src/desktopMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt similarity index 57% rename from core/data/src/jvmMain/kotlin/org/mifospay/core/data/JvmPlatformDependentDataModule.kt rename to core/data/src/desktopMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt index ba5672f7e..fe646afb5 100644 --- a/core/data/src/jvmMain/kotlin/org/mifospay/core/data/JvmPlatformDependentDataModule.kt +++ b/core/data/src/desktopMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt @@ -16,18 +16,16 @@ import org.mifospay.core.data.di.PlatformDependentDataModule import org.mifospay.core.data.util.NetworkMonitor import org.mifospay.core.data.util.TimeZoneMonitor -class JvmPlatformDependentDataModule : PlatformDependentDataModule() { - override fun bindsNetworkMonitor(): NetworkMonitor { - return object : NetworkMonitor { - override val isOnline: Flow - get() = flowOf(true) +class JsPlatformDependentDataModule : PlatformDependentDataModule { + override val networkMonitor: NetworkMonitor by lazy { + object : NetworkMonitor { + override val isOnline: Flow = flowOf(true) } } - override fun bindsTimeZoneMonitor(): TimeZoneMonitor { - return object : TimeZoneMonitor { - override val currentTimeZone: Flow - get() = flowOf(TimeZone.currentSystemDefault()) + override val timeZoneMonitor: TimeZoneMonitor by lazy { + object : TimeZoneMonitor { + override val currentTimeZone: Flow = flowOf(TimeZone.currentSystemDefault()) } } } diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/di/Modules.kt b/core/data/src/desktopMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt similarity index 53% rename from shared/src/commonMain/kotlin/org/mifospay/shared/di/Modules.kt rename to core/data/src/desktopMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt index 9708d1fec..9dbf3539a 100644 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/di/Modules.kt +++ b/core/data/src/desktopMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt @@ -7,13 +7,16 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared.di +package org.mifospay.core.data.di import org.koin.core.module.Module import org.koin.dsl.module +import org.mifospay.core.data.JsPlatformDependentDataModule -expect val platformModule: Module +actual val getPlatformDataModule: PlatformDependentDataModule + get() = JsPlatformDependentDataModule() -val sharedModule = module { - single { } -} +actual val platformModule: Module + get() = module { + single { getPlatformDataModule } + } diff --git a/core/data/src/jsMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt b/core/data/src/jsMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt new file mode 100644 index 000000000..fe646afb5 --- /dev/null +++ b/core/data/src/jsMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.datetime.TimeZone +import org.mifospay.core.data.di.PlatformDependentDataModule +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneMonitor + +class JsPlatformDependentDataModule : PlatformDependentDataModule { + override val networkMonitor: NetworkMonitor by lazy { + object : NetworkMonitor { + override val isOnline: Flow = flowOf(true) + } + } + + override val timeZoneMonitor: TimeZoneMonitor by lazy { + object : TimeZoneMonitor { + override val currentTimeZone: Flow = flowOf(TimeZone.currentSystemDefault()) + } + } +} diff --git a/core/data/src/jsMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt b/core/data/src/jsMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt new file mode 100644 index 000000000..9dbf3539a --- /dev/null +++ b/core/data/src/jsMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.di + +import org.koin.core.module.Module +import org.koin.dsl.module +import org.mifospay.core.data.JsPlatformDependentDataModule + +actual val getPlatformDataModule: PlatformDependentDataModule + get() = JsPlatformDependentDataModule() + +actual val platformModule: Module + get() = module { + single { getPlatformDataModule } + } diff --git a/core/data/src/nativeMain/kotlin/org/mifospay/core/data/NativePlatformDependentDataModule.kt b/core/data/src/nativeMain/kotlin/org/mifospay/core/data/NativePlatformDependentDataModule.kt index e02565f39..0bc0489c2 100644 --- a/core/data/src/nativeMain/kotlin/org/mifospay/core/data/NativePlatformDependentDataModule.kt +++ b/core/data/src/nativeMain/kotlin/org/mifospay/core/data/NativePlatformDependentDataModule.kt @@ -16,18 +16,16 @@ import org.mifospay.core.data.di.PlatformDependentDataModule import org.mifospay.core.data.util.NetworkMonitor import org.mifospay.core.data.util.TimeZoneMonitor -class NativePlatformDependentDataModule : PlatformDependentDataModule() { - override fun bindsNetworkMonitor(): NetworkMonitor { - return object : NetworkMonitor { - override val isOnline: Flow - get() = flowOf(true) +class NativePlatformDependentDataModule : PlatformDependentDataModule { + override val networkMonitor: NetworkMonitor by lazy { + object : NetworkMonitor { + override val isOnline: Flow = flowOf(true) } } - override fun bindsTimeZoneMonitor(): TimeZoneMonitor { - return object : TimeZoneMonitor { - override val currentTimeZone: Flow - get() = flowOf(TimeZone.currentSystemDefault()) + override val timeZoneMonitor: TimeZoneMonitor by lazy { + object : TimeZoneMonitor { + override val currentTimeZone: Flow = flowOf(TimeZone.currentSystemDefault()) } } } diff --git a/core/data/src/nativeMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.native.kt b/core/data/src/nativeMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.native.kt new file mode 100644 index 000000000..0b6e1b1f8 --- /dev/null +++ b/core/data/src/nativeMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.native.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.di + +import org.koin.core.module.Module +import org.koin.dsl.module +import org.mifospay.core.data.NativePlatformDependentDataModule + +actual val getPlatformDataModule: PlatformDependentDataModule + get() = NativePlatformDependentDataModule() + +actual val platformModule: Module + get() = module { + single { getPlatformDataModule } + } diff --git a/core/data/src/wasmJsMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt b/core/data/src/wasmJsMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt new file mode 100644 index 000000000..fe646afb5 --- /dev/null +++ b/core/data/src/wasmJsMain/kotlin/org/mifospay/core/data/JsPlatformDependentDataModule.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf +import kotlinx.datetime.TimeZone +import org.mifospay.core.data.di.PlatformDependentDataModule +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneMonitor + +class JsPlatformDependentDataModule : PlatformDependentDataModule { + override val networkMonitor: NetworkMonitor by lazy { + object : NetworkMonitor { + override val isOnline: Flow = flowOf(true) + } + } + + override val timeZoneMonitor: TimeZoneMonitor by lazy { + object : TimeZoneMonitor { + override val currentTimeZone: Flow = flowOf(TimeZone.currentSystemDefault()) + } + } +} diff --git a/core/data/src/wasmJsMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt b/core/data/src/wasmJsMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt new file mode 100644 index 000000000..9dbf3539a --- /dev/null +++ b/core/data/src/wasmJsMain/kotlin/org/mifospay/core/data/di/PlatformDependentDataModule.jvm.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.di + +import org.koin.core.module.Module +import org.koin.dsl.module +import org.mifospay.core.data.JsPlatformDependentDataModule + +actual val getPlatformDataModule: PlatformDependentDataModule + get() = JsPlatformDependentDataModule() + +actual val platformModule: Module + get() = module { + single { getPlatformDataModule } + } diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt index af951f03b..32ab5c4a4 100644 --- a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt +++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt @@ -14,7 +14,7 @@ import kotlinx.serialization.Serializable @Serializable data class UserInfoPreferences( val username: String, - val userId: Int, + val userId: Long, val base64EncodedAuthenticationKey: String, val authenticated: Boolean, val officeId: Int, diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt deleted file mode 100644 index 91d76ef11..000000000 --- a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.datastore.proto - -import kotlinx.serialization.Serializable - -@Serializable -data class UserPreferences( - val token: String, - val name: String, - val username: String, - val email: String, - val mobileNo: String, - val userId: Int, - val clientId: Int, - val clientVpa: String, - val accountId: Int, - val firebaseRegId: String, - val client: ClientPreferences, - val user: UserInfoPreferences, -) { - companion object { - val DEFAULT = UserPreferences( - token = "", - name = "", - username = "", - email = "", - mobileNo = "", - userId = 0, - clientId = 0, - clientVpa = "", - accountId = 0, - firebaseRegId = "", - client = ClientPreferences.DEFAULT, - user = UserInfoPreferences.DEFAULT, - ) - } -} diff --git a/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto deleted file mode 100644 index 762a78145..000000000 --- a/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto +++ /dev/null @@ -1,22 +0,0 @@ -syntax = "proto3"; - -import "org.mifospay.core.datastore.proto.client_info.proto"; -import "org.mifospay.core.datastore.proto.user_info.proto"; - -option java_package = "org.mifospay.core.datastore.proto"; -option java_multiple_files = true; - -message UserPreferences { - string token = 1; - string name = 2; - string username = 3; - string email = 4; - string mobile_no = 5; - int32 user_id = 6; - int32 client_id = 7; - string client_vpa = 8; - int32 account_id = 9; - string firebase_reg_id = 10; - Client client = 11; - User user = 12; -} \ No newline at end of file diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index f447d6a0d..154a4d55b 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -35,8 +35,13 @@ kotlin { implementation(projects.core.common) implementation(projects.core.datastoreProto) } + commonTest.dependencies { implementation(libs.multiplatform.settings.test) } + + desktopMain.dependencies { + implementation(libs.kotlinx.coroutines.swing) + } } } \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt index cd67a1dfc..fb6b2803c 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt @@ -12,10 +12,8 @@ package org.mifospay.core.datastore import org.mifospay.core.datastore.proto.ClientPreferences import org.mifospay.core.datastore.proto.RolePreferences import org.mifospay.core.datastore.proto.UserInfoPreferences -import org.mifospay.core.datastore.proto.UserPreferences import org.mifospay.core.model.ClientInfo import org.mifospay.core.model.RoleInfo -import org.mifospay.core.model.UserData import org.mifospay.core.model.UserInfo fun ClientPreferences.toClientInfo(): ClientInfo { @@ -89,37 +87,3 @@ fun UserInfo.toUserInfoPreferences(): UserInfoPreferences { isTwoFactorAuthenticationRequired = isTwoFactorAuthenticationRequired, ) } - -fun UserPreferences.toUserData(): UserData { - return UserData( - token = token, - name = name, - username = username, - email = email, - mobileNo = mobileNo, - userId = userId, - clientId = clientId, - clientVpa = clientVpa, - accountId = accountId, - firebaseRegId = firebaseRegId, - client = client.toClientInfo(), - user = user.toUserInfo(), - ) -} - -fun UserData.toUserPreferences(): UserPreferences { - return UserPreferences( - token = token, - name = name, - username = username, - email = email, - mobileNo = mobileNo, - userId = userId, - clientId = clientId, - clientVpa = clientVpa, - accountId = accountId, - firebaseRegId = firebaseRegId, - client = client.toClientPreferences(), - user = user.toUserInfoPreferences(), - ) -} diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt index 36a76f39a..501dbd040 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt @@ -22,34 +22,18 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi import org.mifospay.core.datastore.proto.ClientPreferences -import org.mifospay.core.datastore.proto.RolePreferences import org.mifospay.core.datastore.proto.UserInfoPreferences -import org.mifospay.core.datastore.proto.UserPreferences import org.mifospay.core.model.ClientInfo -import org.mifospay.core.model.RoleInfo -import org.mifospay.core.model.UserData import org.mifospay.core.model.UserInfo -private const val USER_DATA_KEY = "userData" private const val USER_INFO_KEY = "userInfo" private const val CLIENT_INFO_KEY = "clientInfo" -private const val ROLE_INFO_KEY = "roleInfo" +@OptIn(ExperimentalSerializationApi::class) class UserPreferencesDataSource( private val settings: Settings, private val dispatcher: CoroutineDispatcher, ) { - private val _userData = MutableStateFlow( - settings.decodeValue( - key = USER_DATA_KEY, - serializer = UserPreferences.serializer(), - defaultValue = settings.decodeValueOrNull( - key = USER_DATA_KEY, - serializer = UserPreferences.serializer(), - ) ?: UserPreferences.DEFAULT, - ), - ) - private val _userInfo = MutableStateFlow( settings.decodeValue( key = USER_INFO_KEY, @@ -72,29 +56,11 @@ class UserPreferencesDataSource( ), ) - private val _roleInfo = MutableStateFlow( - settings.decodeValue( - key = ROLE_INFO_KEY, - serializer = RolePreferences.serializer(), - defaultValue = settings.decodeValueOrNull( - key = ROLE_INFO_KEY, - serializer = RolePreferences.serializer(), - ) ?: RolePreferences.DEFAULT, - ), - ) - - val userData = _userData.map(UserPreferences::toUserData) - val token = _userData.map(UserPreferences::toUserData).map { it.token } + val token = _userInfo.map(UserInfoPreferences::toUserInfo).map { + it.base64EncodedAuthenticationKey + } val userInfo = _userInfo.map(UserInfoPreferences::toUserInfo) val clientInfo = _clientInfo.map(ClientPreferences::toClientInfo) - val roleInfo = _roleInfo.map(RolePreferences::toRoleInfo) - - suspend fun updateRoleInfo(roleInfo: RoleInfo) { - withContext(dispatcher) { - settings.putRolePreference(roleInfo.toRolePreferences()) - _roleInfo.value = roleInfo.toRolePreferences() - } - } suspend fun updateClientInfo(clientInfo: ClientInfo) { withContext(dispatcher) { @@ -110,10 +76,9 @@ class UserPreferencesDataSource( } } - suspend fun updateUserData(userData: UserData) { + suspend fun clearInfo() { withContext(dispatcher) { - settings.putUserPreference(userData.toUserPreferences()) - _userData.value = userData.toUserPreferences() + settings.clear() } } } @@ -126,14 +91,6 @@ private fun Settings.putClientPreference(preference: ClientPreferences) { ) } -private fun Settings.putRolePreference(preference: RolePreferences) { - encodeValue( - key = CLIENT_INFO_KEY, - serializer = RolePreferences.serializer(), - value = preference, - ) -} - private fun Settings.putUserInfoPreference(preference: UserInfoPreferences) { encodeValue( key = USER_INFO_KEY, @@ -141,19 +98,3 @@ private fun Settings.putUserInfoPreference(preference: UserInfoPreferences) { value = preference, ) } - -private fun Settings.putUserPreference(preference: UserPreferences) { - encodeValue( - key = USER_DATA_KEY, - serializer = UserPreferences.serializer(), - value = preference, - ) -} - -private fun Settings.getUserPreference(): UserPreferences { - return decodeValue( - key = USER_DATA_KEY, - serializer = UserPreferences.serializer(), - defaultValue = UserPreferences.DEFAULT, - ) -} diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepository.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepository.kt new file mode 100644 index 000000000..520001a82 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepository.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.datastore + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow +import org.mifospay.core.common.Result +import org.mifospay.core.model.ClientInfo +import org.mifospay.core.model.UserInfo +import org.mifospay.core.model.domain.client.Client +import org.mifospay.core.model.domain.user.User + +interface UserPreferencesRepository { + val userInfo: Flow + + val token: StateFlow + + val clientInfo: Flow + + suspend fun updateUserInfo(user: User): Result + + suspend fun updateClientInfo(client: Client): Result + + suspend fun logOut(): Unit +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepositoryImpl.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepositoryImpl.kt new file mode 100644 index 000000000..a2c387553 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepositoryImpl.kt @@ -0,0 +1,69 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.datastore + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.stateIn +import org.mifospay.core.common.Result +import org.mifospay.core.datastore.utils.toUserInfo +import org.mifospay.core.model.ClientInfo +import org.mifospay.core.model.UserInfo +import org.mifospay.core.model.domain.client.Client +import org.mifospay.core.model.domain.user.User + +class UserPreferencesRepositoryImpl( + private val preferenceManager: UserPreferencesDataSource, + private val ioDispatcher: CoroutineDispatcher, + unconfinedDispatcher: CoroutineDispatcher, +) : UserPreferencesRepository { + private val unconfinedScope = CoroutineScope(unconfinedDispatcher) + + override val userInfo: Flow + get() = preferenceManager.userInfo.flowOn(ioDispatcher) + + override val token: StateFlow + get() = preferenceManager.token.stateIn( + unconfinedScope, + initialValue = null, + started = SharingStarted.Eagerly, + ) + + override val clientInfo: Flow + get() = preferenceManager.clientInfo.flowOn(ioDispatcher) + + override suspend fun updateClientInfo(client: Client): Result { + return try { + val result = preferenceManager.updateClientInfo(client.toUserInfo()) + + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } + } + + override suspend fun updateUserInfo(user: User): Result { + return try { + val result = preferenceManager.updateUserInfo(user.toUserInfo()) + + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } + } + + override suspend fun logOut() { + preferenceManager.clearInfo() + } +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt index d3b57761f..e74bee4cf 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt @@ -12,10 +12,21 @@ package org.mifospay.core.datastore.di import com.russhwolf.settings.Settings import org.koin.core.qualifier.named import org.koin.dsl.module +import org.mifospay.core.common.MifosDispatchers import org.mifospay.core.datastore.UserPreferencesDataSource +import org.mifospay.core.datastore.UserPreferencesRepository +import org.mifospay.core.datastore.UserPreferencesRepositoryImpl val PreferencesModule = module { factory { Settings() } // Use the IO dispatcher name - MifosDispatchers.IO.name - factory { UserPreferencesDataSource(get(), get(named("IO"))) } + factory { UserPreferencesDataSource(get(), get(named(MifosDispatchers.IO.name))) } + + single { + UserPreferencesRepositoryImpl( + preferenceManager = get(), + ioDispatcher = get(named(MifosDispatchers.IO.name)), + unconfinedDispatcher = get(named(MifosDispatchers.Unconfined.name)), + ) + } } diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/utils/UserMapper.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/utils/UserMapper.kt new file mode 100644 index 000000000..0c45d6589 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/utils/UserMapper.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.datastore.utils + +import org.mifospay.core.model.ClientInfo +import org.mifospay.core.model.RoleInfo +import org.mifospay.core.model.UserInfo +import org.mifospay.core.model.domain.client.Client +import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.entity.Role + +fun User.toUserInfo() = UserInfo( + username = username, + userId = userId, + base64EncodedAuthenticationKey = base64EncodedAuthenticationKey, + authenticated = authenticated, + officeId = officeId, + officeName = officeName, + roles = roles.map { it.toRoleInfo() }, + permissions = permissions, + clients = clients, + shouldRenewPassword = shouldRenewPassword, + isTwoFactorAuthenticationRequired = isTwoFactorAuthenticationRequired, +) + +fun Role.toRoleInfo() = RoleInfo( + id = id ?: "", + name = name ?: "", + description = description ?: "", + disabled = disabled, +) + +fun Client.toUserInfo() = ClientInfo( + name = name ?: "", + image = image ?: "", + externalId = externalId ?: "", + clientId = clientId, + displayName = displayName ?: "", + mobileNo = mobileNo ?: "", +) diff --git a/core/designsystem/build.gradle.kts b/core/designsystem/build.gradle.kts index fc4ae96c9..868741ec2 100644 --- a/core/designsystem/build.gradle.kts +++ b/core/designsystem/build.gradle.kts @@ -7,8 +7,6 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl -import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig /* * Copyright 2024 Mifos Initiative @@ -34,23 +32,6 @@ android { } kotlin { - @OptIn(ExperimentalWasmDsl::class) - wasmJs { - moduleName = "composeApp" - browser { - commonWebpackConfig { - outputFileName = "composeApp.js" - devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply { - static = (static ?: mutableListOf()).apply { - // Serve sources to debug inside browser - add(project.projectDir.path) - } - } - } - } - binaries.executable() - } - sourceSets { androidMain.dependencies { implementation(libs.androidx.compose.ui.tooling.preview) diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosBasicDialog.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosBasicDialog.kt new file mode 100644 index 000000000..a9ccfe48e --- /dev/null +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosBasicDialog.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.designsystem.component + +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.designsystem.theme.MifosTheme + +@Composable +fun MifosBasicDialog( + visibilityState: BasicDialogState, + onDismissRequest: () -> Unit, +): Unit = when (visibilityState) { + BasicDialogState.Hidden -> Unit + is BasicDialogState.Shown -> { + AlertDialog( + onDismissRequest = onDismissRequest, + confirmButton = { + MifosTextButton( + content = { + Text(text = "Ok") + }, + onClick = onDismissRequest, + modifier = Modifier.testTag("AcceptAlertButton"), + ) + }, + title = visibilityState.title?.let { + { + Text( + text = it, + style = MaterialTheme.typography.headlineSmall, + modifier = Modifier.testTag("AlertTitleText"), + ) + } + }, + text = { + Text( + text = visibilityState.message, + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier.testTag("AlertContentText"), + ) + }, + containerColor = MaterialTheme.colorScheme.surfaceContainerHigh, + modifier = Modifier.semantics { + testTag = "AlertPopup" + }, + ) + } +} + +@Preview +@Composable +private fun MifosBasicDialog_preview() { + MifosTheme { + MifosBasicDialog( + visibilityState = BasicDialogState.Shown( + title = "An error has occurred.", + message = "Username or password is incorrect. Try again.", + ), + onDismissRequest = {}, + ) + } +} + +/** + * Models display of a [MifosBasicDialog]. + */ +sealed class BasicDialogState { + + data object Hidden : BasicDialogState() + + data class Shown( + val message: String, + val title: String = "An Error Occurred!", + ) : BasicDialogState() +} diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosLoadingDialog.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosLoadingDialog.kt new file mode 100644 index 000000000..b9f66c6bd --- /dev/null +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosLoadingDialog.kt @@ -0,0 +1,107 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.designsystem.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CircularProgressIndicator +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.platform.testTag +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag +import androidx.compose.ui.unit.dp +import androidx.compose.ui.window.Dialog +import androidx.compose.ui.window.DialogProperties +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.designsystem.theme.MifosTheme + +@Composable +fun MifosLoadingDialog( + visibilityState: LoadingDialogState, +) { + when (visibilityState) { + is LoadingDialogState.Hidden -> Unit + is LoadingDialogState.Shown -> { + Dialog( + onDismissRequest = {}, + properties = DialogProperties( + dismissOnBackPress = false, + dismissOnClickOutside = false, + ), + ) { + Card( + shape = RoundedCornerShape(28.dp), + colors = CardDefaults.cardColors( + containerColor = MaterialTheme.colorScheme.surfaceContainerHigh, + ), + modifier = Modifier + .semantics { + testTag = "AlertPopup" + } + .fillMaxWidth() + .wrapContentHeight(), + ) { + Column( + modifier = Modifier.fillMaxWidth(), + verticalArrangement = Arrangement.Center, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + text = "Loading..", + modifier = Modifier + .testTag("AlertTitleText") + .padding( + top = 24.dp, + bottom = 8.dp, + ), + ) + CircularProgressIndicator( + modifier = Modifier + .testTag("AlertProgressIndicator") + .padding( + top = 8.dp, + bottom = 24.dp, + ), + ) + } + } + } + } + } +} + +@Preview +@Composable +private fun MifosLoadingDialog_preview() { + MifosTheme { + MifosLoadingDialog( + visibilityState = LoadingDialogState.Shown, + ) + } +} + +/** + * Models display of a [MifosLoadingDialog]. + */ +sealed class LoadingDialogState { + data object Hidden : LoadingDialogState() + + data object Shown : LoadingDialogState() +} diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt index 6c62f4028..078b307e6 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosScaffold.kt @@ -11,9 +11,20 @@ package org.mifospay.core.designsystem.component import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.RowScope +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBarsPadding +import androidx.compose.material3.FabPosition import androidx.compose.material3.FloatingActionButton +import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold +import androidx.compose.material3.ScaffoldDefaults +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.contentColorFor import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -52,6 +63,36 @@ fun MifosScaffold( ) } +@Composable +fun MifosScaffold( + modifier: Modifier = Modifier, + topBar: @Composable () -> Unit = {}, + bottomBar: @Composable () -> Unit = {}, + floatingActionButton: @Composable () -> Unit = {}, + snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }, + floatingActionButtonPosition: FabPosition = FabPosition.End, + containerColor: Color = MaterialTheme.colorScheme.background, + contentColor: Color = contentColorFor(containerColor), + contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets, + content: @Composable (PaddingValues) -> Unit, +) { + Scaffold( + modifier = modifier + .fillMaxSize() + .navigationBarsPadding() + .imePadding(), + topBar = topBar, + bottomBar = bottomBar, + snackbarHost = { SnackbarHost(snackbarHostState) }, + floatingActionButton = floatingActionButton, + floatingActionButtonPosition = floatingActionButtonPosition, + containerColor = containerColor, + contentColor = contentColor, + contentWindowInsets = contentWindowInsets, + content = content, + ) +} + data class FloatingActionButtonContent( val onClick: (() -> Unit), val contentColor: Color, diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopAppBar.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopAppBar.kt new file mode 100644 index 000000000..7f71e3573 --- /dev/null +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/MifosTopAppBar.kt @@ -0,0 +1,275 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.designsystem.component + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.RowScope +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.LargeTopAppBar +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.MediumTopAppBar +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.TopAppBarScrollBehavior +import androidx.compose.material3.rememberTopAppBarState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.designsystem.theme.MifosTheme +import org.mifospay.core.designsystem.utils.mirrorIfRtl + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun MifosTopAppBar( + title: String, + scrollBehavior: TopAppBarScrollBehavior, + navigationIcon: ImageVector, + navigationIconContentDescription: String, + onNavigationIconClick: () -> Unit, + modifier: Modifier = Modifier, + actions: @Composable RowScope.() -> Unit = { }, +) { + MifosTopAppBar( + title = title, + scrollBehavior = scrollBehavior, + navigationIcon = NavigationIcon( + navigationIcon = navigationIcon, + navigationIconContentDescription = navigationIconContentDescription, + onNavigationIconClick = onNavigationIconClick, + ), + modifier = modifier, + actions = actions, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Suppress("LongMethod") +@Composable +fun MifosTopAppBar( + title: String, + scrollBehavior: TopAppBarScrollBehavior, + navigationIcon: NavigationIcon?, + modifier: Modifier = Modifier, + actions: @Composable RowScope.() -> Unit = {}, +) { + var titleTextHasOverflow by remember { + mutableStateOf(false) + } + + val navigationIconContent: @Composable () -> Unit = remember(navigationIcon) { + { + navigationIcon?.let { + IconButton( + onClick = it.onNavigationIconClick, + modifier = Modifier.testTag("CloseButton"), + ) { + Icon( + modifier = Modifier.mirrorIfRtl(), + imageVector = it.navigationIcon, + contentDescription = it.navigationIconContentDescription, + ) + } + } + } + } + + val topAppBarColors = TopAppBarDefaults.largeTopAppBarColors( + containerColor = MaterialTheme.colorScheme.surface, + scrolledContainerColor = MaterialTheme.colorScheme.surfaceContainer, + navigationIconContentColor = MaterialTheme.colorScheme.onSurface, + titleContentColor = MaterialTheme.colorScheme.onSurface, + actionIconContentColor = MaterialTheme.colorScheme.onSurfaceVariant, + ) + + if (titleTextHasOverflow) { + MediumTopAppBar( + colors = topAppBarColors, + scrollBehavior = scrollBehavior, + navigationIcon = navigationIconContent, + title = { + // The height of the component is controlled and will only allow for 1 extra row, + // making adding any arguments for softWrap and minLines superfluous. + Text( + text = title, + style = MaterialTheme.typography.titleLarge, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.testTag("PageTitleLabel"), + ) + }, + modifier = modifier.testTag("HeaderBarComponent"), + actions = actions, + ) + } else { + TopAppBar( + colors = topAppBarColors, + scrollBehavior = scrollBehavior, + navigationIcon = navigationIconContent, + title = { + Text( + text = title, + style = MaterialTheme.typography.titleLarge, + maxLines = 1, + softWrap = false, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.testTag("PageTitleLabel"), + onTextLayout = { + titleTextHasOverflow = it.hasVisualOverflow + }, + ) + }, + modifier = modifier.testTag("HeaderBarComponent"), + actions = actions, + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Suppress("LongMethod") +@Composable +fun MifosTopAppBar( + title: String, + subtitle: String, + scrollBehavior: TopAppBarScrollBehavior, + navigationIcon: ImageVector, + navigationIconContentDescription: String, + onNavigationIconClick: () -> Unit, + modifier: Modifier = Modifier, + actions: @Composable RowScope.() -> Unit = {}, +) { + val navigationIconContent: @Composable () -> Unit = remember(navigationIcon) { + { + IconButton( + onClick = onNavigationIconClick, + modifier = Modifier.testTag("CloseButton"), + ) { + Icon( + modifier = Modifier.mirrorIfRtl(), + imageVector = navigationIcon, + contentDescription = navigationIconContentDescription, + ) + } + } + } + + val topAppBarColors = TopAppBarDefaults.largeTopAppBarColors( + containerColor = MaterialTheme.colorScheme.surface, + scrolledContainerColor = MaterialTheme.colorScheme.surfaceContainer, + navigationIconContentColor = MaterialTheme.colorScheme.onSurface, + titleContentColor = MaterialTheme.colorScheme.onSurface, + actionIconContentColor = MaterialTheme.colorScheme.onSurfaceVariant, + ) + + LargeTopAppBar( + colors = topAppBarColors, + scrollBehavior = scrollBehavior, + navigationIcon = navigationIconContent, + title = { + Column( + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + // The height of the component is controlled and will only allow for 1 extra row, + // making adding any arguments for softWrap and minLines superfluous. + Text( + text = title, + style = MaterialTheme.typography.titleLarge, + overflow = TextOverflow.Ellipsis, + modifier = Modifier.testTag("PageTitleLabel"), + ) + + Text( + text = subtitle, + style = MaterialTheme.typography.bodyMedium, + modifier = Modifier.testTag("PageTitleSubTitle"), + ) + } + }, + modifier = modifier.testTag("HeaderBarComponent"), + actions = actions, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Preview +@Composable +private fun MifosTopAppBar_preview() { + MifosTheme { + MifosTopAppBar( + title = "Title", + scrollBehavior = TopAppBarDefaults + .exitUntilCollapsedScrollBehavior( + rememberTopAppBarState(), + ), + navigationIcon = NavigationIcon( + navigationIcon = MifosIcons.Back, + navigationIconContentDescription = "Back", + onNavigationIconClick = { }, + ), + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Preview +@Composable +private fun MifosTopAppBarOverflow_preview() { + MifosTheme { + MifosTopAppBar( + title = "Title that is too long for the top line", + scrollBehavior = TopAppBarDefaults + .exitUntilCollapsedScrollBehavior( + rememberTopAppBarState(), + ), + navigationIcon = NavigationIcon( + navigationIcon = MifosIcons.Close, + navigationIconContentDescription = "Close", + onNavigationIconClick = { }, + ), + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Preview +@Composable +private fun MifosTopAppBarOverflowCutoff_preview() { + MifosTheme { + MifosTopAppBar( + title = "Title that is too long for the top line and the bottom line", + scrollBehavior = TopAppBarDefaults + .exitUntilCollapsedScrollBehavior( + rememberTopAppBarState(), + ), + navigationIcon = NavigationIcon( + navigationIcon = MifosIcons.Close, + navigationIconContentDescription = "Close", + onNavigationIconClick = { }, + ), + ) + } +} + +data class NavigationIcon( + val navigationIcon: ImageVector, + val navigationIconContentDescription: String, + val onNavigationIconClick: () -> Unit, +) diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/utils/ModifierExt.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/utils/ModifierExt.kt new file mode 100644 index 000000000..d80ad5779 --- /dev/null +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/utils/ModifierExt.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.designsystem.utils + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.scale +import androidx.compose.ui.focus.FocusDirection +import androidx.compose.ui.input.key.Key +import androidx.compose.ui.input.key.KeyEventType +import androidx.compose.ui.input.key.isShiftPressed +import androidx.compose.ui.input.key.key +import androidx.compose.ui.input.key.onPreviewKeyEvent +import androidx.compose.ui.input.key.type +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.unit.LayoutDirection + +@Stable +@Composable +fun Modifier.mirrorIfRtl(): Modifier = + if (LocalLayoutDirection.current == LayoutDirection.Rtl) { + scale(scaleX = -1f, scaleY = 1f) + } else { + this + } + +@Stable +@Composable +fun Modifier.tabNavigation(): Modifier { + val focusManager = LocalFocusManager.current + return onPreviewKeyEvent { keyEvent -> + if (keyEvent.key == Key.Tab && keyEvent.type == KeyEventType.KeyDown) { + focusManager.moveFocus( + if (keyEvent.isShiftPressed) { + FocusDirection.Previous + } else { + FocusDirection.Next + }, + ) + true + } else { + false + } + } +} diff --git a/mifospay/.gitignore b/core/domain/.gitignore similarity index 100% rename from mifospay/.gitignore rename to core/domain/.gitignore diff --git a/core/domain/README.md b/core/domain/README.md new file mode 100644 index 000000000..5d30f1638 --- /dev/null +++ b/core/domain/README.md @@ -0,0 +1,3 @@ +# :core:data module +## Dependency graph +![Dependency graph](../../docs/images/graphs/dep_graph_core_data.svg) diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModule.kt b/core/domain/build.gradle.kts similarity index 50% rename from shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModule.kt rename to core/domain/build.gradle.kts index 1af847cd6..6ceb3c24d 100644 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModule.kt +++ b/core/domain/build.gradle.kts @@ -7,14 +7,20 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared.di +plugins { + alias(libs.plugins.mifospay.kmp.library) +} -import org.koin.core.context.startKoin -import org.koin.dsl.KoinAppDeclaration +android { + namespace = "org.mifospay.core.domain" +} -fun initKoin(config: KoinAppDeclaration? = null) { - startKoin { - config?.invoke(this) - modules(sharedModule, platformModule) +kotlin { + sourceSets { + commonMain.dependencies { + implementation(projects.core.common) + implementation(projects.core.data) + implementation(projects.core.model) + } } -} +} \ No newline at end of file diff --git a/core/domain/proguard-rules.pro b/core/domain/proguard-rules.pro new file mode 100644 index 000000000..918d3d0ef --- /dev/null +++ b/core/domain/proguard-rules.pro @@ -0,0 +1,25 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /home/naman/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle.kts. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/core/domain/src/commonMain/kotlin/org/mifospay/core/domain/LoginUseCase.kt b/core/domain/src/commonMain/kotlin/org/mifospay/core/domain/LoginUseCase.kt new file mode 100644 index 000000000..53eeea344 --- /dev/null +++ b/core/domain/src/commonMain/kotlin/org/mifospay/core/domain/LoginUseCase.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.domain + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.withContext +import org.mifospay.core.common.Result +import org.mifospay.core.data.repository.AuthenticationRepository +import org.mifospay.core.data.repository.ClientRepository +import org.mifospay.core.datastore.UserPreferencesRepository +import org.mifospay.core.model.domain.user.User + +class LoginUseCase( + private val repository: AuthenticationRepository, + private val clientRepository: ClientRepository, + private val userPreferencesRepository: UserPreferencesRepository, + private val ioDispatcher: CoroutineDispatcher, +) { + suspend operator fun invoke(username: String, password: String): Result { + return when (val result = repository.authenticate(username, password)) { + is Result.Loading -> Result.Loading + is Result.Error -> Result.Error(Exception("Invalid credentials")) + is Result.Success -> { + if (result.data.clients.isNotEmpty()) { + withContext(ioDispatcher) { + val userInfo = userPreferencesRepository.updateUserInfo(result.data) + when (userInfo) { + is Result.Success -> { + val clientInfo = + clientRepository.getClient(result.data.clients.first()) + + when (clientInfo) { + is Result.Success -> { + userPreferencesRepository.updateClientInfo(clientInfo.data) + + Result.Success(result.data) + } + + is Result.Error -> { + return@withContext Result.Error(Exception("No client found")) + } + + is Result.Loading -> Result.Loading + } + } + + is Result.Error -> Result.Error(Exception("Something went wrong")) + is Result.Loading -> Result.Loading + } + } + } else { + Result.Error(Exception("No clients found")) + } + } + } + } +} diff --git a/core/domain/src/commonMain/kotlin/org/mifospay/core/domain/di/DomainModule.kt b/core/domain/src/commonMain/kotlin/org/mifospay/core/domain/di/DomainModule.kt new file mode 100644 index 000000000..a601156df --- /dev/null +++ b/core/domain/src/commonMain/kotlin/org/mifospay/core/domain/di/DomainModule.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.domain.di + +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.common.MifosDispatchers +import org.mifospay.core.domain.LoginUseCase + +val DomainModule = module { + single { + LoginUseCase( + repository = get(), + clientRepository = get(), + userPreferencesRepository = get(), + ioDispatcher = get(named(MifosDispatchers.IO.name)), + ) + } +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt index d34179e07..4045cbd42 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt @@ -11,7 +11,7 @@ package org.mifospay.core.model data class UserInfo( val username: String, - val userId: Int, + val userId: Long, val base64EncodedAuthenticationKey: String, val authenticated: Boolean, val officeId: Int, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt index bf59ce9e5..dd79fd813 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt @@ -9,53 +9,55 @@ */ package org.mifospay.core.model.domain.client +import kotlinx.serialization.Serializable import org.mifospay.core.model.utils.DateHelper +@Serializable data class NewClient( - val fullname: String?, - val userName: String?, - val addressLine1: String?, - val addressLine2: String?, - val city: String?, - val postalCode: String?, - val stateProvinceId: String?, - val countryId: String?, - val mobileNo: String?, - val mifosSavingsProductId: Int?, + val firstname: String, + val lastname: String, + val externalId: String, + val mobileNo: String, + val address: Address, + val savingsProductId: Int, + val officeId: Int, + val legalFormId: Int, + val active: Boolean, + val dateFormat: String, + val activationDate: String, + val submittedOnDate: String, + val locale: String, ) { - private val address: MutableList

= mutableListOf() - private val activationDate: String = DateHelper.formattedDate - val submittedOnDate: String = activationDate - val savingsProductId: Int = mifosSavingsProductId ?: 0 - val externalId: String = "$userName@mifos" - - init { - address.add( - Address( - addressLine1 = addressLine1, - addressLine2 = addressLine2, - street = city, - postalCode = postalCode, - stateProvinceId = stateProvinceId, - countryId = countryId, - ), - ) - } - - data class Address( - val addressLine1: String?, - val addressLine2: String?, - val street: String?, - val postalCode: String?, - val stateProvinceId: String?, - val countryId: String?, - ) - - data class CustomDataTable( - val registeredTableName: String = "client_info", - val data: HashMap = hashMapOf( - "locale" to "en", - "info_id" to 1, - ), + constructor( + firstname: String, + lastname: String, + externalId: String, + mobileNo: String, + address: Address, + savingsProductId: Int, + ) : this( + firstname = firstname, + lastname = lastname, + externalId = externalId, + mobileNo = mobileNo, + address = address, + savingsProductId = savingsProductId, + officeId = 1, + legalFormId = 1, + active = true, + dateFormat = DateHelper.SHORT_MONTH, + activationDate = DateHelper.formattedShortDate, + submittedOnDate = DateHelper.formattedShortDate, + locale = "en_US", ) } + +@Serializable +data class Address( + val addressLine1: String, + val addressLine2: String, + val postalCode: String, + val stateProvinceId: String, + val countryId: String, + val addressTypeId: Int = 805, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt index 72a2aee2a..fe550e20b 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt @@ -9,21 +9,49 @@ */ package org.mifospay.core.model.domain.user +import kotlinx.serialization.Serializable + +// Mandatory Fields +// username, firstname, lastname, email, officeId, roles, sendPasswordToEmail +// +// Optional Fields +// staffId,passwordNeverExpires,isSelfServiceUser,clients + +@Serializable class NewUser( - val username: String?, - val firstname: String?, - val lastname: String?, - val email: String?, - val password: String?, + val username: String, + val firstname: String, + val lastname: String, + val email: String, + val password: String, + val officeId: Int, + val roles: ArrayList, + val sendPasswordToEmail: Boolean, + val isSelfServiceUser: Boolean, + val repeatPassword: String, ) { - val officeId = "1" - val roles: MutableList = NEW_USER_ROLE_IDS.toMutableList() - val sendPasswordToEmail = false - val isSelfServiceUser = true - val repeatPassword: String? = password + constructor( + username: String, + firstname: String, + lastname: String, + email: String, + password: String, + ) : this( + username = username, + firstname = firstname, + lastname = lastname, + email = email, + password = password, + officeId = OFFICE_ID, + roles = NEW_USER_ROLE_IDS, + sendPasswordToEmail = false, + isSelfServiceUser = true, + repeatPassword = password, + ) } -private const val MOBILE_WALLET_ROLE_ID = 471 +private const val OFFICE_ID = 1 +private const val MOBILE_WALLET_ROLE_ID = 2 private const val SUPER_USER_ROLE_ID = 1 -val NEW_USER_ROLE_IDS: Collection = listOf(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID) +val NEW_USER_ROLE_IDS: ArrayList = arrayListOf(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt index c1de67fe0..0d45ba07c 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt @@ -15,13 +15,13 @@ import org.mifospay.core.model.entity.Role @Serializable data class User( val username: String, - val userId: Long = 0, + val userId: Long, val base64EncodedAuthenticationKey: String, - val authenticated: Boolean = false, + val authenticated: Boolean, val officeId: Int, val officeName: String, - val roles: List, - val permissions: List, + val roles: List = emptyList(), + val permissions: List = emptyList(), val clients: List = emptyList(), val shouldRenewPassword: Boolean, val isTwoFactorAuthenticationRequired: Boolean, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt index d69b2019f..4775b6f5e 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt @@ -14,9 +14,9 @@ import kotlinx.serialization.Serializable @Serializable data class SearchedEntity( val entityId: Int = 0, - val entityAccountNo: String = " ", - val entityName: String = " ", - val entityType: String = " ", + val entityAccountNo: String = "", + val entityName: String = "", + val entityType: String = "", val parentId: Int = 0, - val parentName: String = " ", + val parentName: String = "", ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt index 981e3d6eb..819cdd41d 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt @@ -25,8 +25,8 @@ import kotlin.time.Duration.Companion.days @OptIn(FormatStringsInDatetimeFormats::class) object DateHelper { private const val LOG_TAG = "DateHelper" - private const val FULL_MONTH = "dd MMM yyyy" - private const val SHORT_MONTH = "dd-MM-yyyy" + const val FULL_MONTH = "dd MM yyyy" + const val SHORT_MONTH = "dd-MM-yyyy" private val fullMonthFormat = LocalDateTime.Format { byUnicodePattern(FULL_MONTH) @@ -144,6 +144,7 @@ object DateHelper { return fullMonthFormat.parse(timeInMillis.toString()).toString() } - val currentDate = Clock.System.now().toEpochMilliseconds().toString() - val formattedDate = fullMonthFormat.parse(currentDate).toString() + val currentDate = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + val formattedFullDate = currentDate.format(fullMonthFormat) + val formattedShortDate = currentDate.format(shortMonthFormat) } diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index 68ba5e7bb..9f836460f 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -19,7 +19,6 @@ */ plugins { alias(libs.plugins.mifospay.kmp.library) - alias(libs.plugins.mifospay.kotlin.inject) alias(libs.plugins.ktrofit) id("kotlinx-serialization") id("com.google.devtools.ksp") @@ -44,6 +43,7 @@ kotlin { api(libs.kotlinx.datetime) api(projects.core.common) api(projects.core.model) + implementation(projects.core.datastore) implementation(libs.kotlinx.serialization.json) implementation(libs.ktor.client.core) implementation(libs.ktor.client.json) @@ -51,28 +51,29 @@ kotlin { implementation(libs.ktor.client.serialization) implementation(libs.ktor.client.content.negotiation) implementation(libs.ktor.client.auth) - implementation(libs.ktor.client.cio) implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.ktorfit.lib) - implementation(libs.ktorfit.converters.call) - implementation(libs.ktorfit.converters.flow) implementation(libs.squareup.okio) } + androidMain.dependencies { - implementation(libs.ktor.client.android) + implementation(libs.ktor.client.okhttp) implementation(libs.koin.android) } - appleMain.dependencies { + nativeMain.dependencies { implementation(libs.ktor.client.darwin) } -// wasmJsMain.dependencies { -// implementation(libs.ktor.client.js) -// } - jvmMain.dependencies { - implementation(libs.ktor.client.java) + + val desktopMain by getting { + dependencies { + implementation(libs.ktor.client.okhttp) + } + } + jsMain.dependencies { + implementation(libs.ktor.client.js) } - mingwMain.dependencies { - implementation(libs.ktor.client.winhttp) + wasmJsMain.dependencies { + implementation(libs.ktor.client.js) } } } @@ -80,8 +81,9 @@ kotlin { dependencies { add("kspCommonMainMetadata", libs.ktorfit.ksp) add("kspAndroid", libs.ktorfit.ksp) -// add("kspWasmJs", libs.ktorfit.ksp) - add("kspJvm", libs.ktorfit.ksp) + add("kspJs", libs.ktorfit.ksp) + add("kspWasmJs", libs.ktorfit.ksp) + add("kspDesktop", libs.ktorfit.ksp) add("kspIosX64", libs.ktorfit.ksp) add("kspIosArm64", libs.ktorfit.ksp) add("kspIosSimulatorArm64", libs.ktorfit.ksp) diff --git a/core/network/src/androidMain/AndroidManifest.xml b/core/network/src/androidMain/AndroidManifest.xml index 961389810..31df960ef 100644 --- a/core/network/src/androidMain/AndroidManifest.xml +++ b/core/network/src/androidMain/AndroidManifest.xml @@ -9,5 +9,5 @@ See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md --> - + \ No newline at end of file diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorAndroidHttpClient.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorAndroidHttpClient.kt new file mode 100644 index 000000000..efd65e12b --- /dev/null +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorAndroidHttpClient.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import io.ktor.client.HttpClient +import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json +import co.touchlab.kermit.Logger.Companion as KermitLogger + +actual val ktorHttpClient: HttpClient + get() = HttpClient(OkHttp) { + expectSuccess = true + + install(HttpTimeout) { + socketTimeoutMillis = 60_000 + requestTimeoutMillis = 60_000 + } + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + KermitLogger.d(tag = "KtorClient", messageString = message) + } + } + } + + install(ContentNegotiation) { + json( + Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + explicitNulls = false + }, + ) + } + } diff --git a/shared/src/iosMain/kotlin/org/mifospay/shared/di/Modules.ios.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorHttpClient.kt similarity index 69% rename from shared/src/iosMain/kotlin/org/mifospay/shared/di/Modules.ios.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorHttpClient.kt index e7cbc9318..a51b5ad54 100644 --- a/shared/src/iosMain/kotlin/org/mifospay/shared/di/Modules.ios.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorHttpClient.kt @@ -7,9 +7,8 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared.di +package org.mifospay.core.network -import org.koin.core.module.Module +import io.ktor.client.HttpClient -actual val platformModule: Module - get() = TODO("Not yet implemented") +expect val ktorHttpClient: HttpClient diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt index 86e5e5afa..120a55e25 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt @@ -10,39 +10,7 @@ package org.mifospay.core.network import de.jensklingenberg.ktorfit.Ktorfit -import de.jensklingenberg.ktorfit.converter.CallConverterFactory -import de.jensklingenberg.ktorfit.converter.FlowConverterFactory import io.ktor.client.HttpClient -import io.ktor.client.engine.cio.CIO -import io.ktor.client.plugins.DefaultRequest -import io.ktor.client.plugins.contentnegotiation.ContentNegotiation -import io.ktor.client.plugins.defaultRequest -import io.ktor.client.plugins.logging.DEFAULT -import io.ktor.client.plugins.logging.LogLevel -import io.ktor.client.plugins.logging.Logger -import io.ktor.client.plugins.logging.Logging -import io.ktor.http.ContentType -import io.ktor.http.contentType -import io.ktor.http.headers -import io.ktor.serialization.kotlinx.json.json -import kotlinx.serialization.json.Json -import org.mifospay.core.network.services.AccountTransfersService -import org.mifospay.core.network.services.AuthenticationService -import org.mifospay.core.network.services.BeneficiaryService -import org.mifospay.core.network.services.ClientService -import org.mifospay.core.network.services.DocumentService -import org.mifospay.core.network.services.InvoiceService -import org.mifospay.core.network.services.KYCLevel1Service -import org.mifospay.core.network.services.NotificationService -import org.mifospay.core.network.services.RegistrationService -import org.mifospay.core.network.services.RunReportService -import org.mifospay.core.network.services.SavedCardService -import org.mifospay.core.network.services.SavingsAccountsService -import org.mifospay.core.network.services.SearchService -import org.mifospay.core.network.services.StandingInstructionService -import org.mifospay.core.network.services.ThirdPartyTransferService -import org.mifospay.core.network.services.TwoFactorAuthService -import org.mifospay.core.network.services.UserService import org.mifospay.core.network.services.createAccountTransfersService import org.mifospay.core.network.services.createAuthenticationService import org.mifospay.core.network.services.createBeneficiaryService @@ -60,122 +28,67 @@ import org.mifospay.core.network.services.createStandingInstructionService import org.mifospay.core.network.services.createThirdPartyTransferService import org.mifospay.core.network.services.createTwoFactorAuthService import org.mifospay.core.network.services.createUserService +import org.mifospay.core.network.utils.FlowConverterFactory class KtorfitClient( - private val httpClient: HttpClient, - private val ktorfit: Ktorfit, + ktorfit: Ktorfit, ) { - internal val authenticationApi: AuthenticationService = ktorfit.createAuthenticationService() + internal val authenticationApi by lazy { ktorfit.createAuthenticationService() } - internal val clientsApi: ClientService = ktorfit.createClientService() + internal val clientsApi by lazy { ktorfit.createClientService() } - internal val registrationAPi: RegistrationService = ktorfit.createRegistrationService() + internal val registrationAPi by lazy { ktorfit.createRegistrationService() } - internal val searchApi: SearchService = ktorfit.createSearchService() + internal val searchApi by lazy { ktorfit.createSearchService() } - internal val documentApi: DocumentService = ktorfit.createDocumentService() + internal val documentApi by lazy { ktorfit.createDocumentService() } - internal val runReportApi: RunReportService = ktorfit.createRunReportService() + internal val runReportApi by lazy { ktorfit.createRunReportService() } - internal val twoFactorAuthApi: TwoFactorAuthService = ktorfit.createTwoFactorAuthService() + internal val twoFactorAuthApi by lazy { ktorfit.createTwoFactorAuthService() } - internal val accountTransfersApi: AccountTransfersService = - ktorfit.createAccountTransfersService() + internal val accountTransfersApi by lazy { ktorfit.createAccountTransfersService() } - internal val savedCardApi: SavedCardService = ktorfit.createSavedCardService() + internal val savedCardApi by lazy { ktorfit.createSavedCardService() } - internal val kycLevel1Api: KYCLevel1Service = ktorfit.createKYCLevel1Service() + internal val kycLevel1Api by lazy { ktorfit.createKYCLevel1Service() } - internal val invoiceApi: InvoiceService = ktorfit.createInvoiceService() + internal val invoiceApi by lazy { ktorfit.createInvoiceService() } - internal val userApi: UserService = ktorfit.createUserService() + internal val userApi by lazy { ktorfit.createUserService() } - internal val thirdPartyTransferApi: ThirdPartyTransferService = - ktorfit.createThirdPartyTransferService() + internal val thirdPartyTransferApi by lazy { ktorfit.createThirdPartyTransferService() } - internal val notificationApi: NotificationService = ktorfit.createNotificationService() + internal val notificationApi by lazy { ktorfit.createNotificationService() } - internal val savingsAccountsApi: SavingsAccountsService = ktorfit.createSavingsAccountsService() + internal val savingsAccountsApi by lazy { ktorfit.createSavingsAccountsService() } - internal val standingInstructionApi: StandingInstructionService = - ktorfit.createStandingInstructionService() + internal val standingInstructionApi by lazy { ktorfit.createStandingInstructionService() } - internal val beneficiaryApi: BeneficiaryService = ktorfit.createBeneficiaryService() + internal val beneficiaryApi by lazy { ktorfit.createBeneficiaryService() } class Builder internal constructor() { private lateinit var baseURL: String - private var tenant: String? = BaseURL.DEFAULT - private var loginUsername: String? = null - private var loginPassword: String? = null - private var insecure: Boolean = false - private var token: String? = null + private lateinit var httpClient: HttpClient fun baseURL(baseURL: String): Builder { this.baseURL = baseURL return this } - fun tenant(tenant: String?): Builder { - this.tenant = tenant - return this - } - - fun basicAuth(username: String?, password: String?): Builder { - this.loginUsername = username - this.loginPassword = password - return this - } - - fun inSecure(insecure: Boolean): Builder { - this.insecure = insecure - return this - } - - fun token(token: String?): Builder { - this.token = token + fun httpClient(ktorHttpClient: HttpClient): Builder { + this.httpClient = ktorHttpClient return this } fun build(): KtorfitClient { - val ktorClient = HttpClient(CIO) { - install(ContentNegotiation) { - json( - Json { - isLenient = true - ignoreUnknownKeys = true - }, - ) - } - - install(DefaultRequest) - - install(Logging) { - logger = Logger.DEFAULT - level = LogLevel.INFO - } - - defaultRequest { - contentType(ContentType.Application.Json) - headers { - append("Accept", "application/json") - tenant?.let { - append(BaseURL.HEADER_TENANT, it) - } - token?.let { - append(BaseURL.HEADER_AUTH, it) - } - } - } - } - val ktorfitBuilder = Ktorfit.Builder() - .httpClient(ktorClient) + .httpClient(httpClient) .baseUrl(baseURL) - .converterFactories(CallConverterFactory()) .converterFactories(FlowConverterFactory()) .build() - return KtorfitClient(ktorClient, ktorfitBuilder) + return KtorfitClient(ktorfitBuilder) } } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt index a40f51b42..f5ff5d5dc 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt @@ -9,42 +9,73 @@ */ package org.mifospay.core.network.di -import kotlinx.serialization.json.Json +import io.ktor.client.HttpClient +import io.ktor.client.plugins.auth.Auth +import io.ktor.client.plugins.auth.providers.BasicAuthCredentials +import io.ktor.client.plugins.auth.providers.basic +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.request.header import org.koin.dsl.module -import org.mifospay.core.network.BaseURL import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.KtorfitClient import org.mifospay.core.network.SelfServiceApiManager +import org.mifospay.core.network.ktorHttpClient +import org.mifospay.core.network.utils.BaseURL +import org.mifospay.core.network.utils.KtorInterceptor val NetworkModule = module { - single { - Json { - ignoreUnknownKeys = true + single(KtorClient) { + ktorHttpClient.config { + install(Auth) + install(KtorInterceptor) { + preferenceRepository = get() + } + } + } + + // TODO:: This could be removed, added for testing + single(KtorBaseClient) { + ktorHttpClient.config { + install(Auth) { + basic { + sendWithoutRequest { true } + credentials { + BasicAuthCredentials( + username = "mifos", + password = "password", + ) + } + } + } + + defaultRequest { + header("Fineract-Platform-TenantId", "default") + header("Content-Type", "application/json") + header("Accept", "application/json") + } } } single(BaseClient) { KtorfitClient.builder() + .httpClient(get(KtorBaseClient)) .baseURL(BaseURL.url) .build() } - single(SelfClient) { + single(SelfClient) { KtorfitClient.builder() + .httpClient(get(KtorClient)) .baseURL(BaseURL.selfServiceUrl) .build() } single { - FineractApiManager( - ktorfitClient = get(BaseClient), - ) + FineractApiManager(ktorfitClient = get(BaseClient)) } single { - SelfServiceApiManager( - ktorfitClient = get(SelfClient), - ) + SelfServiceApiManager(ktorfitClient = get(SelfClient)) } } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt index ce5bbce78..9e5dc7469 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt @@ -13,15 +13,5 @@ import org.koin.core.qualifier.named val SelfClient = named("SelfClient") val BaseClient = named("BaseClient") - -val FineractAuthenticationService = named("FineractAuthenticationService") -val FineractClientService = named("FineractClientService") -val FineractSavingsAccountsService = named("FineractSavingsAccountsService") -val FineractRegistrationService = named("FineractRegistrationService") -val FineractThirdPartyTransferService = named("FineractThirdPartyTransferService") - -val SelfServiceAuthenticationService = named("SelfServiceAuthenticationService") -val SelfServiceClientService = named("SelfServiceClientService") -val SelfServiceSavingsAccountsService = named("SelfServiceSavingsAccountsService") -val SelfServiceRegistrationService = named("SelfServiceRegistrationService") -val SelfServiceThirdPartyTransferService = named("SelfServiceThirdPartyTransferService") +val KtorClient = named("KtorClient") +val KtorBaseClient = named("KtorBaseClient") diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt index 858c886f0..feed1e7e6 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt @@ -9,14 +9,8 @@ */ package org.mifospay.core.network.localAssets -import okio.FileHandle -import okio.FileSystem -import okio.Path.Companion.toPath -import okio.SYSTEM - internal object JvmLocalAssetManager : LocalAssetManager { - override fun open(fileName: String): FileHandle { - val path = fileName.toPath() - return FileSystem.SYSTEM.openReadOnly(path) + override fun open(fileName: String): String { + return "" } } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt index 98f8b1138..3f519965b 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt @@ -9,8 +9,6 @@ */ package org.mifospay.core.network.localAssets -import okio.FileHandle - fun interface LocalAssetManager { - fun open(fileName: String): FileHandle + fun open(fileName: String): String } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt index 78c4b9d60..417fc9810 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt @@ -18,7 +18,6 @@ import org.mifospay.core.model.State class MifosLocalAssetDataSource( private val ioDispatcher: CoroutineDispatcher, private val networkJson: Json, - private val assets: LocalAssetManager, ) : LocalAssetDataSource { override suspend fun getCountries(): List { diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Role.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponse.kt similarity index 59% rename from shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Role.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponse.kt index 29bd13e8d..5fb91288a 100644 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Role.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponse.kt @@ -7,11 +7,14 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared.modal.domain +package org.mifospay.core.network.model -data class Role( - var id: String? = null, - var name: String? = null, - var description: String? = null, - val disabled: Boolean, +import kotlinx.serialization.Serializable + +@Serializable +data class ClientResponse( + val officeId: Int, + val clientId: Int, + val resourceId: Int, + val savingsId: Int, ) diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt index 16c31ed4d..b5e7ae1ce 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt @@ -13,12 +13,12 @@ import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.accounts.savings.TransferDetail -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints /** * Created by ankur on 05/June/2018 */ interface AccountTransfersService { @GET(ApiEndPoints.ACCOUNT_TRANSFER + "/{transferId}") - fun getAccountTransfer(@Path("transferId") transferId: Long): Flow + suspend fun getAccountTransfer(@Path("transferId") transferId: Long): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt index 61daeae86..4c23736ef 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt @@ -11,12 +11,11 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.POST -import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.domain.user.User import org.mifospay.core.model.entity.authentication.AuthenticationPayload -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface AuthenticationService { @POST(ApiEndPoints.AUTHENTICATION) - fun authenticate(@Body authPayload: AuthenticationPayload): Flow + suspend fun authenticate(@Body authPayload: AuthenticationPayload): User } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt index f3baaabcf..c06628a2a 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt @@ -20,25 +20,25 @@ import org.mifospay.core.model.entity.beneficary.Beneficiary import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload import org.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.CommonResponse +import org.mifospay.core.network.utils.ApiEndPoints interface BeneficiaryService { @GET(ApiEndPoints.BENEFICIARIES + "/tpt") - fun beneficiaryList(): Flow> + suspend fun beneficiaryList(): Flow> @GET(ApiEndPoints.BENEFICIARIES + "/tpt/template") - fun beneficiaryTemplate(): Flow + suspend fun beneficiaryTemplate(): Flow @POST(ApiEndPoints.BENEFICIARIES + "/tpt") - fun createBeneficiary(@Body beneficiaryPayload: BeneficiaryPayload): Flow + suspend fun createBeneficiary(@Body beneficiaryPayload: BeneficiaryPayload): Flow @PUT(ApiEndPoints.BENEFICIARIES + "/tpt/{beneficiaryId}") - fun updateBeneficiary( + suspend fun updateBeneficiary( @Path("beneficiaryId") beneficiaryId: Long, @Body payload: BeneficiaryUpdatePayload, ): Flow @DELETE(ApiEndPoints.BENEFICIARIES + "/tpt/{beneficiaryId}") - fun deleteBeneficiary(@Path("beneficiaryId") beneficiaryId: Long): Flow + suspend fun deleteBeneficiary(@Path("beneficiaryId") beneficiaryId: Long): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt index fc8dee419..f32e8b422 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt @@ -10,6 +10,7 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Headers import de.jensklingenberg.ktorfit.http.POST @@ -21,40 +22,44 @@ import org.mifospay.core.model.domain.client.NewClient import org.mifospay.core.model.entity.Page import org.mifospay.core.model.entity.client.ClientAccounts import org.mifospay.core.model.entity.client.ClientEntity -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.model.ClientResponse +import org.mifospay.core.network.utils.ApiEndPoints interface ClientService { @GET(ApiEndPoints.CLIENTS) - fun clients(): Flow> + suspend fun clients(): Flow> @GET(ApiEndPoints.CLIENTS + "/{clientId}") - fun getClientForId(@Path("clientId") clientId: Long): Flow + suspend fun getClientForId(@Path("clientId") clientId: Long): ClientEntity @PUT(ApiEndPoints.CLIENTS + "/{clientId}") - fun updateClient( + suspend fun updateClient( @Path("clientId") clientId: Long, @Body payload: Any, ): Flow @GET(ApiEndPoints.CLIENTS + "/{clientId}/images") @Headers("Accept: text/plain") - fun getClientImage(@Path("clientId") clientId: Long): Flow + suspend fun getClientImage(@Path("clientId") clientId: Long): Flow @PUT(ApiEndPoints.CLIENTS + "/{clientId}/images") - fun updateClientImage( + suspend fun updateClientImage( @Path("clientId") clientId: Long, @Body typedFile: String?, ): Flow @GET(ApiEndPoints.CLIENTS + "/{clientId}/accounts") - fun getClientAccounts(@Path("clientId") clientId: Long): Flow + suspend fun getClientAccounts(@Path("clientId") clientId: Long): Flow @GET(ApiEndPoints.CLIENTS + "/{clientId}/accounts") - fun getAccounts( + suspend fun getAccounts( @Path("clientId") clientId: Long, @Query("fields") accountType: String, ): Flow @POST(ApiEndPoints.CLIENTS) - fun createClient(@Body newClient: NewClient): Flow + suspend fun createClient(@Body newClient: NewClient): ClientResponse + + @DELETE(ApiEndPoints.CLIENTS + "/{clientId}") + suspend fun deleteClient(@Path("clientId") clientId: Int): ClientResponse } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt index 43df8a93b..b605ad4e0 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt @@ -19,11 +19,11 @@ import de.jensklingenberg.ktorfit.http.Path import io.ktor.http.content.PartData import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.noncore.Document -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface DocumentService { @GET("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS) - fun getDocuments( + suspend fun getDocuments( @Path("entityType") entityType: String, @Path("entityId") entityId: Int, ): Flow> @@ -38,7 +38,7 @@ interface DocumentService { */ @POST("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS) @Multipart - fun createDocument( + suspend fun createDocument( @Path("entityType") entityType: String, @Path("entityId") entityId: Int, @Part("name") nameOfDocument: String, @@ -59,7 +59,7 @@ interface DocumentService { * @return ResponseBody */ @GET("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS + "/{documentId}/attachment") - fun downloadDocument( + suspend fun downloadDocument( @Path("entityType") entityType: String, @Path("entityId") entityId: Int, @Path("documentId") documentId: Int, @@ -77,7 +77,7 @@ interface DocumentService { * @param documentId - Document Id */ @DELETE("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS + "/{documentId}") - fun removeDocument( + suspend fun removeDocument( @Path("entityType") entityType: String, @Path("entityId") entityId: Int, @Path("documentId") documentId: Int, @@ -100,7 +100,7 @@ interface DocumentService { */ @PUT("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS + "/{documentId}") @Multipart - fun updateDocument( + suspend fun updateDocument( @Path("entityType") entityType: String, @Path("entityId") entityId: Int, @Path("documentId") documentId: Int, diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt index 7052adb17..94ac56fff 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt @@ -17,35 +17,35 @@ import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.Invoice -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints // TODO:: Fix this endpoints, there's no such endpoint for invoices interface InvoiceService { @GET(ApiEndPoints.DATATABLES + "/invoices/{clientId}") - fun getInvoices(@Path("clientId") clientId: Int): Flow> + suspend fun getInvoices(@Path("clientId") clientId: Int): Flow> @GET(ApiEndPoints.DATATABLES + "/invoices/{clientId}/{invoiceId}") - fun getInvoice( + suspend fun getInvoice( @Path("clientId") clientId: Int, @Path("invoiceId") invoiceId: Int, ): Flow @POST(ApiEndPoints.DATATABLES + "/invoices/{clientId}") - fun addInvoice( + suspend fun addInvoice( @Path("clientId") clientId: Int, @Body invoice: Invoice?, ): Unit @PUT(ApiEndPoints.DATATABLES + "/invoices/{clientId}/{invoiceId}") - fun updateInvoice( + suspend fun updateInvoice( @Path("clientId") clientId: Int, @Path("invoiceId") invoiceId: Int, @Body invoice: Invoice?, ): Flow @DELETE(ApiEndPoints.DATATABLES + "/invoices/{clientId}/{invoiceId}") - fun deleteInvoice( + suspend fun deleteInvoice( @Path("clientId") clientId: Int, @Path("invoiceId") invoiceId: Int, ): Flow diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt index 07e63bcb4..538863215 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt @@ -16,22 +16,22 @@ import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.kyc.KYCLevel1Details -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints interface KYCLevel1Service { @GET(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}") - fun fetchKYCLevel1Details(@Path("clientId") clientId: Int): Flow> + suspend fun fetchKYCLevel1Details(@Path("clientId") clientId: Int): Flow> @POST(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}") - fun addKYCLevel1Details( + suspend fun addKYCLevel1Details( @Path("clientId") clientId: Int, @Body kycLevel1Details: KYCLevel1Details, ): Flow @PUT(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}/") - fun updateKYCLevel1Details( + suspend fun updateKYCLevel1Details( @Path("clientId") clientId: Int, @Body kycLevel1Details: KYCLevel1Details, ): Flow diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt index 33c1dc603..a19c37df6 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt @@ -13,9 +13,9 @@ import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.domain.NotificationPayload -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface NotificationService { @GET(ApiEndPoints.DATATABLES + "/notifications/{clientId}") - fun fetchNotifications(@Path("clientId") clientId: Long): Flow> + suspend fun fetchNotifications(@Path("clientId") clientId: Long): Flow> } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt index d93401cf6..f93f575f4 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt @@ -13,12 +13,12 @@ import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.POST import org.mifospay.core.model.entity.register.RegisterPayload import org.mifospay.core.model.entity.register.UserVerify -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface RegistrationService { @POST(ApiEndPoints.REGISTRATION) - fun registerUser(@Body registerPayload: RegisterPayload) + suspend fun registerUser(@Body registerPayload: RegisterPayload) @POST(ApiEndPoints.REGISTRATION + "/user") - fun verifyUser(@Body userVerify: UserVerify) + suspend fun verifyUser(@Body userVerify: UserVerify) } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt index c502d067f..b32f50fab 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt @@ -13,11 +13,11 @@ import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Query import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface RunReportService { @GET(ApiEndPoints.RUN_REPORT + "/Savings Transaction Receipt") - fun getTransactionReceipt( + suspend fun getTransactionReceipt( @Query("output-type") outputType: String, @Query("R_transactionId") transactionId: String, ): Flow diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt index dcf5e4a60..d513872d8 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt @@ -17,27 +17,27 @@ import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.savedcards.Card -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints interface SavedCardService { @POST(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}") - fun addSavedCard( + suspend fun addSavedCard( @Path("clientId") clientId: Int, @Body card: Card, ): Flow @GET(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}") - fun getSavedCards(@Path("clientId") clientId: Int): Flow> + suspend fun getSavedCards(@Path("clientId") clientId: Int): Flow> @DELETE(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}/{cardId}") - fun deleteCard( + suspend fun deleteCard( @Path("clientId") clientId: Int, @Path("cardId") cardId: Int, ): Flow @PUT(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}/{cardId}") - fun updateCard( + suspend fun updateCard( @Path("clientId") clientId: Int, @Path("cardId") cardId: Int, @Body card: Card, diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt index 7927c84cd..1a20ce280 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt @@ -19,8 +19,8 @@ import org.mifospay.core.model.entity.Page import org.mifospay.core.model.entity.accounts.savings.SavingAccount import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints interface SavingsAccountsService { @GET(ApiEndPoints.SAVINGS_ACCOUNTS + "/{accountId}") diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt index c80edd09c..c075e395c 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt @@ -11,9 +11,8 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Query -import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.SearchedEntity -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface SearchService { @GET(ApiEndPoints.SEARCH) @@ -21,5 +20,5 @@ interface SearchService { @Query("query") query: String, @Query("resource") resources: String, @Query("exactMatch") exactMatch: Boolean, - ): Flow> + ): List } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt index 2fbd5cbe7..134d910a8 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt @@ -20,13 +20,13 @@ import org.mifospay.core.model.entity.Page import org.mifospay.core.model.entity.payload.StandingInstructionPayload import org.mifospay.core.model.entity.standinginstruction.SDIResponse import org.mifospay.core.model.entity.standinginstruction.StandingInstruction -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints interface StandingInstructionService { @POST(ApiEndPoints.STANDING_INSTRUCTION) - fun createStandingInstruction( + suspend fun createStandingInstruction( @Body standingInstructionPayload: StandingInstructionPayload, ): Flow @@ -35,12 +35,12 @@ interface StandingInstructionService { * @param clientId - passed as Query to limit the response to client specific response */ @GET(ApiEndPoints.STANDING_INSTRUCTION) - fun getAllStandingInstructions( + suspend fun getAllStandingInstructions( @Query("clientId") clientId: Long, ): Flow> @GET("${ApiEndPoints.STANDING_INSTRUCTION}/{standingInstructionId}") - fun getStandingInstruction( + suspend fun getStandingInstruction( @Path("standingInstructionId") standingInstructionId: Long, ): Flow @@ -53,13 +53,13 @@ interface StandingInstructionService { * will be performed. */ @PUT("${ApiEndPoints.STANDING_INSTRUCTION}/{standingInstructionId}") - fun deleteStandingInstruction( + suspend fun deleteStandingInstruction( @Path("standingInstructionId") standingInstructionId: Long, @Query("command") command: String, ): Flow @PUT("${ApiEndPoints.STANDING_INSTRUCTION}/{standingInstructionId}") - fun updateStandingInstruction( + suspend fun updateStandingInstruction( @Path("standingInstructionId") standingInstructionId: Long, @Body standingInstructionPayload: StandingInstructionPayload, @Query("command") command: String, diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt index 601234d2d..0586c2393 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt @@ -16,12 +16,12 @@ import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.TPTResponse import org.mifospay.core.model.entity.payload.TransferPayload import org.mifospay.core.model.entity.templates.account.AccountOptionsTemplate -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface ThirdPartyTransferService { @GET(ApiEndPoints.ACCOUNT_TRANSFER + "/template?type=tpt") - fun accountTransferTemplate(): Flow + suspend fun accountTransferTemplate(): Flow @POST(ApiEndPoints.ACCOUNT_TRANSFER + "?type=tpt") - fun makeTransfer(@Body transferPayload: TransferPayload): Flow + suspend fun makeTransfer(@Body transferPayload: TransferPayload): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt index c3defdb53..18b4f9a19 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt @@ -15,15 +15,15 @@ import de.jensklingenberg.ktorfit.http.Query import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.domain.twofactor.AccessToken import org.mifospay.core.model.domain.twofactor.DeliveryMethod -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface TwoFactorAuthService { @GET(ApiEndPoints.TWOFACTOR) - fun deliveryMethods(): Flow> + suspend fun deliveryMethods(): Flow> @POST(ApiEndPoints.TWOFACTOR) - fun requestOTP(@Query("deliveryMethod") deliveryMethod: String): Flow + suspend fun requestOTP(@Query("deliveryMethod") deliveryMethod: String): Flow @POST(ApiEndPoints.TWOFACTOR + "/validate") - fun validateToken(@Query("token") token: String): Flow + suspend fun validateToken(@Query("token") token: String): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt index 2a6c585f7..2ec6be88e 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt @@ -18,28 +18,34 @@ import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.domain.user.NewUser import org.mifospay.core.model.entity.UserWithRole -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.CommonResponse import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints interface UserService { @GET(ApiEndPoints.USER) - fun users(): Flow> + suspend fun users(): Flow> @POST(ApiEndPoints.USER) - fun createUser(@Body user: NewUser): Flow + suspend fun createUser(@Body user: NewUser): CommonResponse @PUT(ApiEndPoints.USER + "/{userId}") - fun updateUser( + suspend fun updateUser( @Path("userId") userId: Int, @Body updateUserEntity: NewUser, ): Flow @DELETE(ApiEndPoints.USER + "/{userId}") - fun deleteUser( + suspend fun deleteUser( @Path("userId") userId: Int, - ): Flow + ): CommonResponse @GET("self/userdetails") - fun getUser(): Flow + suspend fun getUser(): Flow + + @PUT(ApiEndPoints.USER + "/{userId}") + suspend fun assignClientToUser( + @Path("userId") userId: Int, + @Body clients: Map>, + ) } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/ApiEndPoints.kt similarity index 92% rename from core/network/src/commonMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/ApiEndPoints.kt index eb4d9bee8..19d8424b2 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/ApiEndPoints.kt @@ -7,11 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.network +package org.mifospay.core.network.utils object ApiEndPoints { // This class contains all the Constants for API End Points const val AUTHENTICATION = "authentication" + const val AUTHENTICATION_OAUTH = "oauth/token" const val REGISTRATION = "registration" const val CLIENTS = "clients" const val SAVINGS_ACCOUNTS = "savingsaccounts" diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/BaseURL.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/BaseURL.kt similarity index 96% rename from core/network/src/commonMain/kotlin/org/mifospay/core/network/BaseURL.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/BaseURL.kt index ed472d2e0..c274d11c3 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/BaseURL.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/BaseURL.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.network +package org.mifospay.core.network.utils object BaseURL { private const val PROTOCOL_HTTPS = "https://" diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/FlowConverterFactory.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/FlowConverterFactory.kt new file mode 100644 index 000000000..4943f05ef --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/FlowConverterFactory.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.utils + +import de.jensklingenberg.ktorfit.Ktorfit +import de.jensklingenberg.ktorfit.converter.Converter +import de.jensklingenberg.ktorfit.converter.KtorfitResult +import de.jensklingenberg.ktorfit.converter.TypeData +import io.ktor.client.call.body +import io.ktor.client.statement.HttpResponse +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +/** + * Factory that enables the use of Flow as return type + */ +public class FlowConverterFactory : Converter.Factory { + override fun responseConverter( + typeData: TypeData, + ktorfit: Ktorfit, + ): Converter.ResponseConverter? { + if (typeData.typeInfo.type == Flow::class) { + return object : Converter.ResponseConverter> { + override fun convert(getResponse: suspend () -> HttpResponse): Flow { + val requestType = typeData.typeArgs.first() + return flow { + val response = getResponse() + if (requestType.typeInfo.type == HttpResponse::class) { + emit(response) + } else { + val convertedBody = + ktorfit.nextSuspendResponseConverter( + this@FlowConverterFactory, + typeData.typeArgs.first(), + )?.convert(KtorfitResult.Success(response)) + ?: response.body(typeData.typeArgs.first().typeInfo) + emit(convertedBody) + } + } + } + } + } + return null + } +} diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt new file mode 100644 index 000000000..89fae835a --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.utils + +import io.ktor.client.HttpClient +import io.ktor.client.plugins.HttpClientPlugin +import io.ktor.client.request.HttpRequestPipeline +import io.ktor.client.request.header +import io.ktor.util.AttributeKey +import org.mifospay.core.datastore.UserPreferencesRepository + +class KtorInterceptor( + private val repository: UserPreferencesRepository, +) { + companion object Plugin : HttpClientPlugin { + private const val HEADER_TENANT = "Fineract-Platform-TenantId" + private const val HEADER_AUTH = "Authorization" + private const val DEFAULT = "venus" + + override val key: AttributeKey = AttributeKey("KtorInterceptor") + + override fun install(plugin: KtorInterceptor, scope: HttpClient) { + val authToken = plugin.repository.token.value + + scope.requestPipeline.intercept(HttpRequestPipeline.State) { + context.header("Content-Type", "application/json") + context.header("Accept", "application/json") + context.header(HEADER_TENANT, DEFAULT) + if (!authToken.isNullOrEmpty()) { + context.header(HEADER_AUTH, "Basic $authToken") + } + } + } + + override fun prepare(block: Config.() -> Unit): KtorInterceptor { + val config = Config().apply(block) + return KtorInterceptor(config.preferenceRepository!!) + } + } +} + +class Config( + var preferenceRepository: UserPreferencesRepository? = null, +) diff --git a/core/network/src/desktopMain/kotlin/org/mifospay/core/network/KtorJvmHttpClient.kt b/core/network/src/desktopMain/kotlin/org/mifospay/core/network/KtorJvmHttpClient.kt new file mode 100644 index 000000000..981faa77e --- /dev/null +++ b/core/network/src/desktopMain/kotlin/org/mifospay/core/network/KtorJvmHttpClient.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import io.ktor.client.HttpClient +import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json + +actual val ktorHttpClient: HttpClient + get() = HttpClient(OkHttp) { + expectSuccess = true + + install(HttpTimeout) { + socketTimeoutMillis = 60_000 + requestTimeoutMillis = 60_000 + } + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + co.touchlab.kermit.Logger.d(tag = "KtorClient", messageString = message) + } + } + } + + install(ContentNegotiation) { + json( + Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + explicitNulls = false + }, + ) + } + } diff --git a/core/network/src/jsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt b/core/network/src/jsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt new file mode 100644 index 000000000..f62b94c43 --- /dev/null +++ b/core/network/src/jsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import io.ktor.client.HttpClient +import io.ktor.client.engine.js.Js +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json + +actual val ktorHttpClient: HttpClient + get() = HttpClient(Js) { + expectSuccess = true + + install(HttpTimeout) { + socketTimeoutMillis = 60_000 + requestTimeoutMillis = 60_000 + } + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + co.touchlab.kermit.Logger.d(tag = "KtorClient", messageString = message) + } + } + } + + install(ContentNegotiation) { + json( + Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + explicitNulls = false + }, + ) + } + } diff --git a/core/network/src/nativeMain/kotlin/org/mifospay/core/network/KtorNativeHttpClient.kt b/core/network/src/nativeMain/kotlin/org/mifospay/core/network/KtorNativeHttpClient.kt new file mode 100644 index 000000000..7209585ce --- /dev/null +++ b/core/network/src/nativeMain/kotlin/org/mifospay/core/network/KtorNativeHttpClient.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import io.ktor.client.HttpClient +import io.ktor.client.engine.darwin.Darwin +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json + +actual val ktorHttpClient: HttpClient + get() = HttpClient(Darwin) { + expectSuccess = true + + install(HttpTimeout) { + socketTimeoutMillis = 60_000 + requestTimeoutMillis = 60_000 + } + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + co.touchlab.kermit.Logger.d(tag = "KtorClient", messageString = message) + } + } + } + + install(ContentNegotiation) { + json( + Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + explicitNulls = false + }, + ) + } + } diff --git a/core/network/src/wasmJsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt b/core/network/src/wasmJsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt new file mode 100644 index 000000000..f62b94c43 --- /dev/null +++ b/core/network/src/wasmJsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import io.ktor.client.HttpClient +import io.ktor.client.engine.js.Js +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json + +actual val ktorHttpClient: HttpClient + get() = HttpClient(Js) { + expectSuccess = true + + install(HttpTimeout) { + socketTimeoutMillis = 60_000 + requestTimeoutMillis = 60_000 + } + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + co.touchlab.kermit.Logger.d(tag = "KtorClient", messageString = message) + } + } + } + + install(ContentNegotiation) { + json( + Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + explicitNulls = false + }, + ) + } + } diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index ae180d6af..0bb0546c4 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -30,6 +30,9 @@ kotlin { api(projects.core.designsystem) api(projects.core.model) api(projects.core.common) + implementation(libs.jb.composeViewmodel) + implementation(libs.jb.lifecycleViewmodel) + implementation(libs.jb.lifecycleViewmodelSavedState) implementation(libs.coil.kt) implementation(libs.coil.kt.compose) implementation(compose.material3) diff --git a/mifospay/src/main/res/drawable/mifospay_round_logo.png b/core/ui/src/commonMain/composeResources/drawable/feature_receipt_mifospay_round_logo.png similarity index 100% rename from mifospay/src/main/res/drawable/mifospay_round_logo.png rename to core/ui/src/commonMain/composeResources/drawable/feature_receipt_mifospay_round_logo.png diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/MifosPasswordField.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/MifosPasswordField.kt new file mode 100644 index 000000000..fbbcb3f00 --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/MifosPasswordField.kt @@ -0,0 +1,189 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui + +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +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.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.designsystem.utils.tabNavigation + +@Composable +fun MifosPasswordField( + label: String, + value: String, + showPassword: Boolean, + showPasswordChange: (Boolean) -> Unit, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + readOnly: Boolean = false, + singleLine: Boolean = true, + hint: String? = null, + showPasswordTestTag: String? = null, + autoFocus: Boolean = false, + keyboardType: KeyboardType = KeyboardType.Password, + imeAction: ImeAction = ImeAction.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, +) { + val focusRequester = remember { FocusRequester() } + OutlinedTextField( + modifier = modifier + .tabNavigation() + .focusRequester(focusRequester), + label = { Text(text = label) }, + value = value, + onValueChange = onValueChange, + visualTransformation = when { + !showPassword -> PasswordVisualTransformation() + readOnly -> nonLetterColorVisualTransformation() + else -> VisualTransformation.None + }, + singleLine = singleLine, + readOnly = readOnly, + keyboardOptions = KeyboardOptions( + keyboardType = keyboardType, + imeAction = imeAction, + ), + keyboardActions = keyboardActions, + supportingText = hint?.let { + { + Text( + text = hint, + style = MaterialTheme.typography.bodySmall, + ) + } + }, + trailingIcon = { + IconButton( + onClick = { showPasswordChange.invoke(!showPassword) }, + ) { + val imageVector = if (showPassword) { + MifosIcons.VisibilityOff + } else { + MifosIcons.Visibility + } + + Icon( + modifier = Modifier.semantics { showPasswordTestTag?.let { testTag = it } }, + imageVector = imageVector, + contentDescription = "togglePassword", + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + }, + ) + if (autoFocus) { + LaunchedEffect(Unit) { focusRequester.requestFocus() } + } +} + +@Composable +fun MifosPasswordField( + label: String, + value: String, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + readOnly: Boolean = false, + singleLine: Boolean = true, + hint: String? = null, + initialShowPassword: Boolean = false, + showPasswordTestTag: String? = null, + autoFocus: Boolean = false, + keyboardType: KeyboardType = KeyboardType.Password, + imeAction: ImeAction = ImeAction.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, +) { + var showPassword by rememberSaveable { mutableStateOf(initialShowPassword) } + MifosPasswordField( + modifier = modifier, + label = label, + value = value, + showPassword = showPassword, + showPasswordChange = { showPassword = !showPassword }, + onValueChange = onValueChange, + readOnly = readOnly, + singleLine = singleLine, + hint = hint, + showPasswordTestTag = showPasswordTestTag, + autoFocus = autoFocus, + keyboardType = keyboardType, + imeAction = imeAction, + keyboardActions = keyboardActions, + ) +} + +@Preview +@Composable +private fun MifosPasswordField_preview_withInput_hidePassword() { + MifosPasswordField( + label = "Label", + value = "Password", + onValueChange = {}, + initialShowPassword = false, + hint = "Hint", + ) +} + +@Preview +@Composable +private fun MifosPasswordField_preview_withInput_showPassword() { + MifosPasswordField( + label = "Label", + value = "Password", + onValueChange = {}, + initialShowPassword = true, + hint = "Hint", + ) +} + +@Preview +@Composable +private fun MifosPasswordField_preview_withoutInput_hidePassword() { + MifosPasswordField( + label = "Label", + value = "", + onValueChange = {}, + initialShowPassword = false, + hint = "Hint", + ) +} + +@Preview +@Composable +private fun MifosPasswordField_preview_withoutInput_showPassword() { + MifosPasswordField( + label = "Label", + value = "", + onValueChange = {}, + initialShowPassword = true, + hint = "Hint", + ) +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/NonLetterColorVisualTransformation.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/NonLetterColorVisualTransformation.kt new file mode 100644 index 000000000..d7051993d --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/NonLetterColorVisualTransformation.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui + +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.input.OffsetMapping +import androidx.compose.ui.text.input.TransformedText +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.withStyle + +@Composable +fun nonLetterColorVisualTransformation(): VisualTransformation { + val digitColor = MaterialTheme.colorScheme.primary + val specialCharacterColor = MaterialTheme.colorScheme.error + return remember(digitColor, specialCharacterColor) { + NonLetterColorVisualTransformation( + digitColor = digitColor, + specialCharacterColor = specialCharacterColor, + ) + } +} + +private class NonLetterColorVisualTransformation( + private val digitColor: Color, + private val specialCharacterColor: Color, +) : VisualTransformation { + + override fun filter(text: AnnotatedString): TransformedText = + TransformedText( + buildTransformedAnnotatedString(text.toString()), + OffsetMapping.Identity, + ) + + private fun buildTransformedAnnotatedString(text: String): AnnotatedString { + val builder = AnnotatedString.Builder() + text.toCharArray().forEach { char -> + when { + char.isDigit() -> builder.withStyle(SpanStyle(color = digitColor)) { append(char) } + + !char.isLetter() -> { + builder.withStyle(SpanStyle(color = specialCharacterColor)) { append(char) } + } + + else -> builder.append(char) + } + } + return builder.toAnnotatedString() + } +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BackgroundEvent.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BackgroundEvent.kt new file mode 100644 index 000000000..0e6459add --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BackgroundEvent.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +/** + * Almost all the events in the app involve navigation or toasts. To prevent accidentally + * navigating to the same view twice, by default, events are ignored if the view is not currently + * resumed. To avoid that restriction, specific events can implement [BackgroundEvent]. + */ +interface BackgroundEvent diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BaseViewModel.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BaseViewModel.kt new file mode 100644 index 000000000..b955bf226 --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BaseViewModel.kt @@ -0,0 +1,100 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.SendChannel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.consumeAsFlow +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.launch + +/** + * A base [ViewModel] that helps enforce the unidirectional data flow pattern and associated + * responsibilities of a typical ViewModel: + * + * - Maintaining and emitting a current state (of type [S]) with the given `initialState`. + * - Emitting one-shot events as needed (of type [E]). These should be rare and are typically + * reserved for things such as non-state based navigation. + * - Receiving actions (of type [A]) that may induce changes in the current state, trigger an + * event emission, or both. + */ +abstract class BaseViewModel( + initialState: S, +) : ViewModel() { + protected val mutableStateFlow: MutableStateFlow = MutableStateFlow(initialState) + private val eventChannel: Channel = Channel(capacity = Channel.UNLIMITED) + private val internalActionChannel: Channel = Channel(capacity = Channel.UNLIMITED) + + /** + * A helper that returns the current state of the view model. + */ + protected val state: S get() = mutableStateFlow.value + + /** + * A [StateFlow] representing state updates. + */ + val stateFlow: StateFlow = mutableStateFlow.asStateFlow() + + /** + * A [Flow] of one-shot events. These may be received and consumed by only a single consumer. + * Any additional consumers will receive no events. + */ + val eventFlow: Flow = eventChannel.receiveAsFlow() + + /** + * A [SendChannel] for sending actions to the ViewModel for processing. + */ + val actionChannel: SendChannel = internalActionChannel + + init { + viewModelScope.launch { + internalActionChannel + .consumeAsFlow() + .collect { action -> + handleAction(action) + } + } + } + + /** + * Handles the given [action] in a synchronous manner. + * + * Any changes to internal state that first require asynchronous work should post a follow-up + * action that may be used to then update the state synchronously. + */ + protected abstract fun handleAction(action: A): Unit + + /** + * Convenience method for sending an action to the [actionChannel]. + */ + fun trySendAction(action: A) { + actionChannel.trySend(action) + } + + /** + * Helper method for sending an internal action. + */ + protected suspend fun sendAction(action: A) { + actionChannel.send(action) + } + + /** + * Helper method for sending an event. + */ + protected fun sendEvent(event: E) { + viewModelScope.launch { eventChannel.send(event) } + } +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/EventsEffect.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/EventsEffect.kt new file mode 100644 index 000000000..b10cfdd8c --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/EventsEffect.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +/** + * Convenience method for observing event flow from [BaseViewModel]. + * + * By default, events will only be consumed when the associated screen is + * resumed, to avoid bugs like duplicate navigation calls. To override + * this behavior, a given event type can implement [BackgroundEvent]. + */ +@Composable +fun EventsEffect( + viewModel: BaseViewModel<*, E, *>, + lifecycleOwner: Lifecycle = LocalLifecycleOwner.current.lifecycle, + handler: suspend (E) -> Unit, +) { + LaunchedEffect(key1 = Unit) { + viewModel.eventFlow + .filter { + it is BackgroundEvent || + lifecycleOwner.currentState.isAtLeast(Lifecycle.State.RESUMED) + } + .onEach { handler.invoke(it) } + .launchIn(this) + } +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/LifecycleEventEffect.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/LifecycleEventEffect.kt new file mode 100644 index 000000000..98e75cf87 --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/LifecycleEventEffect.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner + +/** + * Creates a side effect to observe lifecycle events. + */ +@Composable +fun LivecycleEventEffect( + onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit, +) { + val eventHandler = rememberUpdatedState(onEvent) + val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current) + + DisposableEffect(lifecycleOwner.value) { + val lifecycle = lifecycleOwner.value.lifecycle + val observer = LifecycleEventObserver { owner, event -> + eventHandler.value(owner, event) + } + + lifecycle.addObserver(observer) + onDispose { + lifecycle.removeObserver(observer) + } + } +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordChecker.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordChecker.kt new file mode 100644 index 000000000..8b7f5bb94 --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordChecker.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +import kotlin.math.log2 +import kotlin.math.pow + +object PasswordChecker { + private const val MIN_PASSWORD_LENGTH = 8 + private const val STRONG_PASSWORD_LENGTH = 12 + private const val MIN_ENTROPY_BITS = 60.0 + private const val MAX_PASSWORD_LENGTH = 128 + + fun getPasswordStrengthResult(password: String): PasswordStrengthResult { + when { + password.isEmpty() -> return PasswordStrengthResult.Error("Password cannot be empty.") + password.length > MAX_PASSWORD_LENGTH -> { + return PasswordStrengthResult.Error( + "Password is too long. Maximum length is $MAX_PASSWORD_LENGTH characters.", + ) + } + } + + val result = getPasswordStrength(password) + + return PasswordStrengthResult.Success(result) + } + + fun getPasswordStrength(password: String): PasswordStrength { + val length = password.length + val hasUpperCase = password.any { it.isUpperCase() } + val hasLowerCase = password.any { it.isLowerCase() } + val hasNumbers = password.any { it.isDigit() } + val hasSymbols = password.any { !it.isLetterOrDigit() } + + val numTypesPresent = + listOf(hasUpperCase, hasLowerCase, hasNumbers, hasSymbols).count { it } + val entropyBits = calculateEntropy(password) + + return when { + length < MIN_PASSWORD_LENGTH -> PasswordStrength.LEVEL_0 + numTypesPresent == 1 -> PasswordStrength.LEVEL_1 + numTypesPresent == 2 -> PasswordStrength.LEVEL_2 + numTypesPresent == 3 && length >= STRONG_PASSWORD_LENGTH -> PasswordStrength.LEVEL_4 + numTypesPresent == 4 && length >= STRONG_PASSWORD_LENGTH && + entropyBits >= MIN_ENTROPY_BITS -> PasswordStrength.LEVEL_5 + + else -> PasswordStrength.LEVEL_3 + } + } + + private fun calculateEntropy(password: String): Double { + val charPool = 26 + 26 + 10 + 33 // lowercase + uppercase + digits + symbols + return log2(charPool.toDouble().pow(password.length)) + } + + fun getPasswordFeedback(password: String): List { + val feedback = mutableListOf() + + if (password.length < MIN_PASSWORD_LENGTH) { + feedback.add("Password should be at least $MIN_PASSWORD_LENGTH characters long.") + } + if (!password.any { it.isUpperCase() }) { + feedback.add("Include at least one uppercase letter.") + } + if (!password.any { it.isLowerCase() }) { + feedback.add("Include at least one lowercase letter.") + } + if (!password.any { it.isDigit() }) { + feedback.add("Include at least one number.") + } + if (!password.any { !it.isLetterOrDigit() }) { + feedback.add("Include at least one special character.") + } + if (password.length < STRONG_PASSWORD_LENGTH) { + feedback.add("For a stronger password, use at least $STRONG_PASSWORD_LENGTH characters.") + } + + return feedback + } +} + +sealed class PasswordStrengthResult { + data class Success(val passwordStrength: PasswordStrength) : PasswordStrengthResult() + + data class Error(val message: String) : PasswordStrengthResult() +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/PasswordStrength.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrength.kt similarity index 74% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/PasswordStrength.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrength.kt index b8c6ebd33..033554673 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/PasswordStrength.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrength.kt @@ -7,13 +7,13 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.signup +package org.mifospay.core.ui.utils enum class PasswordStrength { - WEAK, - MODERATE, - STRONG, - VERY_STRONG, - EXCELLENT, - INVALID, + LEVEL_0, + LEVEL_1, + LEVEL_2, + LEVEL_3, + LEVEL_4, + LEVEL_5, } diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrengthExtensions.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrengthExtensions.kt new file mode 100644 index 000000000..eecae452d --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrengthExtensions.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +/** + * Converts the given [Int] to a [PasswordStrength]. A `null` value is returned if this value is + * not in the [0, 4] range. + */ +@Suppress("MagicNumber") +fun Int.toPasswordStrengthOrNull(): PasswordStrength? = + when (this) { + 0 -> PasswordStrength.LEVEL_0 + 1 -> PasswordStrength.LEVEL_1 + 2 -> PasswordStrength.LEVEL_2 + 3 -> PasswordStrength.LEVEL_3 + 4 -> PasswordStrength.LEVEL_4 + 5 -> PasswordStrength.LEVEL_5 + else -> null + } + +/** + * Converts the given [PasswordStrength] to an [Int]. + */ +@Suppress("MagicNumber") +fun PasswordStrength.toInt(): Int = + when (this) { + PasswordStrength.LEVEL_0 -> 0 + PasswordStrength.LEVEL_1 -> 1 + PasswordStrength.LEVEL_2 -> 2 + PasswordStrength.LEVEL_3 -> 3 + PasswordStrength.LEVEL_4 -> 4 + PasswordStrength.LEVEL_5 -> 5 + } diff --git a/feature/auth/build.gradle.kts b/feature/auth/build.gradle.kts index ae4c6d07b..2eb49adfd 100644 --- a/feature/auth/build.gradle.kts +++ b/feature/auth/build.gradle.kts @@ -8,8 +8,9 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.feature) - alias(libs.plugins.mifospay.android.library.compose) + alias(libs.plugins.mifospay.cmp.feature) + alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.kotlin.serialization) } android { @@ -19,15 +20,32 @@ android { } } -dependencies { - implementation(projects.libs.countryCodePicker) +kotlin { + sourceSets { + commonMain.dependencies { + implementation(projects.core.domain) + implementation(compose.material3) + implementation(compose.foundation) + implementation(compose.ui) + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) + implementation(libs.koin.compose.viewmodel) + implementation(libs.koin.compose) + implementation(libs.jb.kotlin.stdlib) + implementation(libs.kotlin.reflect) + } - // Credentials Manager - implementation(libs.androidx.credentials) - // optional - needed for credentials support from play services, for devices running - // Android 13 and below. - implementation(libs.androidx.credentials.play.services.auth) - implementation(libs.googleid) + androidMain.dependencies { + implementation(projects.libs.countryCodePicker) - implementation(libs.play.services.auth) + // Credentials Manager + implementation(libs.androidx.credentials) + // optional - needed for credentials support from play services, for devices running + // Android 13 and below. + implementation(libs.androidx.credentials.play.services.auth) + implementation(libs.googleid) + + implementation(libs.play.services.auth) + } + } } \ No newline at end of file diff --git a/feature/auth/src/main/AndroidManifest.xml b/feature/auth/src/androidMain/AndroidManifest.xml similarity index 100% rename from feature/auth/src/main/AndroidManifest.xml rename to feature/auth/src/androidMain/AndroidManifest.xml diff --git a/feature/auth/src/main/res/values/strings.xml b/feature/auth/src/commonMain/composeResources/values/strings.xml similarity index 91% rename from feature/auth/src/main/res/values/strings.xml rename to feature/auth/src/commonMain/composeResources/values/strings.xml index 13745ed1c..acc1b6be0 100644 --- a/feature/auth/src/main/res/values/strings.xml +++ b/feature/auth/src/commonMain/composeResources/values/strings.xml @@ -20,7 +20,7 @@ Sign up as merchant Sign up as customer or - Ease my sign up using Google Account + Ease my sign up using Google Account Please enter a valid email address All fields are mandatory. Complete your registration @@ -33,6 +33,8 @@ Address Line 2 Pin Code State + Country + Mobile No Complete Please wait… Mandatory field @@ -46,7 +48,7 @@ It should be currently activated on your device and linked with your bank account as well. - Enter otp received on your registered device + Enter otp received on your registered device Verify Phone Verify Otp Phone Number diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/di/AuthModule.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/di/AuthModule.kt new file mode 100644 index 000000000..126684fd3 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/di/AuthModule.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.di + +import org.koin.core.module.dsl.viewModelOf +import org.koin.dsl.module +import org.mifospay.feature.auth.login.LoginViewModel +import org.mifospay.feature.auth.mobileVerify.MobileVerificationViewModel +import org.mifospay.feature.auth.signup.SignupViewModel + +val AuthModule = module { + viewModelOf(::LoginViewModel) + viewModelOf(::SignupViewModel) + viewModelOf(::MobileVerificationViewModel) +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt new file mode 100644 index 000000000..0f673bb5a --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt @@ -0,0 +1,252 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.login + +import androidx.compose.foundation.clickable +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.Spacer +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.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch +import mobile_wallet.feature.auth.generated.resources.Res +import mobile_wallet.feature.auth.generated.resources.feature_auth_login +import mobile_wallet.feature.auth.generated.resources.feature_auth_password +import mobile_wallet.feature.auth.generated.resources.feature_auth_sign_up +import mobile_wallet.feature.auth.generated.resources.feature_auth_username +import mobile_wallet.feature.auth.generated.resources.feature_auth_welcome_back +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.koin.compose.viewmodel.koinViewModel +import org.mifospay.core.designsystem.component.BasicDialogState +import org.mifospay.core.designsystem.component.LoadingDialogState +import org.mifospay.core.designsystem.component.MifosBasicDialog +import org.mifospay.core.designsystem.component.MifosButton +import org.mifospay.core.designsystem.component.MifosLoadingDialog +import org.mifospay.core.designsystem.component.MifosOutlinedTextField +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.designsystem.theme.MifosTheme +import org.mifospay.core.designsystem.theme.grey +import org.mifospay.core.designsystem.theme.styleNormal18sp +import org.mifospay.core.ui.utils.EventsEffect + +@Composable +internal fun LoginScreen( + onNavigateBack: () -> Unit, + navigateToPasscodeScreen: () -> Unit, + navigateToSignupScreen: () -> Unit, + modifier: Modifier = Modifier, + viewModel: LoginViewModel = koinViewModel(), +) { + val state by viewModel.stateFlow.collectAsState() + val snackbarHostState = remember { SnackbarHostState() } + val scope = rememberCoroutineScope() + + EventsEffect(viewModel) { event -> + when (event) { + is LoginEvent.NavigateBack -> onNavigateBack.invoke() + is LoginEvent.NavigateToSignup -> navigateToSignupScreen.invoke() + is LoginEvent.NavigateToPasscodeScreen -> navigateToPasscodeScreen.invoke() + is LoginEvent.ShowToast -> { + scope.launch { + snackbarHostState.showSnackbar(event.message) + } + } + } + } + + LoginDialogs( + dialogState = state.dialogState, + onDismissRequest = remember(viewModel) { + { viewModel.trySendAction(LoginAction.ErrorDialogDismiss) } + }, + ) + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + modifier = modifier.fillMaxSize(), + containerColor = MaterialTheme.colorScheme.background, + ) { paddingValues -> + LoginScreenContent( + state = state, + onEvent = remember(viewModel) { + { viewModel.trySendAction(it) } + }, + modifier = modifier.padding(paddingValues), + navigateToSignupScreen = navigateToSignupScreen, + ) + } +} + +@Composable +private fun LoginDialogs( + dialogState: LoginState.DialogState?, + onDismissRequest: () -> Unit, +) { + when (dialogState) { + is LoginState.DialogState.Error -> MifosBasicDialog( + visibilityState = BasicDialogState.Shown( + message = dialogState.message, + ), + onDismissRequest = onDismissRequest, + ) + + is LoginState.DialogState.Loading -> MifosLoadingDialog( + visibilityState = LoadingDialogState.Shown, + ) + + null -> Unit + } +} + +@Composable +private fun LoginScreenContent( + state: LoginState, + onEvent: (LoginAction) -> Unit, + modifier: Modifier = Modifier, + navigateToSignupScreen: () -> Unit, +) { + Column( + modifier = modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(horizontal = 24.dp) + .padding(top = 100.dp), + horizontalAlignment = Alignment.Start, + ) { + Text( + text = stringResource(Res.string.feature_auth_login), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.primary, + ) + Text( + modifier = Modifier + .padding(top = 24.dp), + text = stringResource(Res.string.feature_auth_welcome_back), + style = styleNormal18sp.copy(color = grey), + ) + Spacer(modifier = Modifier.padding(top = 32.dp)) + MifosOutlinedTextField( + label = stringResource(Res.string.feature_auth_username), + value = state.username, + onValueChange = { + onEvent(LoginAction.UsernameChanged(it)) + }, + modifier = Modifier.fillMaxWidth(), + ) + Spacer(modifier = Modifier.padding(top = 16.dp)) + MifosOutlinedTextField( + label = stringResource(Res.string.feature_auth_password), + value = state.password, + onValueChange = { + onEvent(LoginAction.PasswordChanged(it)) + }, + modifier = Modifier.fillMaxWidth(), + visualTransformation = if (state.isPasswordVisible) { + VisualTransformation.None + } else { + PasswordVisualTransformation() + }, + trailingIcon = { + val icon = if (state.isPasswordVisible) { + MifosIcons.Visibility + } else { + MifosIcons.VisibilityOff + } + IconButton( + onClick = { onEvent(LoginAction.TogglePasswordVisibility) }, + ) { + Icon(imageVector = icon, null) + } + }, + ) + val isLoginButtonEnabled = state.username.isNotEmpty() && state.password.isNotEmpty() + MifosButton( + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp), + enabled = isLoginButtonEnabled, + onClick = { + onEvent(LoginAction.LoginClicked) + }, + contentPadding = PaddingValues(12.dp), + ) { + Text( + text = stringResource(Res.string.feature_auth_login).uppercase(), + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.onPrimary, + ) + } + + SignupButton { navigateToSignupScreen() } + } +} + +@Composable +private fun SignupButton( + navigateToSignupScreen: () -> Unit, +) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 24.dp), + horizontalArrangement = Arrangement.Center, + ) { + Text( + text = "Don’t have an account yet? ", + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.onSurface, + ) + Text( + modifier = Modifier.clickable { + navigateToSignupScreen() + }, + text = stringResource(Res.string.feature_auth_sign_up), + style = MaterialTheme.typography.titleMedium.copy( + textDecoration = TextDecoration.Underline, + ), + ) + } +} + +@Preview +@Composable +private fun LoanScreenPreview() { + MifosTheme { + LoginScreenContent( + state = LoginState(dialogState = null), + onEvent = {}, + navigateToSignupScreen = {}, + ) + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt new file mode 100644 index 000000000..9bd45e200 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt @@ -0,0 +1,154 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.login + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.mifospay.core.common.IgnoredOnParcel +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize +import org.mifospay.core.common.Result +import org.mifospay.core.domain.LoginUseCase +import org.mifospay.core.model.domain.user.User +import org.mifospay.core.ui.utils.BaseViewModel + +private const val KEY_STATE = "state" + +class LoginViewModel( + private val loginUseCase: LoginUseCase, + savedStateHandle: SavedStateHandle, +) : BaseViewModel( + initialState = savedStateHandle[KEY_STATE] ?: LoginState(dialogState = null), +) { + + init { + savedStateHandle.get("username")?.let { + trySendAction(LoginAction.UsernameChanged(it)) + } + } + + override fun handleAction(action: LoginAction) { + when (action) { + is LoginAction.UsernameChanged -> { + mutableStateFlow.update { + it.copy(username = action.username) + } + } + + is LoginAction.PasswordChanged -> { + mutableStateFlow.update { + it.copy(password = action.password) + } + } + + is LoginAction.TogglePasswordVisibility -> { + mutableStateFlow.update { + it.copy(isPasswordVisible = !it.isPasswordVisible) + } + } + + is LoginAction.LoginClicked -> { + loginUser(state.username, state.password) + } + + is LoginAction.Internal.ReceiveLoginResult -> { + handleLoginResult(action) + } + + is LoginAction.SignupClicked -> { + sendEvent(LoginEvent.NavigateToSignup) + } + + is LoginAction.ErrorDialogDismiss -> { + mutableStateFlow.update { it.copy(dialogState = null) } + } + } + } + + private fun handleLoginResult(action: LoginAction.Internal.ReceiveLoginResult) { + when (action.loginResult) { + is Result.Error -> { + val message = action.loginResult.exception.message ?: "" + + mutableStateFlow.update { + it.copy(dialogState = LoginState.DialogState.Error(message)) + } + } + + is Result.Loading -> { + mutableStateFlow.update { + it.copy(dialogState = LoginState.DialogState.Loading) + } + } + + is Result.Success -> { + mutableStateFlow.update { + it.copy(dialogState = null) + } + sendEvent(LoginEvent.NavigateToPasscodeScreen) + } + } + } + + private fun loginUser( + username: String, + password: String, + ) { + mutableStateFlow.update { + it.copy(dialogState = LoginState.DialogState.Loading) + } + + viewModelScope.launch { + val result = loginUseCase(username, password) + sendAction(LoginAction.Internal.ReceiveLoginResult(result)) + } + } +} + +@Parcelize +data class LoginState( + val username: String = "", + @IgnoredOnParcel + val password: String = "", + val isPasswordVisible: Boolean = false, + val dialogState: DialogState?, +) : Parcelable { + sealed class DialogState : Parcelable { + @Parcelize + data class Error(val message: String) : DialogState() + + @Parcelize + data object Loading : DialogState() + } +} + +sealed class LoginEvent { + data object NavigateBack : LoginEvent() + data object NavigateToSignup : LoginEvent() + data object NavigateToPasscodeScreen : LoginEvent() + data class ShowToast(val message: String) : LoginEvent() +} + +sealed class LoginAction { + data class UsernameChanged(val username: String) : LoginAction() + data class PasswordChanged(val password: String) : LoginAction() + data object TogglePasswordVisibility : LoginAction() + data object ErrorDialogDismiss : LoginAction() + data object LoginClicked : LoginAction() + data object SignupClicked : LoginAction() + + sealed class Internal : LoginAction() { + data class ReceiveLoginResult( + val loginResult: Result, + ) : Internal() + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt new file mode 100644 index 000000000..d81788914 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt @@ -0,0 +1,291 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.mobileVerify + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTopAppBarState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch +import mobile_wallet.feature.auth.generated.resources.Res +import mobile_wallet.feature.auth.generated.resources.feature_auth_enter_mobile_number +import mobile_wallet.feature.auth.generated.resources.feature_auth_enter_mobile_number_description +import mobile_wallet.feature.auth.generated.resources.feature_auth_enter_otp +import mobile_wallet.feature.auth.generated.resources.feature_auth_enter_otp_received +import mobile_wallet.feature.auth.generated.resources.feature_auth_phone_number +import mobile_wallet.feature.auth.generated.resources.feature_auth_verify_otp +import mobile_wallet.feature.auth.generated.resources.feature_auth_verify_phone +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.koin.compose.viewmodel.koinViewModel +import org.mifospay.core.designsystem.component.BasicDialogState +import org.mifospay.core.designsystem.component.LoadingDialogState +import org.mifospay.core.designsystem.component.MifosBasicDialog +import org.mifospay.core.designsystem.component.MifosButton +import org.mifospay.core.designsystem.component.MifosLoadingDialog +import org.mifospay.core.designsystem.component.MifosOutlinedTextField +import org.mifospay.core.designsystem.component.MifosScaffold +import org.mifospay.core.designsystem.component.MifosTopAppBar +import org.mifospay.core.designsystem.component.NavigationIcon +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.designsystem.theme.MifosTheme +import org.mifospay.core.ui.utils.EventsEffect + +@Composable +internal fun MobileVerificationScreen( + onNavigateBack: () -> Unit, + onOtpVerificationSuccess: (String) -> Unit, + modifier: Modifier = Modifier, + viewModel: MobileVerificationViewModel = koinViewModel(), +) { + val state by viewModel.stateFlow.collectAsState() + val snackbarHostState = remember { SnackbarHostState() } + val scope = rememberCoroutineScope() + + EventsEffect(viewModel) { event -> + when (event) { + is MobileVerificationEvent.NavigateBack -> onNavigateBack.invoke() + + is MobileVerificationEvent.NavigateToSignup -> { + onOtpVerificationSuccess(event.phoneNo) + } + + is MobileVerificationEvent.ShowToast -> { + scope.launch { + snackbarHostState.showSnackbar(event.message) + } + } + } + } + + MobileVerificationScreen( + uiState = state, + onEvent = remember(viewModel) { + { viewModel.trySendAction(it) } + }, + snackbarHostState = snackbarHostState, + modifier = modifier, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun MobileVerificationScreen( + uiState: MobileVerificationState, + onEvent: (MobileVerificationAction) -> Unit, + modifier: Modifier = Modifier, + snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }, +) { + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) + + val title = if (uiState is MobileVerificationState.VerifyPhoneState) { + stringResource(Res.string.feature_auth_enter_mobile_number) + } else { + stringResource(Res.string.feature_auth_enter_otp) + } + + MifosScaffold( + modifier = modifier.fillMaxSize(), + snackbarHostState = snackbarHostState, + topBar = { + MifosTopAppBar( + title = title, + scrollBehavior = scrollBehavior, + navigationIcon = NavigationIcon( + navigationIcon = MifosIcons.Back, + navigationIconContentDescription = "Go Back", + onNavigationIconClick = { + onEvent(MobileVerificationAction.CloseButtonClick) + }, + ), + ) + }, + ) { paddingValues -> + when (uiState) { + is MobileVerificationState.VerifyPhoneState -> { + PhoneNoVerifyContent( + modifier = Modifier.padding(paddingValues), + state = uiState, + onEvent = onEvent, + ) + } + + is MobileVerificationState.VerifyOtpState -> { + OtpVerifyContent( + modifier = Modifier.padding(paddingValues), + state = uiState, + onEvent = onEvent, + ) + } + } + } +} + +@Composable +fun PhoneNoVerifyContent( + modifier: Modifier = Modifier, + state: MobileVerificationState.VerifyPhoneState, + onEvent: (MobileVerificationAction) -> Unit, +) { + MobileVerificationDialogs( + dialogState = state.dialogState, + onDismissRequest = { + onEvent(MobileVerificationAction.DismissDialog) + }, + ) + + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + MifosOutlinedTextField( + modifier = modifier, + value = state.phoneNo, + label = stringResource(Res.string.feature_auth_phone_number), + onValueChange = { + onEvent(MobileVerificationAction.PhoneNoChanged(it)) + }, + ) + + Text( + text = stringResource(Res.string.feature_auth_enter_mobile_number_description), + style = MaterialTheme.typography.bodySmall, + ) + + MifosButton( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 32.dp, vertical = 16.dp), + color = MaterialTheme.colorScheme.primary, + enabled = state.isPhoneNoValid, + onClick = { + onEvent(MobileVerificationAction.VerifyPhoneBtnClicked) + }, + contentPadding = PaddingValues(12.dp), + ) { + Text( + text = stringResource(Res.string.feature_auth_verify_phone).uppercase(), + style = MaterialTheme.typography.labelLarge, + ) + } + } +} + +@Composable +fun OtpVerifyContent( + modifier: Modifier = Modifier, + state: MobileVerificationState.VerifyOtpState, + onEvent: (MobileVerificationAction) -> Unit, +) { + MobileVerificationDialogs( + dialogState = state.dialogState, + onDismissRequest = { + onEvent(MobileVerificationAction.DismissDialog) + }, + ) + + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + MifosOutlinedTextField( + modifier = modifier, + value = state.otp, + label = stringResource(Res.string.feature_auth_enter_otp), + onValueChange = { + onEvent(MobileVerificationAction.PhoneNoChanged(it)) + }, + ) + + Text( + text = stringResource(Res.string.feature_auth_enter_otp_received), + style = MaterialTheme.typography.bodySmall, + ) + + MifosButton( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 32.dp, vertical = 16.dp), + color = MaterialTheme.colorScheme.primary, + enabled = state.isOtpValid, + onClick = { + onEvent(MobileVerificationAction.VerifyOtpBtnClicked) + }, + contentPadding = PaddingValues(12.dp), + ) { + Text( + text = stringResource(Res.string.feature_auth_verify_otp).uppercase(), + style = MaterialTheme.typography.labelLarge, + ) + } + } +} + +@Composable +private fun MobileVerificationDialogs( + dialogState: MobileVerificationState.DialogState?, + onDismissRequest: () -> Unit, +) { + when (dialogState) { + is MobileVerificationState.DialogState.Error -> MifosBasicDialog( + visibilityState = BasicDialogState.Shown( + message = dialogState.message, + ), + onDismissRequest = onDismissRequest, + ) + + is MobileVerificationState.DialogState.Loading -> MifosLoadingDialog( + visibilityState = LoadingDialogState.Shown, + ) + + null -> Unit + } +} + +@Preview +@Composable +private fun MobileVerificationScreenVerifyPhonePreview() { + MifosTheme { + MobileVerificationScreen( + uiState = MobileVerificationState.VerifyPhoneState(), + onEvent = {}, + ) + } +} + +@Preview +@Composable +private fun MobileVerificationScreenVerifyOtpPreview() { + MifosTheme { + MobileVerificationScreen( + uiState = MobileVerificationState.VerifyOtpState(phoneNo = ""), + onEvent = {}, + ) + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt new file mode 100644 index 000000000..c90595ad5 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt @@ -0,0 +1,287 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.mobileVerify + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize +import org.mifospay.core.common.Result +import org.mifospay.core.data.repository.SearchRepository +import org.mifospay.core.data.util.Constants +import org.mifospay.core.ui.utils.BaseViewModel +import org.mifospay.feature.auth.mobileVerify.MobileVerificationAction.Internal.ReceiveOtpVerifyResult + +private const val KEY_STATE = "mobile_verification" + +class MobileVerificationViewModel( + private val searchRepository: SearchRepository, + savedStateHandle: SavedStateHandle, +) : BaseViewModel( + initialState = savedStateHandle[KEY_STATE] ?: MobileVerificationState.VerifyPhoneState(), +) { + + init { + stateFlow.onEach { savedStateHandle[KEY_STATE] = it }.launchIn(viewModelScope) + } + + override fun handleAction(action: MobileVerificationAction) { + when (action) { + is MobileVerificationAction.PhoneNoChanged -> { + mutableStateFlow.update { + if (it is MobileVerificationState.VerifyPhoneState) { + it.copy(phoneNo = action.phoneNo) + } else { + it + } + } + } + + is MobileVerificationAction.VerifyPhoneBtnClicked -> { + val currentState = state as? MobileVerificationState.VerifyPhoneState ?: return + verifyPhoneNo(currentState) + } + + is MobileVerificationAction.OtpChanged -> { + mutableStateFlow.update { + if (it is MobileVerificationState.VerifyOtpState) { + it.copy(otp = action.otp) + } else { + it + } + } + } + + is MobileVerificationAction.VerifyOtpBtnClicked -> { + val currentState = state as? MobileVerificationState.VerifyOtpState ?: return + verifyEnteredOTP(currentState) + } + + is ReceiveOtpVerifyResult -> handleOtpVerifyResult(action) + + is MobileVerificationAction.ChangePhoneNumber -> handleChangePhoneNoClick() + + is MobileVerificationAction.DismissDialog -> handleDismissDialog() + + is MobileVerificationAction.CloseButtonClick -> handleCloseButtonClick() + } + } + + private fun verifyPhoneNo(currentState: MobileVerificationState.VerifyPhoneState) { + if (currentState.isPhoneNoValid) { + verifyMobileAndRequestOtp(currentState.phoneNo, currentState) + } else { + mutableStateFlow.update { + currentState.copy( + dialogState = MobileVerificationState.DialogState.Error("Phone no isn't valid"), + ) + } + } + } + + private fun verifyMobileAndRequestOtp( + phoneNo: String, + currentState: MobileVerificationState.VerifyPhoneState, + ) { + viewModelScope.launch { + val result = searchRepository.searchResources( + query = phoneNo, + resources = Constants.CLIENTS, + exactMatch = true, + ) + + when (result) { + is Result.Error -> { + val message = result.exception.message ?: "Something Went Wrong!" + mutableStateFlow.update { + currentState.copy( + dialogState = MobileVerificationState.DialogState.Error(message), + ) + } + } + + is Result.Loading -> { + mutableStateFlow.update { + currentState.copy(dialogState = MobileVerificationState.DialogState.Loading) + } + } + + is Result.Success -> { + if (result.data.isEmpty()) { + requestAnOtpToPhoneNo(phoneNo) + } else { + val message = "Mobile number already exists." + mutableStateFlow.update { + currentState.copy( + dialogState = MobileVerificationState.DialogState.Error(message), + ) + } + } + } + } + } + } + + private fun requestAnOtpToPhoneNo(phoneNo: String) { + viewModelScope.launch { + // TODO:: Call repository request an otp to this phone no. + mutableStateFlow.update { + MobileVerificationState.VerifyOtpState(phoneNo) + } + trySendAction(MobileVerificationAction.DismissDialog) + } + } + + private fun verifyEnteredOTP(state: MobileVerificationState.VerifyOtpState) { + viewModelScope.launch { + if (state.isOtpValid) { + // TODO:: Match send otp to entered otp + mutableStateFlow.update { + state.copy( + dialogState = MobileVerificationState.DialogState.Loading, + ) + } + + sendAction(ReceiveOtpVerifyResult(Result.Success(state.phoneNo))) + } else { + mutableStateFlow.update { + state.copy( + dialogState = MobileVerificationState.DialogState.Error("OTP isn't valid"), + ) + } + } + } + } + + private fun handleOtpVerifyResult(action: ReceiveOtpVerifyResult) { + when (action.loginResult) { + is Result.Error -> { + mutableStateFlow.update { + (state as? MobileVerificationState.VerifyOtpState)?.copy( + dialogState = MobileVerificationState.DialogState.Error("Otp Verification Failed"), + ) ?: state + } + } + + is Result.Loading -> { + mutableStateFlow.update { + (state as? MobileVerificationState.VerifyOtpState)?.copy( + dialogState = MobileVerificationState.DialogState.Loading, + ) ?: state + } + } + + is Result.Success -> { + mutableStateFlow.update { + (state as? MobileVerificationState.VerifyOtpState)?.copy( + dialogState = null, + ) ?: state + } + sendEvent(MobileVerificationEvent.ShowToast("Otp Verified Successfully")) + sendEvent(MobileVerificationEvent.NavigateToSignup(action.loginResult.data)) + } + } + } + + private fun handleChangePhoneNoClick() { + viewModelScope.launch { + mutableStateFlow.update { + if (it is MobileVerificationState.VerifyOtpState) { + MobileVerificationState.VerifyPhoneState(phoneNo = it.phoneNo) + } else { + it + } + } + } + } + + private fun handleDismissDialog() { + viewModelScope.launch { + mutableStateFlow.update { + when (it) { + is MobileVerificationState.VerifyOtpState -> { + it.copy(dialogState = null) + } + + is MobileVerificationState.VerifyPhoneState -> { + it.copy(dialogState = null) + } + } + } + } + } + + private fun handleCloseButtonClick() { + viewModelScope.launch { + if (state is MobileVerificationState.VerifyOtpState) { + sendEvent(MobileVerificationEvent.NavigateBack) + } else { + sendAction(MobileVerificationAction.ChangePhoneNumber) + } + } + } +} + +sealed class MobileVerificationState : Parcelable { + @Parcelize + data class VerifyPhoneState( + val phoneNo: String = "", + val dialogState: DialogState? = null, + ) : MobileVerificationState() { + val isPhoneNoValid: Boolean + get() = phoneNo.length == 10 + } + + @Parcelize + data class VerifyOtpState( + val phoneNo: String, + val otp: String = "", + val dialogState: DialogState? = null, + ) : MobileVerificationState() { + val isOtpValid: Boolean + get() = otp.length == 6 + } + + sealed class DialogState : Parcelable { + @Parcelize + data class Error(val message: String) : DialogState() + + @Parcelize + data object Loading : DialogState() + } +} + +sealed interface MobileVerificationEvent { + data object NavigateBack : MobileVerificationEvent + data class NavigateToSignup(val phoneNo: String) : MobileVerificationEvent + data class ShowToast(val message: String) : MobileVerificationEvent +} + +sealed interface MobileVerificationAction { + data class PhoneNoChanged(val phoneNo: String) : MobileVerificationAction + data object VerifyPhoneBtnClicked : MobileVerificationAction + + data class OtpChanged(val otp: String) : MobileVerificationAction + data object ChangePhoneNumber : MobileVerificationAction + data object VerifyOtpBtnClicked : MobileVerificationAction + + data object DismissDialog : MobileVerificationAction + data object CloseButtonClick : MobileVerificationAction + + sealed class Internal : MobileVerificationAction { + data class ReceiveOtpVerifyResult( + val loginResult: Result, + ) : Internal() + } +} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt similarity index 63% rename from feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt rename to feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt index ef1c44d0f..98aec8fba 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt @@ -11,23 +11,35 @@ package org.mifospay.feature.auth.navigation import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType import androidx.navigation.compose.composable +import androidx.navigation.navArgument import org.mifospay.feature.auth.login.LoginScreen const val LOGIN_ROUTE = "login_route" fun NavGraphBuilder.loginScreen( + onNavigateBack: () -> Unit, onNavigateToPasscodeScreen: () -> Unit, onNavigateToSignupScreen: () -> Unit, ) { - composable(route = LOGIN_ROUTE) { + composable( + route = "$LOGIN_ROUTE?username={username}", + arguments = listOf( + navArgument("username") { + type = NavType.StringType + defaultValue = "" + }, + ), + ) { LoginScreen( + onNavigateBack = onNavigateBack, navigateToPasscodeScreen = onNavigateToPasscodeScreen, navigateToSignupScreen = onNavigateToSignupScreen, ) } } -fun NavController.navigateToLogin() { - this.navigate(LOGIN_ROUTE) +fun NavController.navigateToLogin(username: String = "") { + this.navigate("$LOGIN_ROUTE?username=$username") } diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt new file mode 100644 index 000000000..5bd912564 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +@file:Suppress("MaxLineLength") + +package org.mifospay.feature.auth.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable +import org.mifospay.feature.auth.mobileVerify.MobileVerificationScreen + +const val MOBILE_VERIFICATION_ROUTE = "mobile_verification_route" + +fun NavGraphBuilder.mobileVerificationScreen( + onNavigateBack: () -> Unit, + onOtpVerificationSuccess: (String) -> Unit, +) { + composable( + route = MOBILE_VERIFICATION_ROUTE, + ) { + MobileVerificationScreen( + onNavigateBack = onNavigateBack, + onOtpVerificationSuccess = onOtpVerificationSuccess, + ) + } +} + +fun NavController.navigateToMobileVerification() { + this.navigate(MOBILE_VERIFICATION_ROUTE) +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt new file mode 100644 index 000000000..e3d961162 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +@file:Suppress("MaxLineLength") + +package org.mifospay.feature.auth.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument +import org.mifospay.feature.auth.signup.SignupScreen + +const val SIGNUP_ROUTE = "signup_route" + +fun NavGraphBuilder.signupScreen( + onNavigateBack: () -> Unit, + onNavigateToLogin: (String) -> Unit, +) { + composable( + route = "$SIGNUP_ROUTE?savingsProductId={savingsProductId}" + + "&mobileNumber={mobileNumber}&businessName={businessName}", + arguments = listOf( + navArgument("savingsProductId") { + type = NavType.IntType + defaultValue = 0 + }, + navArgument("mobileNumber") { + type = NavType.StringType + defaultValue = "" + }, + navArgument("businessName") { + type = NavType.StringType + defaultValue = "" + }, + ), + ) { + SignupScreen( + onNavigateBack = onNavigateBack, + onNavigateToLogin = onNavigateToLogin, + ) + } +} + +fun NavController.navigateToSignup( + savingsProductId: Int = 0, + mobileNumber: String = "", + businessName: String = "", +) { + this.navigate( + "$SIGNUP_ROUTE?savingsProductId=$savingsProductId" + + "&mobileNumber=$mobileNumber&businessName=$businessName", + ) +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/PasswordStrengthIndicator.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/PasswordStrengthIndicator.kt new file mode 100644 index 000000000..ef44fb1f5 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/PasswordStrengthIndicator.kt @@ -0,0 +1,217 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.signup + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.background +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.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CheckCircle +import androidx.compose.material.icons.filled.Close +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.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.TransformOrigin +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.designsystem.theme.MifosTheme + +@Suppress("LongMethod", "CyclomaticComplexMethod", "MagicNumber") +@Composable +fun PasswordStrengthIndicator( + modifier: Modifier = Modifier, + state: PasswordStrengthState, + currentCharacterCount: Int, + minimumCharacterCount: Int? = null, +) { + val widthPercent by animateFloatAsState( + targetValue = when (state) { + PasswordStrengthState.NONE -> 0f + PasswordStrengthState.WEAK_1 -> .25f + PasswordStrengthState.WEAK_2 -> .5f + PasswordStrengthState.WEAK_3 -> .66f + PasswordStrengthState.GOOD -> .82f + PasswordStrengthState.STRONG -> 1f + PasswordStrengthState.VERY_STRONG -> 1f + }, + label = "Width Percent State", + ) + val indicatorColor = when (state) { + PasswordStrengthState.NONE -> MaterialTheme.colorScheme.error + PasswordStrengthState.WEAK_1 -> MaterialTheme.colorScheme.error + PasswordStrengthState.WEAK_2 -> MaterialTheme.colorScheme.error + PasswordStrengthState.WEAK_3 -> weakColor + PasswordStrengthState.GOOD -> MaterialTheme.colorScheme.primary + PasswordStrengthState.STRONG -> strongColor + PasswordStrengthState.VERY_STRONG -> Color.Magenta + } + val animatedIndicatorColor by animateColorAsState( + targetValue = indicatorColor, + label = "Indicator Color State", + ) + val label = when (state) { + PasswordStrengthState.NONE -> "" + PasswordStrengthState.WEAK_1 -> "Weak" + PasswordStrengthState.WEAK_2 -> "Weak" + PasswordStrengthState.WEAK_3 -> "Weak" + PasswordStrengthState.GOOD -> "Good" + PasswordStrengthState.STRONG -> "Strong" + PasswordStrengthState.VERY_STRONG -> "Very Strong" + } + Column( + modifier = modifier, + ) { + Box( + Modifier + .fillMaxWidth() + .height(4.dp) + .background(MaterialTheme.colorScheme.surfaceContainerHigh), + ) { + Box( + modifier = Modifier + .fillMaxHeight() + .fillMaxWidth() + .graphicsLayer { + transformOrigin = TransformOrigin(pivotFractionX = 0f, pivotFractionY = 0f) + scaleX = widthPercent + } + .drawBehind { + drawRect(animatedIndicatorColor) + }, + ) + } + Spacer(Modifier.height(4.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + minimumCharacterCount?.let { minCount -> + MinimumCharacterCount( + minimumRequirementMet = currentCharacterCount >= minCount, + minimumCharacterCount = minCount, + ) + } + Text( + text = label, + style = MaterialTheme.typography.labelSmall, + color = indicatorColor, + ) + } + } +} + +@Composable +private fun MinimumCharacterCount( + modifier: Modifier = Modifier, + minimumRequirementMet: Boolean, + minimumCharacterCount: Int, +) { + val characterCountColor by animateColorAsState( + targetValue = if (minimumRequirementMet) { + strongColor + } else { + MaterialTheme.colorScheme.surfaceDim + }, + label = "minmumCharacterCountColor", + ) + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically, + ) { + AnimatedContent( + targetState = if (minimumRequirementMet) { + Icons.Default.CheckCircle + } else { + Icons.Default.Close + }, + label = "iconForMinimumCharacterCount", + ) { + Icon( + imageVector = it, + contentDescription = null, + tint = characterCountColor, + modifier = Modifier.size(12.dp), + ) + } + Spacer(modifier = Modifier.width(2.dp)) + Text( + text = "$minimumCharacterCount characters", + color = characterCountColor, + style = MaterialTheme.typography.labelSmall, + ) + } +} + +enum class PasswordStrengthState { + NONE, + WEAK_1, + WEAK_2, + WEAK_3, + GOOD, + STRONG, + VERY_STRONG, +} + +private val strongColor = Color(0xFF41B06D) +private val weakColor = Color(0xFF8B6609) + +@Preview +@Composable +private fun PasswordStrengthIndicatorPreview_minCharMet() { + MifosTheme { + PasswordStrengthIndicator( + state = PasswordStrengthState.WEAK_3, + currentCharacterCount = 12, + minimumCharacterCount = 12, + ) + } +} + +@Preview +@Composable +private fun PasswordStrengthIndicatorPreview_minCharNotMet() { + MifosTheme { + PasswordStrengthIndicator( + state = PasswordStrengthState.WEAK_3, + currentCharacterCount = 11, + minimumCharacterCount = 12, + ) + } +} + +@Preview +@Composable +private fun PasswordStrengthIndicatorPreview_noMinChar() { + MifosTheme { + PasswordStrengthIndicator( + state = PasswordStrengthState.WEAK_3, + currentCharacterCount = 12, + ) + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt new file mode 100644 index 000000000..0d1266f4d --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt @@ -0,0 +1,308 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.signup + +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.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTopAppBarState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +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.unit.dp +import kotlinx.coroutines.launch +import mobile_wallet.feature.auth.generated.resources.Res +import mobile_wallet.feature.auth.generated.resources.feature_auth_address_line_1 +import mobile_wallet.feature.auth.generated.resources.feature_auth_address_line_2 +import mobile_wallet.feature.auth.generated.resources.feature_auth_all_fields_are_mandatory +import mobile_wallet.feature.auth.generated.resources.feature_auth_complete +import mobile_wallet.feature.auth.generated.resources.feature_auth_complete_your_registration +import mobile_wallet.feature.auth.generated.resources.feature_auth_confirm_password +import mobile_wallet.feature.auth.generated.resources.feature_auth_country +import mobile_wallet.feature.auth.generated.resources.feature_auth_email +import mobile_wallet.feature.auth.generated.resources.feature_auth_first_name +import mobile_wallet.feature.auth.generated.resources.feature_auth_last_name +import mobile_wallet.feature.auth.generated.resources.feature_auth_mobile_no +import mobile_wallet.feature.auth.generated.resources.feature_auth_password +import mobile_wallet.feature.auth.generated.resources.feature_auth_pin_code +import mobile_wallet.feature.auth.generated.resources.feature_auth_state +import mobile_wallet.feature.auth.generated.resources.feature_auth_username +import org.jetbrains.compose.resources.stringResource +import org.koin.compose.viewmodel.koinViewModel +import org.mifospay.core.designsystem.component.BasicDialogState +import org.mifospay.core.designsystem.component.LoadingDialogState +import org.mifospay.core.designsystem.component.MfOutlinedTextField +import org.mifospay.core.designsystem.component.MifosBasicDialog +import org.mifospay.core.designsystem.component.MifosButton +import org.mifospay.core.designsystem.component.MifosLoadingDialog +import org.mifospay.core.designsystem.component.MifosScaffold +import org.mifospay.core.designsystem.component.MifosTopAppBar +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.ui.MifosPasswordField +import org.mifospay.core.ui.utils.EventsEffect + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun SignupScreen( + onNavigateBack: () -> Unit, + onNavigateToLogin: (String) -> Unit, + modifier: Modifier = Modifier, + viewModel: SignupViewModel = koinViewModel(), +) { + val state by viewModel.stateFlow.collectAsState() + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) + val snackbarHostState = remember { SnackbarHostState() } + val scope = rememberCoroutineScope() + + EventsEffect(viewModel) { event -> + when (event) { + is SignUpEvent.NavigateBack -> onNavigateBack.invoke() + is SignUpEvent.NavigateToLogin -> onNavigateToLogin.invoke(event.username) + is SignUpEvent.ShowToast -> { + scope.launch { + snackbarHostState.showSnackbar(event.message) + } + } + } + } + + SignUpDialogs( + dialogState = state.dialogState, + onDismissRequest = remember(viewModel) { + { viewModel.trySendAction(SignUpAction.ErrorDialogDismiss) } + }, + ) + + MifosScaffold( + snackbarHostState = snackbarHostState, + modifier = modifier, + topBar = { + MifosTopAppBar( + title = stringResource(Res.string.feature_auth_complete_your_registration), + subtitle = stringResource(Res.string.feature_auth_all_fields_are_mandatory), + scrollBehavior = scrollBehavior, + navigationIcon = MifosIcons.Back, + navigationIconContentDescription = "Back", + onNavigationIconClick = remember(viewModel) { + { viewModel.trySendAction(SignUpAction.CloseClick) } + }, + ) + }, + ) { + SignupScreenContent( + modifier = Modifier.padding(it), + state = state, + onAction = viewModel::trySendAction, + ) + } +} + +@Composable +private fun SignUpDialogs( + dialogState: SignUpDialog?, + onDismissRequest: () -> Unit, +) { + when (dialogState) { + is SignUpDialog.Error -> MifosBasicDialog( + visibilityState = BasicDialogState.Shown( + message = dialogState.message, + ), + onDismissRequest = onDismissRequest, + ) + + is SignUpDialog.Loading -> MifosLoadingDialog( + visibilityState = LoadingDialogState.Shown, + ) + + null -> Unit + } +} + +@Composable +private fun SignupScreenContent( + modifier: Modifier = Modifier, + state: SignUpState, + onAction: (SignUpAction) -> Unit, +) { + Column( + modifier = modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(horizontal = 16.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + MfOutlinedTextField( + value = state.firstNameInput, + label = stringResource(Res.string.feature_auth_first_name), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.FirstNameInputChange(it)) + }, + isError = state.firstNameInput.isEmpty(), + ) + + MfOutlinedTextField( + value = state.lastNameInput, + label = stringResource(Res.string.feature_auth_last_name), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.LastNameInputChange(it)) + }, + isError = state.lastNameInput.isEmpty(), + ) + + MfOutlinedTextField( + value = state.userNameInput, + label = stringResource(Res.string.feature_auth_username), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.UserNameInputChange(it)) + }, + isError = state.userNameInput.isEmpty(), + ) + + MfOutlinedTextField( + value = state.emailInput, + label = stringResource(Res.string.feature_auth_email), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.EmailInputChange(it)) + }, + isError = state.emailInput.isEmpty(), + ) + + MfOutlinedTextField( + value = state.mobileNumberInput, + label = stringResource(Res.string.feature_auth_mobile_no), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.MobileNumberInputChange(it)) + }, + isError = state.mobileNumberInput.isEmpty(), + ) + + var showPassword by rememberSaveable { mutableStateOf(false) } + + MifosPasswordField( + value = state.passwordInput, + label = stringResource(Res.string.feature_auth_password), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.PasswordInputChange(it)) + }, + showPassword = showPassword, + showPasswordChange = { showPassword = !showPassword }, + ) + PasswordStrengthIndicator( + modifier = Modifier.padding(horizontal = 16.dp), + state = state.passwordStrengthState, + currentCharacterCount = state.passwordInput.length, + ) + MifosPasswordField( + value = state.confirmPasswordInput, + label = stringResource(Res.string.feature_auth_confirm_password), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.ConfirmPasswordInputChange(it)) + }, + showPassword = showPassword, + showPasswordChange = { showPassword = !showPassword }, + ) + + MfOutlinedTextField( + value = state.addressLine1Input, + label = stringResource(Res.string.feature_auth_address_line_1), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.AddressLine1InputChange(it)) + }, + isError = state.addressLine1Input.isEmpty(), + ) + + MfOutlinedTextField( + value = state.addressLine2Input, + modifier = Modifier.fillMaxWidth(), + label = stringResource(Res.string.feature_auth_address_line_2), + onValueChange = { + onAction(SignUpAction.AddressLine2InputChange(it)) + }, + isError = state.addressLine2Input.isEmpty(), + ) + + MfOutlinedTextField( + value = state.pinCodeInput, + label = stringResource(Res.string.feature_auth_pin_code), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.PinCodeInputChange(it)) + }, + isError = state.pinCodeInput.isEmpty(), + ) + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + MfOutlinedTextField( + value = state.countryInput, + label = stringResource(Res.string.feature_auth_country), + onValueChange = { + onAction(SignUpAction.CountryInputChange(it)) + }, + modifier = Modifier.weight(1.5f), + isError = state.countryInput.isEmpty(), + ) + + MfOutlinedTextField( + value = state.stateInput, + label = stringResource(Res.string.feature_auth_state), + onValueChange = { + onAction(SignUpAction.StateInputChange(it)) + }, + modifier = Modifier.weight(1.5f), + isError = state.stateInput.isEmpty(), + ) + } + + MifosButton( + modifier = Modifier + .fillMaxWidth(), + color = MaterialTheme.colorScheme.primary, + enabled = true, + onClick = { + onAction(SignUpAction.SubmitClick) + }, + contentPadding = PaddingValues(12.dp), + ) { + Text( + text = stringResource(Res.string.feature_auth_complete), + ) + } + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt new file mode 100644 index 000000000..45d9e040f --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt @@ -0,0 +1,591 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.signup + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize +import org.mifospay.core.common.Result +import org.mifospay.core.common.utils.isValidEmail +import org.mifospay.core.data.repository.ClientRepository +import org.mifospay.core.data.repository.SearchRepository +import org.mifospay.core.data.repository.UserRepository +import org.mifospay.core.data.util.Constants +import org.mifospay.core.model.domain.client.Address +import org.mifospay.core.model.domain.client.NewClient +import org.mifospay.core.model.domain.user.NewUser +import org.mifospay.core.ui.utils.BaseViewModel +import org.mifospay.core.ui.utils.PasswordChecker +import org.mifospay.core.ui.utils.PasswordStrength +import org.mifospay.core.ui.utils.PasswordStrengthResult +import org.mifospay.feature.auth.signup.SignUpAction.Internal.ReceivePasswordStrengthResult + +private const val KEY_STATE = "signup_state" +private const val MIN_PASSWORD_LENGTH = 8 + +class SignupViewModel( + private val userRepository: UserRepository, + private val searchRepository: SearchRepository, + private val clientRepository: ClientRepository, + savedStateHandle: SavedStateHandle, +) : BaseViewModel( + initialState = savedStateHandle[KEY_STATE] ?: SignUpState(), +) { + private var passwordStrengthJob: Job = Job().apply { complete() } + + init { + stateFlow + .onEach { savedStateHandle[KEY_STATE] = it } + .launchIn(viewModelScope) + + savedStateHandle.get("mobileNumber")?.let { + viewModelScope.launch { + trySendAction(SignUpAction.MobileNumberInputChange(it)) + } + } + + savedStateHandle.get("savingsProductId")?.let { + viewModelScope.launch { + trySendAction(SignUpAction.SavingsAccountNoInputChange(it)) + } + } + + savedStateHandle.get("businessName")?.let { + viewModelScope.launch { + trySendAction(SignUpAction.BusinessNameInputChange(it)) + } + } + } + + override fun handleAction(action: SignUpAction) { + when (action) { + is SignUpAction.FirstNameInputChange -> { + mutableStateFlow.update { + it.copy(firstNameInput = action.firstName) + } + } + + is SignUpAction.LastNameInputChange -> { + mutableStateFlow.update { + it.copy(lastNameInput = action.lastName) + } + } + + is SignUpAction.UserNameInputChange -> { + mutableStateFlow.update { + it.copy(userNameInput = action.username) + } + } + + is SignUpAction.PasswordInputChange -> handlePasswordInput(action) + + is SignUpAction.ConfirmPasswordInputChange -> { + mutableStateFlow.update { + it.copy(confirmPasswordInput = action.confirmPassword) + } + } + + is SignUpAction.EmailInputChange -> { + mutableStateFlow.update { + it.copy(emailInput = action.email) + } + } + + is SignUpAction.AddressLine1InputChange -> { + mutableStateFlow.update { + it.copy(addressLine1Input = action.addressLineOne) + } + } + + is SignUpAction.AddressLine2InputChange -> { + mutableStateFlow.update { + it.copy(addressLine2Input = action.addressLineTwo) + } + } + + is SignUpAction.PinCodeInputChange -> { + mutableStateFlow.update { + it.copy(pinCodeInput = action.pincode) + } + } + + is SignUpAction.BusinessNameInputChange -> { + mutableStateFlow.update { + it.copy(businessNameInput = action.businessName) + } + } + + is SignUpAction.MobileNumberInputChange -> { + mutableStateFlow.update { + it.copy(mobileNumberInput = action.mobileNumber) + } + } + + is SignUpAction.SavingsAccountNoInputChange -> { + mutableStateFlow.update { + it.copy(savingsProductId = action.savingsAccountNo) + } + } + + is SignUpAction.StateInputChange -> { + mutableStateFlow.update { + it.copy(stateInput = action.state) + } + } + + is SignUpAction.CountryInputChange -> { + mutableStateFlow.update { + it.copy(countryInput = action.country) + } + } + + is SignUpAction.CloseClick -> { + sendEvent(SignUpEvent.NavigateBack) + } + + is SignUpAction.ErrorDialogDismiss -> { + mutableStateFlow.update { + it.copy(dialogState = null) + } + } + + is ReceivePasswordStrengthResult -> handlePasswordStrengthResult(action) + + is SignUpAction.Internal.ReceiveRegisterResult -> handleSignUpResult(action) + + is SignUpAction.SubmitClick -> handleSubmitClick() + } + } + + private fun handlePasswordInput(action: SignUpAction.PasswordInputChange) { + // Update input: + mutableStateFlow.update { it.copy(passwordInput = action.password) } + // Update password strength: + passwordStrengthJob.cancel() + if (action.password.isEmpty()) { + mutableStateFlow.update { + it.copy(passwordStrengthState = PasswordStrengthState.NONE) + } + } else { + passwordStrengthJob = viewModelScope.launch { + val result = PasswordChecker.getPasswordStrengthResult(action.password) + trySendAction(ReceivePasswordStrengthResult(result)) + } + } + } + + private fun handlePasswordStrengthResult(action: ReceivePasswordStrengthResult) { + when (val result = action.result) { + is PasswordStrengthResult.Success -> { + val updatedState = when (result.passwordStrength) { + PasswordStrength.LEVEL_0 -> PasswordStrengthState.WEAK_1 + PasswordStrength.LEVEL_1 -> PasswordStrengthState.WEAK_2 + PasswordStrength.LEVEL_2 -> PasswordStrengthState.WEAK_3 + PasswordStrength.LEVEL_3 -> PasswordStrengthState.GOOD + PasswordStrength.LEVEL_4 -> PasswordStrengthState.STRONG + PasswordStrength.LEVEL_5 -> PasswordStrengthState.VERY_STRONG + } + mutableStateFlow.update { oldState -> + oldState.copy(passwordStrengthState = updatedState) + } + } + + is PasswordStrengthResult.Error -> {} + } + } + + private fun handleSignUpResult(action: SignUpAction.Internal.ReceiveRegisterResult) { + when (val result = action.registerResult) { + is Result.Success -> { + mutableStateFlow.update { it.copy(dialogState = null) } + sendEvent(SignUpEvent.NavigateToLogin(result.data)) + } + + is Result.Error -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error(result.exception.message.toString())) + } + } + + Result.Loading -> { + mutableStateFlow.update { it.copy(dialogState = SignUpDialog.Loading) } + } + + else -> {} + } + } + + // TODO:: move error messages to strings.xml + private fun handleSubmitClick() = when { + state.savingsProductId == 0 -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please select a savings account.")) + } + } + + state.firstNameInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your first name.")) + } + } + + state.lastNameInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your last name.")) + } + } + + state.userNameInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your username.")) + } + } + + state.emailInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your email.")) + } + } + + !state.emailInput.isValidEmail() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter a valid email.")) + } + } + + state.mobileNumberInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your mobile number.")) + } + } + + state.mobileNumberInput.length < 10 -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Mobile number must be 10 digits long.")) + } + } + + state.passwordInput.length < MIN_PASSWORD_LENGTH -> { + mutableStateFlow.update { + it.copy( + dialogState = SignUpDialog.Error( + "Password must be at least $MIN_PASSWORD_LENGTH characters long.", + ), + ) + } + } + + !state.isPasswordMatch -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Passwords do not match.")) + } + } + + !state.isPasswordStrong -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Password is weak.")) + } + } + + state.addressLine1Input.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your address line 1.")) + } + } + + state.addressLine2Input.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your address line 2.")) + } + } + + state.pinCodeInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your pin code.")) + } + } + + state.pinCodeInput.length < 6 -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Pin code must be 6 digits long.")) + } + } + + state.countryInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your country.")) + } + } + + state.stateInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your state.")) + } + } + + else -> initiateSignUp() + } + + /* + Enhancement: Move the following code in to a Use Case + */ + private fun initiateSignUp() { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Loading) + } + + // 0. Unique Mobile Number (checked in MOBILE VERIFICATION ACTIVITY) + // 1. Check for unique external id and username + // 2. Create user + // 3. Create Client + // 4. Update User and connect client with user + checkForUsernameExists(state.userNameInput) + } + + private fun checkForUsernameExists(username: String) { + viewModelScope.launch { + val result = searchRepository.searchResources( + username, + Constants.CLIENTS, + false, + ) + + when (result) { + is Result.Error -> { + val message = result.exception.message.toString() + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error(message)) + } + } + + is Result.Success -> { + if (result.data.isEmpty()) { + // Username is unique + val newUser = NewUser( + state.userNameInput, + state.firstNameInput, + state.lastNameInput, + state.emailInput, + state.passwordInput, + ) + + createUser(newUser) + } else { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Username already exists.")) + } + } + } + + is Result.Loading -> Unit + } + } + } + + private fun createUser(newUser: NewUser) { + viewModelScope.launch { + when (val result = userRepository.createUser(newUser)) { + is Result.Error -> { + val message = result.exception.message.toString() + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error(message)) + } + } + + is Result.Success -> { + createClient(result.data.resourceId) + } + + is Result.Loading -> Unit + } + } + } + + private fun createClient(userId: Int) { + viewModelScope.launch { + val newClient = NewClient( + firstname = state.firstNameInput, + lastname = state.lastNameInput, + externalId = state.userNameInput.plus("_client"), + mobileNo = state.mobileNumberInput, + savingsProductId = state.savingsProductId, + address = Address( + addressLine1 = state.addressLine1Input, + addressLine2 = state.addressLine2Input, + postalCode = state.pinCodeInput, + stateProvinceId = state.stateInput, + countryId = state.countryInput, + ), + ) + + when (val result = clientRepository.createClient(newClient)) { + is Result.Error -> { + deleteUser(userId) + val message = result.exception.message.toString() + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error(message)) + } + } + + is Result.Success -> { + assignClientToUser(result.data.clientId, userId) + } + + is Result.Loading -> Unit + } + } + } + + private fun assignClientToUser(clientId: Int, userId: Int) { + viewModelScope.launch { + when (val result = userRepository.assignClientToUser(userId, clientId)) { + is Result.Error -> { + deleteUser(userId) + deleteClient(clientId) + val message = result.exception.message.toString() + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error(message)) + } + } + + is Result.Success -> { + mutableStateFlow.update { + it.copy(dialogState = null) + } + sendEvent(SignUpEvent.ShowToast("Registration successful.")) + sendAction( + SignUpAction.Internal.ReceiveRegisterResult( + Result.Success(state.userNameInput), + ), + ) + } + + is Result.Loading -> Unit + } + } + } + + private fun deleteUser(userId: Int) { + viewModelScope.launch { + userRepository.deleteUser(userId) + } + } + + private fun deleteClient(clientId: Int) { + viewModelScope.launch { + clientRepository.deleteClient(clientId) + } + } +} + +@Parcelize +data class SignUpState( + val savingsProductId: Int = 0, + val firstNameInput: String = "", + val lastNameInput: String = "", + val emailInput: String = "", + val userNameInput: String = "", + val addressLine1Input: String = "", + val addressLine2Input: String = "", + val pinCodeInput: String = "", + val passwordInput: String = "", + val confirmPasswordInput: String = "", + val mobileNumberInput: String = "", + val stateInput: String = "", + val countryInput: String = "", + val businessNameInput: String = "", + val dialogState: SignUpDialog? = null, + val passwordStrengthState: PasswordStrengthState = PasswordStrengthState.NONE, +) : Parcelable { + val isPasswordStrong: Boolean + get() = when (passwordStrengthState) { + PasswordStrengthState.NONE, + PasswordStrengthState.WEAK_1, + PasswordStrengthState.WEAK_2, + PasswordStrengthState.WEAK_3, + -> false + + PasswordStrengthState.GOOD, + PasswordStrengthState.STRONG, + PasswordStrengthState.VERY_STRONG, + -> true + } + + val isPasswordMatch: Boolean + get() = passwordInput == confirmPasswordInput + + val isSubmitEnabled: Boolean + get() = firstNameInput.isNotEmpty() && + lastNameInput.isNotEmpty() && + emailInput.isNotEmpty() && + userNameInput.isNotEmpty() && + addressLine1Input.isNotEmpty() && + addressLine2Input.isNotEmpty() && + pinCodeInput.isNotEmpty() && + mobileNumberInput.isNotEmpty() && + passwordInput.isNotEmpty() && + confirmPasswordInput.isNotEmpty() && + stateInput.isNotEmpty() && + countryInput.isNotEmpty() && + passwordInput.length >= MIN_PASSWORD_LENGTH && + isPasswordStrong && isPasswordMatch && + savingsProductId != 0 +} + +sealed interface SignUpDialog : Parcelable { + @Parcelize + data object Loading : SignUpDialog + + @Parcelize + data class Error(val message: String) : SignUpDialog +} + +sealed interface SignUpEvent { + data object NavigateBack : SignUpEvent + data class ShowToast(val message: String) : SignUpEvent + data class NavigateToLogin(val username: String) : SignUpEvent +} + +sealed interface SignUpAction { + data class FirstNameInputChange(val firstName: String) : SignUpAction + data class LastNameInputChange(val lastName: String) : SignUpAction + data class EmailInputChange(val email: String) : SignUpAction + data class UserNameInputChange(val username: String) : SignUpAction + data class AddressLine1InputChange(val addressLineOne: String) : SignUpAction + data class AddressLine2InputChange(val addressLineTwo: String) : SignUpAction + data class PinCodeInputChange(val pincode: String) : SignUpAction + data class BusinessNameInputChange(val businessName: String) : SignUpAction + data class PasswordInputChange(val password: String) : SignUpAction + data class ConfirmPasswordInputChange(val confirmPassword: String) : SignUpAction + data class MobileNumberInputChange(val mobileNumber: String) : SignUpAction + data class SavingsAccountNoInputChange(val savingsAccountNo: Int) : SignUpAction + data class StateInputChange(val state: String) : SignUpAction + data class CountryInputChange(val country: String) : SignUpAction + + data object SubmitClick : SignUpAction + data object CloseClick : SignUpAction + data object ErrorDialogDismiss : SignUpAction + + sealed class Internal : SignUpAction { + data class ReceiveRegisterResult( + val registerResult: Result, + ) : Internal() + + data class ReceivePasswordStrengthResult( + val result: PasswordStrengthResult, + ) : Internal() + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodNavigation.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodNavigation.kt new file mode 100644 index 000000000..a49df5196 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodNavigation.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.socialSignup + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable + +const val SIGNUP_METHOD_ROUTE = "signup_method_route" + +fun NavGraphBuilder.signupMethodScreen( + onNavigateBack: () -> Unit, + onNavigateToSignUp: (savingsProductId: Int) -> Unit, +) { + composable( + route = SIGNUP_METHOD_ROUTE, + ) { + SignupMethodScreen( + onDismissSignUp = onNavigateBack, + navigateToSignupScreen = onNavigateToSignUp, + ) + } +} + +fun NavController.navigateToSignupMethod() { + this.navigate(SIGNUP_METHOD_ROUTE) +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodScreen.kt new file mode 100644 index 000000000..45acff8ac --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodScreen.kt @@ -0,0 +1,175 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.socialSignup + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +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.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import mobile_wallet.feature.auth.generated.resources.Res +import mobile_wallet.feature.auth.generated.resources.feature_auth_create_an_account +import mobile_wallet.feature.auth.generated.resources.feature_auth_or +import mobile_wallet.feature.auth.generated.resources.feature_auth_sign_up_as_customer +import mobile_wallet.feature.auth.generated.resources.feature_auth_sign_up_as_merchant +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.data.util.Constants.WALLET_ACCOUNT_SAVINGS_PRODUCT_ID +import org.mifospay.core.designsystem.component.MifosOutlinedButton +import org.mifospay.core.designsystem.component.MifosScaffold +import org.mifospay.core.designsystem.component.MifosTopAppBar +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.designsystem.theme.MifosTheme + +@Composable +internal fun SignupMethodScreen( + modifier: Modifier = Modifier, + navigateToSignupScreen: (savingsProductId: Int) -> Unit = {}, + onDismissSignUp: () -> Unit = {}, +) { + SignupMethodScreenContent( + modifier = modifier, + onDismissSignUp = onDismissSignUp, + navigateToSignupScreen = navigateToSignupScreen, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun SignupMethodScreenContent( + modifier: Modifier = Modifier, + onDismissSignUp: () -> Unit = {}, + navigateToSignupScreen: (savingsProductId: Int) -> Unit = {}, +) { + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + MifosScaffold( + modifier = modifier, + topBar = { + MifosTopAppBar( + title = "Choose Account Type", + navigationIcon = MifosIcons.Back, + onNavigationIconClick = onDismissSignUp, + navigationIconContentDescription = "Back", + scrollBehavior = scrollBehavior, + ) + }, + ) { + SignupMethodScreenContent( + modifier = Modifier.padding(it), + onSignUpAsMerchant = { + navigateToSignupScreen(WALLET_ACCOUNT_SAVINGS_PRODUCT_ID) + }, + onSignupAsCustomer = { + navigateToSignupScreen(WALLET_ACCOUNT_SAVINGS_PRODUCT_ID) + }, + ) + } +} + +@Composable +private fun SignupMethodScreenContent( + onSignUpAsMerchant: () -> Unit, + onSignupAsCustomer: () -> Unit, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .fillMaxSize() + .background(color = MaterialTheme.colorScheme.surface), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + modifier = Modifier.padding(top = 16.dp), + text = stringResource(Res.string.feature_auth_create_an_account), + ) + + MifosOutlinedButton( + modifier = Modifier.padding(top = 48.dp), + onClick = onSignUpAsMerchant, + border = BorderStroke(1.dp, Color.LightGray), + shape = RoundedCornerShape(4.dp), + colors = ButtonDefaults.outlinedButtonColors( + contentColor = MaterialTheme.colorScheme.primary, + ), + ) { + Text( + text = stringResource(Res.string.feature_auth_sign_up_as_merchant).uppercase(), + style = MaterialTheme.typography.labelMedium, + ) + } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 24.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + HorizontalDivider( + modifier = Modifier + .padding(start = 24.dp, end = 8.dp) + .weight(.4f), + thickness = 1.dp, + ) + Text( + modifier = Modifier + .wrapContentWidth() + .weight(.1f), + text = stringResource(Res.string.feature_auth_or), + ) + HorizontalDivider( + modifier = Modifier + .padding(start = 8.dp, end = 24.dp) + .weight(.4f), + thickness = 1.dp, + ) + } + + MifosOutlinedButton( + modifier = Modifier.padding(top = 24.dp), + onClick = onSignupAsCustomer, + border = BorderStroke(1.dp, Color.LightGray), + shape = RoundedCornerShape(4.dp), + colors = ButtonDefaults.outlinedButtonColors( + contentColor = MaterialTheme.colorScheme.primary, + ), + ) { + Text( + text = stringResource(Res.string.feature_auth_sign_up_as_customer).uppercase(), + style = MaterialTheme.typography.labelMedium, + ) + } + } +} + +@Preview +@Composable +private fun SignupMethodContentScreenPreview() { + MifosTheme { + SignupMethodScreenContent( + onSignUpAsMerchant = {}, + onSignupAsCustomer = {}, + ) + } +} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt deleted file mode 100644 index 7da08aa6a..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.di - -import org.koin.core.module.dsl.viewModel -import org.koin.dsl.module -import org.mifospay.feature.auth.login.LoginViewModel -import org.mifospay.feature.auth.mobileVerify.MobileVerificationViewModel -import org.mifospay.feature.auth.signup.SignupViewModel - -val AuthModule = module { - viewModel { - LoginViewModel( - mUseCaseHandler = get(), - authenticateUserUseCase = get(), - fetchClientDataUseCase = get(), - fetchUserDetailsUseCase = get(), - preferencesHelper = get(), - ) - } - viewModel { - SignupViewModel( - localAssetRepository = get(), - useCaseHandler = get(), - preferencesHelper = get(), - searchClientUseCase = get(), - createClientUseCase = get(), - createUserUseCase = get(), - updateUserUseCase = get(), - authenticateUserUseCase = get(), - fetchClientDataUseCase = get(), - deleteUserUseCase = get(), - fetchUserDetailsUseCase = get(), - ) - } - viewModel { - MobileVerificationViewModel( - mUseCaseHandler = get(), - searchClientUseCase = get(), - ) - } -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt deleted file mode 100644 index 4cddd202e..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.login - -import android.widget.Toast -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -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.rememberScrollState -import androidx.compose.foundation.verticalScroll -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.remember -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.stringResource -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.text.style.TextDecoration -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import org.koin.androidx.compose.koinViewModel -import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel -import org.mifospay.core.designsystem.component.MifosButton -import org.mifospay.core.designsystem.component.MifosOutlinedTextField -import org.mifospay.core.designsystem.icon.MifosIcons -import org.mifospay.core.designsystem.theme.MifosTheme -import org.mifospay.core.designsystem.theme.grey -import org.mifospay.core.designsystem.theme.styleNormal18sp -import org.mifospay.feature.auth.R -import org.mifospay.feature.auth.socialSignup.SocialSignupMethodContentScreen - -@Composable -internal fun LoginScreen( - navigateToPasscodeScreen: () -> Unit, - modifier: Modifier = Modifier, - viewModel: LoginViewModel = koinViewModel(), - navigateToSignupScreen: () -> Unit, -) { - val context = LocalContext.current - val showProgress by viewModel.showProgress.collectAsStateWithLifecycle() - val isLoginSuccess by viewModel.isLoginSuccess.collectAsStateWithLifecycle() - - LoginScreenContent( - modifier = modifier, - showProgress = showProgress, - login = { username, password -> - viewModel.loginUser( - username = username, - password = password, - onLoginFailed = { message -> - Toast.makeText(context, message, Toast.LENGTH_SHORT).show() - }, - ) - }, - navigateToSignupScreen = navigateToSignupScreen, - ) - - if (isLoginSuccess) { - navigateToPasscodeScreen() - } -} - -@Composable -@Suppress("LongMethod") -private fun LoginScreenContent( - showProgress: Boolean, - login: (username: String, password: String) -> Unit, - modifier: Modifier = Modifier, - navigateToSignupScreen: () -> Unit, -) { - var showSignUpScreen by rememberSaveable { mutableStateOf(false) } - - var userName by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf( - TextFieldValue(""), - ) - } - var password by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf( - TextFieldValue(""), - ) - } - var passwordVisibility: Boolean by remember { mutableStateOf(false) } - - if (showSignUpScreen) { - SocialSignupMethodContentScreen( - navigateToSignupScreen = navigateToSignupScreen, - ) { - showSignUpScreen = false - } - } - - Box( - modifier = modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.surface), - ) { - Column( - modifier = Modifier - .fillMaxSize() - .verticalScroll(rememberScrollState()) - .padding(top = 100.dp, start = 48.dp, end = 48.dp), - horizontalAlignment = Alignment.Start, - ) { - Text( - text = stringResource(id = R.string.feature_auth_login), - style = MaterialTheme.typography.titleLarge, - color = MaterialTheme.colorScheme.primary, - ) - Text( - modifier = Modifier - .padding(top = 32.dp), - text = stringResource(id = R.string.feature_auth_welcome_back), - style = styleNormal18sp.copy(color = grey), - ) - Spacer(modifier = Modifier.padding(top = 32.dp)) - MifosOutlinedTextField( - label = R.string.feature_auth_username, - value = userName, - onValueChange = { - userName = it - }, - modifier = Modifier.fillMaxWidth(), - ) - Spacer(modifier = Modifier.padding(top = 16.dp)) - MifosOutlinedTextField( - label = R.string.feature_auth_password, - value = password, - onValueChange = { - password = it - }, - modifier = Modifier.fillMaxWidth(), - visualTransformation = if (passwordVisibility) { - VisualTransformation.None - } else { - PasswordVisualTransformation() - }, - trailingIcon = { - val image = if (passwordVisibility) { - MifosIcons.Visibility - } else { - MifosIcons.VisibilityOff - } - IconButton(onClick = { passwordVisibility = !passwordVisibility }) { - Icon(imageVector = image, null) - } - }, - ) - MifosButton( - modifier = Modifier - .fillMaxWidth() - .padding(top = 16.dp), - enabled = userName.text.isNotEmpty() && password.text.isNotEmpty(), - onClick = { - login.invoke(userName.text, password.text) - }, - contentPadding = PaddingValues(12.dp), - ) { - Text( - text = stringResource(id = R.string.feature_auth_login).uppercase(), - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onPrimary, - ) - } - // Hide reset password for now - /*Text( - modifier = Modifier - .fillMaxWidth() - .padding(top = 32.dp), - text = "Forgot Password", - textAlign = TextAlign.Center, - style = styleMedium16sp.copy( - textDecoration = TextDecoration.Underline, - ) - ) - Text( - modifier = Modifier - .fillMaxWidth() - .padding(top = 24.dp), - text = "OR", - textAlign = TextAlign.Center, - style = styleMedium16sp.copy(color = grey) - )*/ - Row( - modifier = Modifier - .fillMaxWidth() - .padding(top = 24.dp), - horizontalArrangement = Arrangement.Center, - ) { - Text( - text = "Don’t have an account yet? ", - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onSurface, - ) - Text( - modifier = Modifier.clickable { - showSignUpScreen = true - }, - text = stringResource(id = R.string.feature_auth_sign_up), - style = MaterialTheme.typography.titleMedium.copy( - textDecoration = TextDecoration.Underline, - ), - ) - } - } - - if (showProgress) { - MfOverlayLoadingWheel( - contentDesc = stringResource(id = R.string.feature_auth_logging_in), - ) - } - } -} - -@Preview(showSystemUi = true, device = "id:pixel_5") -@Composable -private fun LoanScreenPreview() { - MifosTheme { - LoginScreenContent( - showProgress = false, - login = { _, _ -> }, - navigateToSignupScreen = {}, - ) - } -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt deleted file mode 100644 index 8ed1a1cec..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.login - -import android.util.Log -import androidx.lifecycle.ViewModel -import com.mifospay.core.model.domain.client.Client -import com.mifospay.core.model.domain.user.User -import com.mifospay.core.model.entity.UserWithRole -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.update -import org.mifospay.core.data.base.UseCase.UseCaseCallback -import org.mifospay.core.data.base.UseCaseHandler -import org.mifospay.core.data.domain.usecase.client.FetchClientData -import org.mifospay.core.data.domain.usecase.user.AuthenticateUser -import org.mifospay.core.data.domain.usecase.user.FetchUserDetails -import org.mifospay.core.datastore.PreferencesHelper - -class LoginViewModel( - private val mUseCaseHandler: UseCaseHandler, - private val authenticateUserUseCase: AuthenticateUser, - private val fetchClientDataUseCase: FetchClientData, - private val fetchUserDetailsUseCase: FetchUserDetails, - private val preferencesHelper: PreferencesHelper, -) : ViewModel() { - - private val _showProgress = MutableStateFlow(false) - val showProgress: StateFlow = _showProgress - - private val _isLoginSuccess = MutableStateFlow(false) - val isLoginSuccess: StateFlow = _isLoginSuccess - - fun updateProgressState(isVisible: Boolean) { - _showProgress.update { isVisible } - } - - fun updateIsLoginSuccess(isLoginSuccess: Boolean) { - _isLoginSuccess.update { isLoginSuccess } - } - - /** - * Authenticate User with username and password - * @param username - * @param password - * Note: username and password can't be empty or null when we pass to API - */ - fun loginUser( - username: String, - password: String, - onLoginFailed: (String) -> Unit, - ) { - updateProgressState(true) - authenticateUserUseCase.walletRequestValues = - AuthenticateUser.RequestValues(username, password) - - val requestValue = authenticateUserUseCase.walletRequestValues - mUseCaseHandler.execute( - authenticateUserUseCase, - requestValue, - object : UseCaseCallback { - override fun onSuccess(response: AuthenticateUser.ResponseValue) { - saveAuthTokenInPref(response.user) - fetchClientData(response.user) - fetchUserDetails(response.user) - } - - override fun onError(message: String) { - updateProgressState(false) - onLoginFailed(message) - } - }, - ) - } - - /** - * Fetch user details return by authenticated user - * @param user - */ - private fun fetchUserDetails(user: User) { - mUseCaseHandler.execute( - fetchUserDetailsUseCase, - FetchUserDetails.RequestValues(user.userId), - object : UseCaseCallback { - override fun onSuccess(response: FetchUserDetails.ResponseValue) { - saveUserDetails(user, response.userWithRole) - } - - override fun onError(message: String) { - updateProgressState(false) - Log.d("Login User Detailed: ", message) - } - }, - ) - } - - /** - * Fetch client details return by authenticated user - * Client Id: user.clients.firstOrNull() ?: 0 - * @param user - */ - private fun fetchClientData(user: User) { - mUseCaseHandler.execute( - fetchClientDataUseCase, - FetchClientData.RequestValues(user.clients.firstOrNull()), - object : UseCaseCallback { - override fun onSuccess(response: FetchClientData.ResponseValue) { - saveClientDetails(response.clientDetails) - updateProgressState(false) - if (response.clientDetails.name != "") { - updateIsLoginSuccess(true) - } - } - - override fun onError(message: String) { - updateProgressState(false) - } - }, - ) - } - - private fun saveAuthTokenInPref(user: User) { - preferencesHelper.saveToken("Basic " + user.base64EncodedAuthenticationKey) - } - - /** - * TODO remove userName, userId and Email from pref and use from saved User - */ - private fun saveUserDetails( - user: User, - userWithRole: UserWithRole, - ) { - val userName = user.username - val userID = user.userId - preferencesHelper.saveUsername(userName) - preferencesHelper.userId = userID - preferencesHelper.saveEmail(userWithRole.email) - preferencesHelper.user = user - } - - /** - * TODO remove name, clientId and mobileNo from pref and use from saved Client - */ - private fun saveClientDetails(client: Client?) { - preferencesHelper.saveFullName(client?.name) - preferencesHelper.clientId = client?.clientId!! - preferencesHelper.saveMobile(client.mobileNo) - preferencesHelper.client = client - } -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt deleted file mode 100644 index 31cc30a7d..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.mobileVerify - -import android.widget.Toast -import androidx.compose.foundation.background -import androidx.compose.foundation.focusable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextFieldDefaults -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.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.TextFieldValue -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.mifos.library.countrycodepicker.CountryCodePicker -import org.koin.androidx.compose.koinViewModel -import org.mifospay.core.common.Constants -import org.mifospay.core.designsystem.component.MifosButton -import org.mifospay.core.designsystem.component.MifosLoadingWheel -import org.mifospay.core.designsystem.component.MifosOutlinedTextField -import org.mifospay.core.designsystem.theme.MifosTheme -import org.mifospay.feature.auth.R - -@Composable -internal fun MobileVerificationScreen( - onOtpVerificationSuccess: (String) -> Unit, - modifier: Modifier = Modifier, - viewModel: MobileVerificationViewModel = koinViewModel(), -) { - val context = LocalContext.current - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - MobileVerificationScreen( - uiState = uiState, - showProgressState = viewModel.showProgress, - verifyMobileAndRequestOtp = { phone, fullPhone -> - viewModel.verifyMobileAndRequestOtp(fullPhone, phone) { - it?.let { - Toast.makeText(context, it, Toast.LENGTH_SHORT).show() - } - } - }, - verifyOtp = { validatedOtp, fullNumber -> - viewModel.verifyOTP(validatedOtp) { - onOtpVerificationSuccess(fullNumber) - } - }, - modifier = modifier, - ) -} - -@Composable -private fun MobileVerificationScreen( - uiState: MobileVerificationUiState, - verifyMobileAndRequestOtp: (String, String) -> Unit, - verifyOtp: (String, String) -> Unit, - modifier: Modifier = Modifier, - showProgressState: Boolean = false, -) { - var phoneNumber by rememberSaveable { mutableStateOf("") } - var fullPhoneNumber by rememberSaveable { mutableStateOf("") } - var isNumberValid: Boolean by rememberSaveable { mutableStateOf(false) } - - var isOtpValidated by rememberSaveable { mutableStateOf(false) } - var validatedOtp by rememberSaveable { mutableStateOf("") } - - fun verifyMobileOrOtp() { - if (uiState == MobileVerificationUiState.VerifyPhone && isNumberValid) { - verifyMobileAndRequestOtp(phoneNumber, fullPhoneNumber) - } else if (isOtpValidated) { - verifyOtp(validatedOtp, fullPhoneNumber) - } - } - - Box(modifier) { - Column( - modifier = Modifier - .fillMaxSize() - .background(color = Color.White) - .focusable(!showProgressState), - ) { - Column( - modifier = Modifier - .fillMaxWidth() - .background(color = MaterialTheme.colorScheme.primary), - verticalArrangement = Arrangement.Top, - ) { - Text( - modifier = Modifier.padding(top = 48.dp, start = 24.dp, end = 24.dp), - text = if (uiState == MobileVerificationUiState.VerifyPhone) { - stringResource(id = R.string.feature_auth_enter_mobile_number) - } else { - stringResource(id = R.string.feature_auth_enter_otp) - }, - style = MaterialTheme.typography.titleLarge.copy(color = MaterialTheme.colorScheme.onPrimary), - ) - Text( - modifier = Modifier.padding( - top = 4.dp, - bottom = 32.dp, - start = 24.dp, - end = 24.dp, - ), - text = if (uiState == MobileVerificationUiState.VerifyPhone) { - stringResource(id = R.string.feature_auth_enter_mobile_number_description) - } else { - stringResource(id = R.string.feature_auth_enter_otp_received_on_your_registered_device) - }, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onPrimary, - ) - } - - when (uiState) { - MobileVerificationUiState.VerifyPhone -> { - EnterPhoneScreen( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 16.dp), - onNumberUpdated = { phone, fullPhone, valid -> - phoneNumber = phone - fullPhoneNumber = fullPhone - isNumberValid = valid - }, - ) - } - - MobileVerificationUiState.VerifyOtp -> { - EnterOtpScreen( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 48.dp, vertical = 24.dp), - onOtpValidated = { isValidated, otp -> - isOtpValidated = isValidated - validatedOtp = otp - }, - ) - } - } - - MifosButton( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 32.dp, vertical = 16.dp), - color = MaterialTheme.colorScheme.primary, - enabled = if (uiState == MobileVerificationUiState.VerifyPhone) { - isNumberValid - } else { - isOtpValidated - }, - onClick = { verifyMobileOrOtp() }, - contentPadding = PaddingValues(12.dp), - ) { - Text( - text = if (uiState == MobileVerificationUiState.VerifyPhone) { - stringResource(id = R.string.feature_auth_verify_phone).uppercase() - } else { - stringResource(id = R.string.feature_auth_verify_otp).uppercase() - }, - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onPrimary, - ) - } - } - - if (showProgressState) { - ShowProgressScreen(uiState = uiState) - } - } -} - -@Composable -private fun EnterPhoneScreen( - onNumberUpdated: (String, String, Boolean) -> Unit, - modifier: Modifier = Modifier, -) { - val keyboardController = LocalSoftwareKeyboardController.current - CountryCodePicker( - modifier = modifier, - shape = RoundedCornerShape(8.dp), - colors = OutlinedTextFieldDefaults.colors( - focusedBorderColor = MaterialTheme.colorScheme.primary, - ), - onValueChange = { (code, phone), isValid -> - onNumberUpdated(phone, code + phone, isValid) - }, - label = { Text(stringResource(id = R.string.feature_auth_phone_number)) }, - keyboardActions = KeyboardActions { keyboardController?.hide() }, - ) -} - -@Composable -private fun EnterOtpScreen( - onOtpValidated: (Boolean, String) -> Unit, - modifier: Modifier = Modifier, -) { - val keyboardController = LocalSoftwareKeyboardController.current - var otp by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue("")) - } - - MifosOutlinedTextField( - label = R.string.feature_auth_enter_otp, - value = otp, - onValueChange = { - otp = it - onOtpValidated(otp.text.length == 6, otp.text) - }, - modifier = modifier, - keyboardActions = KeyboardActions { keyboardController?.hide() }, - ) -} - -@Composable -private fun ShowProgressScreen( - uiState: MobileVerificationUiState, - modifier: Modifier = Modifier, -) { - Box( - modifier = modifier - .fillMaxSize() - .background(color = MaterialTheme.colorScheme.primary.copy(alpha = 0.6f)) - .focusable(), - contentAlignment = Alignment.Center, - ) { - MifosLoadingWheel( - modifier = Modifier.wrapContentSize(), - contentDesc = if (uiState == MobileVerificationUiState.VerifyPhone) { - Constants.SENDING_OTP_TO_YOUR_MOBILE_NUMBER - } else { - Constants.VERIFYING_OTP - }, - ) - } -} - -@Preview -@Composable -private fun MobileVerificationScreenVerifyPhonePreview() { - MifosTheme { - MobileVerificationScreen( - uiState = MobileVerificationUiState.VerifyPhone, - showProgressState = false, - verifyMobileAndRequestOtp = { _, _ -> }, - verifyOtp = { _, _ -> }, - ) - } -} - -@Preview -@Composable -private fun MobileVerificationScreenVerifyOtpPreview() { - MifosTheme { - MobileVerificationScreen( - uiState = MobileVerificationUiState.VerifyOtp, - showProgressState = false, - verifyMobileAndRequestOtp = { _, _ -> }, - verifyOtp = { _, _ -> }, - ) - } -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt deleted file mode 100644 index fa0e3b7ab..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.mobileVerify - -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.base.UseCaseHandler -import org.mifospay.core.data.domain.usecase.client.SearchClient - -@Suppress("UnusedParameter") -class MobileVerificationViewModel( - private val mUseCaseHandler: UseCaseHandler, - private val searchClientUseCase: SearchClient, -) : ViewModel() { - - private val _uiState = - MutableStateFlow(MobileVerificationUiState.VerifyPhone) - val uiState: StateFlow = _uiState - - var showProgress by mutableStateOf(false) - - /** - * Verify Mobile number that it already exist or not then request otp - */ - fun verifyMobileAndRequestOtp( - fullNumber: String, - mobileNo: String, - onError: (String?) -> Unit, - ) { - showProgress = true - mUseCaseHandler.execute( - searchClientUseCase, - fullNumber.let { SearchClient.RequestValues(it) }, - object : UseCase.UseCaseCallback { - override fun onSuccess(response: SearchClient.ResponseValue) { - onError("Mobile number already exists.") - showProgress = false - } - - override fun onError(message: String) { - requestOtp(fullNumber) - } - }, - ) - } - - /** - * Request Otp from server - */ - fun requestOtp(fullNumber: String) { - viewModelScope.launch { - delay(2000) - showProgress = false - _uiState.update { - MobileVerificationUiState.VerifyOtp - } - } - } - - /** - * Verify Otp - */ - fun verifyOTP(otp: String?, onOtpVerifySuccess: () -> Unit) { - showProgress = true - viewModelScope.launch { - delay(2000) - showProgress = false - onOtpVerifySuccess() - } - } -} - -sealed interface MobileVerificationUiState { - data object VerifyOtp : MobileVerificationUiState - data object VerifyPhone : MobileVerificationUiState -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt deleted file mode 100644 index 2eb75757b..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -@file:Suppress("MaxLineLength") - -package org.mifospay.feature.auth.navigation - -import androidx.navigation.NavController -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavType -import androidx.navigation.compose.composable -import androidx.navigation.navArgument -import org.mifospay.core.common.Constants -import org.mifospay.feature.auth.mobileVerify.MobileVerificationScreen - -const val MOBILE_VERIFICATION_ROUTE = "mobile_verification_route" - -fun NavGraphBuilder.mobileVerificationScreen( - onOtpVerificationSuccess: (String, Map) -> Unit, -) { - composable( - route = "$MOBILE_VERIFICATION_ROUTE?mifosSignedUp={mifosSignedUp}&googleDisplayName={googleDisplayName}&googleEmail={googleEmail}&googleFamilyName={googleFamilyName}&googleGivenName={googleGivenName}", - arguments = listOf( - navArgument("mifosSignedUp") { - type = NavType.IntType - defaultValue = 0 - }, - navArgument("googleDisplayName") { - type = NavType.StringType - nullable = true - }, - navArgument("googleEmail") { - type = NavType.StringType - nullable = true - }, - navArgument("googleFamilyName") { - type = NavType.StringType - nullable = true - }, - navArgument("googleGivenName") { - type = NavType.StringType - nullable = true - }, - ), - ) { backStackEntry -> - val mifosSignedUp = backStackEntry.arguments?.getInt("mifosSignedUp") ?: 0 - val googleDisplayName = backStackEntry.arguments?.getString("googleDisplayName") - val googleEmail = backStackEntry.arguments?.getString("googleEmail") - val googleFamilyName = backStackEntry.arguments?.getString("googleFamilyName") - val googleGivenName = backStackEntry.arguments?.getString("googleGivenName") - - MobileVerificationScreen( - onOtpVerificationSuccess = { fullNumber -> - val extraData = mapOf( - Constants.MIFOS_SAVINGS_PRODUCT_ID to mifosSignedUp, - Constants.GOOGLE_DISPLAY_NAME to googleDisplayName, - Constants.GOOGLE_EMAIL to googleEmail, - Constants.GOOGLE_FAMILY_NAME to googleFamilyName, - Constants.GOOGLE_GIVEN_NAME to googleGivenName, - Constants.COUNTRY to "Canada", - Constants.MOBILE_NUMBER to fullNumber, - ) - onOtpVerificationSuccess(fullNumber, extraData) - }, - ) - } -} - -fun NavController.navigateToMobileVerification( - mifosSignedUp: Int, - googleDisplayName: String?, - googleEmail: String?, - googleFamilyName: String?, - googleGivenName: String?, -) { - this.navigate("$MOBILE_VERIFICATION_ROUTE?mifosSignedUp=$mifosSignedUp&googleDisplayName=$googleDisplayName&googleEmail=$googleEmail&googleFamilyName=$googleFamilyName&googleGivenName=$googleGivenName") -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt deleted file mode 100644 index 6c696eba9..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -@file:Suppress("MaxLineLength") - -package org.mifospay.feature.auth.navigation - -import androidx.navigation.NavController -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavType -import androidx.navigation.compose.composable -import androidx.navigation.navArgument -import org.mifospay.feature.auth.signup.SignupScreen - -const val SIGNUP_ROUTE = "signup_route" - -@Suppress("UnusedParameter") -fun NavGraphBuilder.signupScreen( - onLoginSuccess: () -> Unit, - onRegisterSuccess: () -> Unit, -) { - composable( - route = "$SIGNUP_ROUTE?savingProductId={savingProductId}&mobileNumber={mobileNumber}&country={country}&email={email}&firstName={firstName}&lastName={lastName}&businessName={businessName}", - arguments = listOf( - navArgument("savingProductId") { - type = NavType.IntType - defaultValue = 0 - }, - navArgument("mobileNumber") { - type = NavType.StringType - defaultValue = "" - }, - navArgument("country") { - type = NavType.StringType - defaultValue = "" - }, - navArgument("email") { - type = NavType.StringType - defaultValue = "" - }, - navArgument("firstName") { - type = NavType.StringType - defaultValue = "" - }, - navArgument("lastName") { - type = NavType.StringType - defaultValue = "" - }, - navArgument("businessName") { - type = NavType.StringType - defaultValue = "" - }, - ), - ) { backStackEntry -> - val savingProductId = backStackEntry.arguments?.getInt("savingProductId") ?: 0 - val mobileNumber = backStackEntry.arguments?.getString("mobileNumber") ?: "" - val country = backStackEntry.arguments?.getString("country") ?: "" - val email = backStackEntry.arguments?.getString("email") ?: "" - val firstName = backStackEntry.arguments?.getString("firstName") ?: "" - val lastName = backStackEntry.arguments?.getString("lastName") ?: "" - val businessName = backStackEntry.arguments?.getString("businessName") ?: "" - - SignupScreen( - onLoginSuccess = onLoginSuccess, - savingProductId = savingProductId, - mobileNumber = mobileNumber, - country = country, - email = email, - firstName = firstName, - lastName = lastName, - businessName = businessName, - ) - } -} - -fun NavController.navigateToSignup( - savingProductId: Int = 0, - mobileNumber: String = "", - country: String = "", - email: String = "", - firstName: String = "", - lastName: String = "", - businessName: String = "", -) { - this.navigate( - "$SIGNUP_ROUTE?savingProductId=$savingProductId" + - "&mobileNumber=$mobileNumber&country=$country&email=$email" + - "&firstName=$firstName&lastName=$lastName&businessName=$businessName", - ) -} - -@Suppress("UnusedParameter") -fun onRegisterSuccess(s: String?) { - // registered but unable to login or user not updated with client - // TODO :: Consider this case - // 1. User not updated: when logging in update user - // 2. User unable to login (must be caused due to server) - // Toast.makeText(this, "Registered successfully.", Toast.LENGTH_SHORT).show() - // startActivity(Intent(this@SignupActivity, LoginActivity::class.java)) - // finish() -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt deleted file mode 100644 index 91525c17a..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt +++ /dev/null @@ -1,531 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.signup - -import android.widget.Toast -import androidx.compose.foundation.background -import androidx.compose.foundation.focusable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -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.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.ExposedDropdownMenuDefaults -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField -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.Color -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import org.mifospay.core.model.State -import com.mifospay.core.model.signup.PasswordStrength -import com.mifospay.core.model.signup.SignupData -import org.koin.androidx.compose.koinViewModel -import org.mifospay.core.data.util.Constants.MIFOS_MERCHANT_SAVINGS_PRODUCT_ID -import org.mifospay.core.designsystem.component.MfOutlinedTextField -import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel -import org.mifospay.core.designsystem.component.MfPasswordTextField -import org.mifospay.core.designsystem.component.MifosButton -import org.mifospay.core.designsystem.theme.styleMedium16sp -import org.mifospay.feature.auth.R -import org.mifospay.feature.auth.utils.ValidateUtil.isValidEmail -import java.util.Locale - -@Composable -internal fun SignupScreen( - savingProductId: Int, - mobileNumber: String, - country: String, - email: String, - firstName: String, - lastName: String, - businessName: String, - onLoginSuccess: () -> Unit, - modifier: Modifier = Modifier, - viewModel: SignupViewModel = koinViewModel(), -) { - val context = LocalContext.current - - val stateList by viewModel.states.collectAsStateWithLifecycle() - - LaunchedEffect(key1 = true) { - viewModel.initSignupData( - savingProductId = savingProductId, - mobileNumber = mobileNumber, - countryName = country, - email = email, - firstName = firstName, - lastName = lastName, - businessName = businessName, - ) - } - LaunchedEffect(viewModel.isLoginSuccess) { - if (viewModel.isLoginSuccess) { - onLoginSuccess.invoke() - } - } - - SignupScreenContent( - modifier = modifier, - showProgressState = viewModel.showProgress, - data = viewModel.signupData, - stateList = stateList, - onCompleteRegistration = { - viewModel.registerUser(it) { message -> - Toast.makeText(context, message, Toast.LENGTH_SHORT).show() - } - }, - ) -} - -@Composable -@Suppress("LongMethod", "CyclomaticComplexMethod") -private fun SignupScreenContent( - data: SignupData, - stateList: List, - onCompleteRegistration: (SignupData) -> Unit, - modifier: Modifier = Modifier, - showProgressState: Boolean = false, -) { - val context = LocalContext.current - - var firstName by rememberSaveable { mutableStateOf(data.firstName ?: "") } - var lastName by rememberSaveable { mutableStateOf(data.lastName ?: "") } - var email by rememberSaveable { mutableStateOf(data.email ?: "") } - var userName by rememberSaveable { - mutableStateOf( - data.email?.ifEmpty { "" } - ?: data.email?.let { it.substring(0, it.indexOf('@')) } ?: "", - ) - } - var addressLine1 by rememberSaveable { mutableStateOf("") } - var addressLine2 by rememberSaveable { mutableStateOf("") } - var pinCode by rememberSaveable { mutableStateOf("") } - var nameOfBusiness by rememberSaveable { mutableStateOf(data.businessName ?: "") } - - var password by rememberSaveable { mutableStateOf("") } - var confirmPassword by rememberSaveable { mutableStateOf("") } - var isPasswordVisible by rememberSaveable { mutableStateOf(false) } - var isConfirmPasswordVisible by rememberSaveable { mutableStateOf(false) } - - var selectedState by rememberSaveable { mutableStateOf(null) } - - fun validateAllFields() { - val isAnyFieldEmpty = - firstName.isEmpty() || - lastName.isEmpty() || - email.isEmpty() || - userName.isEmpty() || - addressLine1.isEmpty() || - addressLine2.isEmpty() || - pinCode.isEmpty() || - password.isEmpty() || - confirmPassword.isEmpty() || - selectedState == null - - val isNameOfBusinessEmpty = - data.mifosSavingsProductId == MIFOS_MERCHANT_SAVINGS_PRODUCT_ID && - nameOfBusiness.isEmpty() - - if (!email.isValidEmail()) { - Toast - .makeText( - context, - context.getString(R.string.feature_auth_validate_email), - Toast.LENGTH_SHORT, - ).show() - return - } - - if (isAnyFieldEmpty || isNameOfBusinessEmpty) { - Toast - .makeText( - context, - context.getString(R.string.feature_auth_all_fields_are_mandatory), - Toast.LENGTH_SHORT, - ).show() - return - } - } - - fun completeRegistration() { - val signUpData = - data.copy( - firstName = firstName, - lastName = lastName, - email = email, - userName = userName, - addressLine1 = addressLine1, - addressLine2 = addressLine2, - pinCode = pinCode, - businessName = nameOfBusiness, - password = password, - stateId = selectedState?.id, - ) - onCompleteRegistration.invoke(signUpData) - } - - Box(modifier) { - Column( - modifier = - Modifier - .fillMaxSize() - .background(color = MaterialTheme.colorScheme.surface) - .verticalScroll(rememberScrollState()) - .focusable(!showProgressState), - ) { - Column( - modifier = - Modifier - .fillMaxWidth() - .background(color = MaterialTheme.colorScheme.primary), - verticalArrangement = Arrangement.Top, - ) { - Text( - modifier = Modifier.padding(top = 48.dp, start = 24.dp, end = 24.dp), - text = stringResource(id = R.string.feature_auth_complete_your_registration), - style = MaterialTheme.typography.titleLarge.copy(color = MaterialTheme.colorScheme.onPrimary), - ) - Text( - modifier = - Modifier.padding( - top = 4.dp, - bottom = 32.dp, - start = 24.dp, - end = 24.dp, - ), - text = stringResource(id = R.string.feature_auth_all_fields_are_mandatory), - style = MaterialTheme.typography.bodySmall.copy(color = Color.White), - ) - } - - Column( - modifier = - Modifier - .fillMaxWidth() - .padding(horizontal = 32.dp) - .focusable(!showProgressState), - ) { - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 16.dp), - label = stringResource(id = R.string.feature_auth_first_name), - value = firstName, - ) { - firstName = it - } - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_last_name), - value = lastName, - ) { - lastName = it - } - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_username), - value = userName, - ) { - userName = it - } - PasswordAndConfirmPassword( - password = password, - onPasswordChange = { password = it }, - confirmPassword = confirmPassword, - onConfirmPasswordChange = { confirmPassword = it }, - isPasswordVisible = isPasswordVisible, - onTogglePasswordVisibility = { isPasswordVisible = !isPasswordVisible }, - isConfirmPasswordVisible = isConfirmPasswordVisible, - onConfirmTogglePasswordVisibility = { - isConfirmPasswordVisible = !isConfirmPasswordVisible - }, - ) - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_email), - value = email, - ) { - email = it - } - if (data.mifosSavingsProductId == MIFOS_MERCHANT_SAVINGS_PRODUCT_ID) { - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_name_of_business), - value = nameOfBusiness, - ) { - nameOfBusiness = it - } - } - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_address_line_1), - value = addressLine1, - ) { - addressLine1 = it - } - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_address_line_2), - value = addressLine2, - ) { - addressLine2 = it - } - UserInfoTextField( - modifier = Modifier.padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_pin_code), - value = pinCode, - ) { - pinCode = it - } - HorizontalDivider(thickness = 8.dp, color = Color.White) - MifosStateDropDownOutlinedTextField( - value = selectedState?.name ?: "", - label = stringResource(id = R.string.feature_auth_state), - stateList = stateList, - ) { - selectedState = it - } - HorizontalDivider(thickness = 24.dp, color = Color.White) - MifosButton( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - color = MaterialTheme.colorScheme.primary, - enabled = true, - onClick = { - validateAllFields() - completeRegistration() - }, - contentPadding = PaddingValues(12.dp), - ) { - Text( - text = stringResource(id = R.string.feature_auth_complete), - style = styleMedium16sp.copy(color = MaterialTheme.colorScheme.onPrimary), - ) - } - } - } - - if (showProgressState) { - MfOverlayLoadingWheel( - contentDesc = stringResource(id = R.string.feature_auth_please_wait), - ) - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun MifosStateDropDownOutlinedTextField( - value: String, - label: String, - stateList: List, - modifier: Modifier = Modifier, - onSelectedState: (State) -> Unit = {}, -) { - var expanded by rememberSaveable { mutableStateOf(false) } - ExposedDropdownMenuBox( - expanded = expanded, - onExpandedChange = { - expanded = !expanded - }, - ) { - OutlinedTextField( - modifier = modifier.menuAnchor(), - value = value, - onValueChange = { }, - readOnly = true, - label = { Text(label) }, - trailingIcon = { - ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) - }, - ) - DropdownMenu( - expanded = expanded, - onDismissRequest = { - expanded = false - }, - ) { - stateList.forEach { - DropdownMenuItem( - text = { Text(text = it.name) }, - onClick = { - expanded = false - onSelectedState(it) - }, - ) - } - } - } -} - -@Composable -private fun UserInfoTextField( - label: String, - value: String, - modifier: Modifier = Modifier, - onValueChange: (String) -> Unit = {}, -) { - MfOutlinedTextField( - value = value, - label = label, - onValueChange = onValueChange, - modifier = modifier, - isError = value.isEmpty(), - errorMessage = stringResource(id = R.string.feature_auth_mandatory), - ) -} - -@Composable -private fun PasswordAndConfirmPassword( - password: String, - onPasswordChange: (String) -> Unit, - confirmPassword: String, - onConfirmPasswordChange: (String) -> Unit, - isPasswordVisible: Boolean, - onTogglePasswordVisibility: () -> Unit, - isConfirmPasswordVisible: Boolean, - onConfirmTogglePasswordVisibility: () -> Unit, - modifier: Modifier = Modifier, -) { - Column(modifier) { - MfPasswordTextField( - password = password, - label = stringResource(id = R.string.feature_auth_password), - isError = password.isEmpty() || password.length < 6, - isPasswordVisible = isPasswordVisible, - onTogglePasswordVisibility = onTogglePasswordVisibility, - onPasswordChange = onPasswordChange, - modifier = Modifier.fillMaxWidth(), - errorMessage = - if (password.isEmpty()) { - stringResource(id = R.string.feature_auth_password_cannot_be_empty) - } else if (password.length < 6) { - stringResource(id = R.string.feature_auth_password_must_be_least_6_characters) - } else { - null - }, - ) - MfPasswordTextField( - password = confirmPassword, - label = stringResource(id = R.string.feature_auth_confirm_password), - isError = confirmPassword.isEmpty() || password != confirmPassword, - isPasswordVisible = isConfirmPasswordVisible, - onTogglePasswordVisibility = onConfirmTogglePasswordVisibility, - onPasswordChange = onConfirmPasswordChange, - modifier = Modifier.fillMaxWidth(), - errorMessage = - if (confirmPassword.isEmpty()) { - stringResource(id = R.string.feature_auth_confirm_password_cannot_empty) - } else if (password != confirmPassword) { - stringResource(id = R.string.feature_auth_passwords_do_not_match) - } else { - null - }, - ) - if (password.length >= 6) { - Text( - modifier = Modifier.padding(top = 8.dp), - text = "${stringResource(id = R.string.feature_auth_password_strength)}${ - getPasswordStrength(password).replaceFirstChar { - if (it.isLowerCase()) { - it.titlecase( - Locale.ENGLISH, - ) - } else { - it.toString() - } - } - }", - color = getPasswordStrengthColor(password), - ) - } - } -} - -private fun getPasswordStrength(password: String): String { - val hasUpperCase = password.any { it.isUpperCase() } - val hasLowerCase = password.any { it.isLowerCase() } - val hasNumbers = password.any { it.isDigit() } - val hasSymbols = password.any { !it.isLetterOrDigit() } - - val numTypesPresent = - intArrayOf( - hasUpperCase.toInt(), - hasLowerCase.toInt(), - hasNumbers.toInt(), - hasSymbols.toInt(), - ).sum() - return PasswordStrength.entries[numTypesPresent].name -} - -private fun Boolean.toInt() = if (this) 1 else 0 - -private fun getPasswordStrengthColor(password: String): Color { - val strength = getPasswordStrength(password) - return when (PasswordStrength.valueOf(strength)) { - PasswordStrength.WEAK -> Color.Red - PasswordStrength.MODERATE -> Color.DarkGray - PasswordStrength.STRONG -> Color.Green - PasswordStrength.VERY_STRONG -> Color.Blue - PasswordStrength.EXCELLENT -> Color.Magenta - else -> Color.Black - } -} - -@Preview -@Composable -private fun SignupScreenPreview() { - SignupScreenContent( - showProgressState = false, - data = SignupData(), - stateList = listOf(), - onCompleteRegistration = { }, - ) -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt deleted file mode 100644 index 284d93cb4..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.signup - -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import org.mifospay.core.model.State -import com.mifospay.core.model.domain.user.NewUser -import com.mifospay.core.model.domain.user.UpdateUserEntityClients -import com.mifospay.core.model.domain.user.User -import com.mifospay.core.model.entity.UserWithRole -import com.mifospay.core.model.signup.SignupData -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import org.mifospay.core.common.Constants -import org.mifospay.core.common.DebugUtil -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.base.UseCaseHandler -import org.mifospay.core.data.domain.usecase.client.CreateClient -import org.mifospay.core.data.domain.usecase.client.FetchClientData -import org.mifospay.core.data.domain.usecase.client.SearchClient -import org.mifospay.core.data.domain.usecase.user.AuthenticateUser -import org.mifospay.core.data.domain.usecase.user.CreateUser -import org.mifospay.core.data.domain.usecase.user.DeleteUser -import org.mifospay.core.data.domain.usecase.user.FetchUserDetails -import org.mifospay.core.data.domain.usecase.user.UpdateUser -import org.mifospay.core.data.repository.local.LocalAssetRepository -import org.mifospay.core.datastore.PreferencesHelper - -class SignupViewModel( - localAssetRepository: LocalAssetRepository, - private val useCaseHandler: UseCaseHandler, - private val preferencesHelper: PreferencesHelper, - private val searchClientUseCase: SearchClient, - private val createClientUseCase: CreateClient, - private val createUserUseCase: CreateUser, - private val updateUserUseCase: UpdateUser, - private val authenticateUserUseCase: AuthenticateUser, - private val fetchClientDataUseCase: FetchClientData, - private val deleteUserUseCase: DeleteUser, - private val fetchUserDetailsUseCase: FetchUserDetails, -) : ViewModel() { - - var showProgress by mutableStateOf(false) - var isLoginSuccess by mutableStateOf(false) - - var signupData by mutableStateOf(SignupData()) - var state by mutableStateOf(null) - - fun initSignupData( - savingProductId: Int, - mobileNumber: String, - countryName: String?, - email: String?, - firstName: String?, - lastName: String?, - businessName: String?, - ) { - signupData = signupData.copy( - mifosSavingsProductId = savingProductId, - mobileNumber = mobileNumber, - countryName = countryName, - email = email, - firstName = firstName!!, - lastName = lastName!!, - businessName = businessName, - ) - } - - val states: StateFlow> = combine( - localAssetRepository.getCountries(), - localAssetRepository.getStateList(), - ::Pair, - ) - .map { - val countries = it.first - signupData = signupData.copy( - countryId = countries.find { it.name == signupData.countryName }?.id ?: "", - ) - it.second.filter { it.countryId == signupData.countryId } - } - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = emptyList(), - ) - - fun registerUser(data: SignupData, showToastMessage: (String) -> Unit) { - signupData = data - - // 0. Unique Mobile Number (checked in MOBILE VERIFICATION ACTIVITY) - // 1. Check for unique external id and username - // 2. Create user - // 3. Create Client - // 4. Update User and connect client with user - useCaseHandler.execute( - searchClientUseCase, - SearchClient.RequestValues("${signupData.userName}@mifos"), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: SearchClient.ResponseValue) { - showToastMessage("Username already exists.") - } - - override fun onError(message: String) { - createUser(showToastMessage) - } - }, - ) - } - - private fun createUser(showToastMessage: (String) -> Unit) { - val newUser = NewUser( - signupData.userName, - signupData.firstName, - signupData.lastName, - signupData.email, - signupData.password, - ) - useCaseHandler.execute( - createUserUseCase, - CreateUser.RequestValues(newUser), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: CreateUser.ResponseValue) { - createClient(response.userId, showToastMessage) - } - - override fun onError(message: String) { - DebugUtil.log(message) - showToastMessage(message) - } - }, - ) - } - - private fun createClient(userId: Int, showToastMessage: (String) -> Unit) { - val newClient = com.mifospay.core.model.domain.client.NewClient( - signupData.businessName, signupData.userName, signupData.addressLine1, - signupData.addressLine2, signupData.city, signupData.pinCode, signupData.stateId, - signupData.countryId, signupData.mobileNumber, signupData.mifosSavingsProductId, - ) - useCaseHandler.execute( - createClientUseCase, - CreateClient.RequestValues(newClient), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: CreateClient.ResponseValue) { - response.clientId.let { DebugUtil.log(it) } - val clients = ArrayList() - response.clientId.let { clients.add(it) } - updateClient(clients, userId, showToastMessage) - } - - override fun onError(message: String) { - // delete user - DebugUtil.log(message) - showToastMessage(message) - deleteUser(userId) - } - }, - ) - } - - private fun updateClient( - clients: ArrayList, - userId: Int, - showToastMessage: (String) -> Unit, - ) { - useCaseHandler.execute( - updateUserUseCase, - UpdateUser.RequestValues(UpdateUserEntityClients(clients), userId), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: UpdateUser.ResponseValue?) { - loginUser(signupData.userName, signupData.password, showToastMessage) - } - - override fun onError(message: String) { - // connect client later - DebugUtil.log(message) - showToastMessage("update client error") - } - }, - ) - } - - private fun loginUser( - username: String?, - password: String?, - showToastMessage: (String) -> Unit, - ) { - authenticateUserUseCase.walletRequestValues = AuthenticateUser.RequestValues(username!!, password!!) - val requestValue = authenticateUserUseCase.walletRequestValues - useCaseHandler.execute( - authenticateUserUseCase, - requestValue, - object : UseCase.UseCaseCallback { - override fun onSuccess(response: AuthenticateUser.ResponseValue) { - createAuthenticatedService(response.user) - fetchClientData(showToastMessage) - fetchUserDetails(response.user) - } - - override fun onError(message: String) { - showToastMessage("Login Failed") - } - }, - ) - } - - private fun fetchUserDetails(user: User) { - useCaseHandler.execute( - fetchUserDetailsUseCase, - FetchUserDetails.RequestValues(user.userId), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: FetchUserDetails.ResponseValue) { - saveUserDetails(user, response.userWithRole) - } - - override fun onError(message: String) { - DebugUtil.log(message) - } - }, - ) - } - - private fun fetchClientData(showToastMessage: (String) -> Unit) { - useCaseHandler.execute( - fetchClientDataUseCase, - null, - object : UseCase.UseCaseCallback { - override fun onSuccess(response: FetchClientData.ResponseValue) { - saveClientDetails(response.clientDetails) - if (response.clientDetails.name != "") { - isLoginSuccess = true - } - } - - override fun onError(message: String) { - showToastMessage("Fetch Client Error") - } - }, - ) - } - - private fun createAuthenticatedService(user: User) { - val authToken = Constants.BASIC + user.base64EncodedAuthenticationKey - preferencesHelper.saveToken(authToken) - } - - private fun saveUserDetails( - user: User, - userWithRole: UserWithRole, - ) { - val userName = user.username - val userID = user.userId - preferencesHelper.saveUsername(userName) - preferencesHelper.userId = userID - preferencesHelper.saveEmail(userWithRole.email) - } - - private fun saveClientDetails(client: com.mifospay.core.model.domain.client.Client) { - preferencesHelper.saveFullName(client.name) - preferencesHelper.clientId = client.clientId - preferencesHelper.saveMobile(client.mobileNo) - } - - private fun deleteUser(userId: Int) { - useCaseHandler.execute( - deleteUserUseCase, - DeleteUser.RequestValues(userId), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: DeleteUser.ResponseValue) {} - override fun onError(message: String) {} - }, - ) - } -} - -sealed interface SignupUiState { - data object None : SignupUiState - data object Success : SignupUiState - data class Error(val exception: String) : SignupUiState -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt deleted file mode 100644 index 87c377b69..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -@file:Suppress("MaxLineLength") - -package org.mifospay.feature.auth.socialSignup - -import android.content.Context -import android.util.Log -import android.widget.Toast -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -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.layout.size -import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Checkbox -import androidx.compose.material3.CheckboxDefaults -import androidx.compose.material3.CircularProgressIndicator -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.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -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.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.credentials.ClearCredentialStateRequest -import androidx.credentials.CredentialManager -import androidx.credentials.CustomCredential -import androidx.credentials.GetCredentialRequest -import androidx.credentials.GetCredentialResponse -import androidx.credentials.exceptions.GetCredentialException -import com.google.android.libraries.identity.googleid.GetGoogleIdOption -import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential -import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException -import kotlinx.coroutines.launch -import org.mifospay.core.common.Constants -import org.mifospay.core.data.util.Constants.MIFOS_CONSUMER_SAVINGS_PRODUCT_ID -import org.mifospay.core.data.util.Constants.MIFOS_MERCHANT_SAVINGS_PRODUCT_ID -import org.mifospay.core.designsystem.component.MifosBottomSheet -import org.mifospay.core.designsystem.component.MifosOutlinedButton -import org.mifospay.core.designsystem.theme.MifosTheme -import org.mifospay.feature.auth.R - -const val TAG = "Social Login" - -// Followed this https://medium.com/@nirmale.ashwin9696/a-comprehensive-guide-to-google-sign-in-integration-with-credential-manager-in-android-apps-05286f8f5848 -// Keeping until we fix sign up -@Composable -internal fun SocialSignupMethodContentScreen( - modifier: Modifier = Modifier, - navigateToSignupScreen: () -> Unit = {}, - onDismissSignUp: () -> Unit = {}, -) { - SocialSignupMethodScreen( - modifier = modifier, - onDismissSignUp = onDismissSignUp, - navigateToSignupScreen = navigateToSignupScreen, - ) -} - -@Composable -@Suppress("NestedBlockDepth") -private fun SocialSignupMethodScreen( - modifier: Modifier = Modifier, - onDismissSignUp: () -> Unit = {}, - navigateToSignupScreen: () -> Unit = {}, -) { - val context = LocalContext.current - var mifosSavingProductId by remember { mutableIntStateOf(0) } - var showProgress by remember { mutableStateOf(false) } - - val credentialManager = CredentialManager.create(context) - val coroutineScope = rememberCoroutineScope() - var showFilterByAuthorizedAccounts by rememberSaveable { mutableStateOf(false) } - var googleIdTokenCredential by remember { mutableStateOf(null) } - - val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder() - .setFilterByAuthorizedAccounts(false) - .setServerClientId("728434912738-ea88f1thgvhi9058o23dbtp3p0555m32.apps.googleusercontent.com") - .build() - - val request: GetCredentialRequest = GetCredentialRequest.Builder() - .addCredentialOption(googleIdOption) - .build() - - fun signUpWithMifos() { - googleIdTokenCredential.signUpWithMifos(context, mifosSavingProductId) { - coroutineScope.launch { - credentialManager.clearCredentialState(ClearCredentialStateRequest()) - } - onDismissSignUp.invoke() - } - } - - fun handleSignIn(result: GetCredentialResponse) { - // Handle the successfully returned credential. - when (val credential = result.credential) { - is CustomCredential -> { - if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) { - try { - googleIdTokenCredential = - GoogleIdTokenCredential.createFrom(credential.data) - googleIdTokenCredential?.let { - signUpWithMifos() - } ?: { - Toast.makeText( - context, - Constants.GOOGLE_SIGN_IN_FAILED, - Toast.LENGTH_SHORT, - ).show() - } - } catch (e: GoogleIdTokenParsingException) { - Log.e(TAG, "Received an invalid google id token response", e) - } - } else { - // Catch any unrecognized custom credential type here. - Log.e(TAG, "Unexpected type of credential") - } - } - - else -> { - // Catch any unrecognized credential type here. - Log.e(TAG, "Unexpected type of credential") - } - } - } - - fun signUpCredentialManager() { - coroutineScope.launch { - try { - val result = credentialManager.getCredential( - request = request, - context = context, - ) - handleSignIn(result) - } catch (e: GetCredentialException) { - showFilterByAuthorizedAccounts = false - Log.e(TAG, e.message.toString()) - // handleFailure(e) - } - } - } - - fun signUp(checkedGoogleAccount: Boolean) { - if (checkedGoogleAccount) { - signUpCredentialManager() - } else { - signUpWithMifos() - } - showProgress = true - } - - MifosBottomSheet( - modifier = modifier, - content = { - SignupMethodContentScreen( - showProgress = showProgress, - onSignUpAsMerchant = { checkedGoogleAccount -> - mifosSavingProductId = MIFOS_MERCHANT_SAVINGS_PRODUCT_ID - signUp(checkedGoogleAccount) - }, - onSignupAsCustomer = { checkedGoogleAccount -> - mifosSavingProductId = MIFOS_CONSUMER_SAVINGS_PRODUCT_ID - signUp(checkedGoogleAccount) - }, - navigateToSignupScreen = navigateToSignupScreen, - ) - }, - onDismiss = { - onDismissSignUp.invoke() - }, - ) -} - -@Composable -@Suppress("LongMethod") -private fun SignupMethodContentScreen( - showProgress: Boolean, - onSignUpAsMerchant: (Boolean) -> Unit, - onSignupAsCustomer: (Boolean) -> Unit, - modifier: Modifier = Modifier, - navigateToSignupScreen: () -> Unit = {}, -) { - var checkedGoogleAccountState by remember { mutableStateOf(true) } - - Box( - modifier = modifier, - ) { - Column( - modifier = Modifier - .fillMaxSize() - .background(color = MaterialTheme.colorScheme.surface), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Text( - modifier = Modifier.padding(top = 16.dp), - text = stringResource(id = R.string.feature_auth_create_an_account), - ) - MifosOutlinedButton( - modifier = Modifier.padding(top = 48.dp), - onClick = { - if (checkedGoogleAccountState) { - onSignUpAsMerchant.invoke(checkedGoogleAccountState) - } else { - navigateToSignupScreen.invoke() - } - }, - border = BorderStroke(1.dp, Color.LightGray), - shape = RoundedCornerShape(4.dp), - colors = ButtonDefaults.outlinedButtonColors( - contentColor = MaterialTheme.colorScheme.primary, - ), - ) { - Text( - text = stringResource(id = R.string.feature_auth_sign_up_as_merchant).uppercase(), - style = MaterialTheme.typography.labelMedium, - ) - } - Row( - modifier = Modifier - .fillMaxWidth() - .padding(top = 24.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - HorizontalDivider( - modifier = Modifier - .padding(start = 24.dp, end = 8.dp) - .weight(.4f), - thickness = 1.dp, - ) - Text( - modifier = Modifier - .wrapContentWidth() - .weight(.1f), - text = stringResource(id = R.string.feature_auth_or), - ) - HorizontalDivider( - modifier = Modifier - .padding(start = 8.dp, end = 24.dp) - .weight(.4f), - thickness = 1.dp, - ) - } - MifosOutlinedButton( - modifier = Modifier.padding(top = 24.dp), - onClick = { - if (checkedGoogleAccountState) { - onSignupAsCustomer.invoke(checkedGoogleAccountState) - } else { - navigateToSignupScreen.invoke() - } - }, - border = BorderStroke(1.dp, Color.LightGray), - shape = RoundedCornerShape(4.dp), - colors = ButtonDefaults.outlinedButtonColors( - contentColor = MaterialTheme.colorScheme.primary, - ), - ) { - Text( - text = stringResource(id = R.string.feature_auth_sign_up_as_customer).uppercase(), - style = MaterialTheme.typography.labelMedium, - ) - } - Row( - modifier = Modifier - .padding(top = 24.dp, start = 16.dp, end = 16.dp) - .clickable { - checkedGoogleAccountState = !checkedGoogleAccountState - }, - verticalAlignment = Alignment.CenterVertically, - ) { - Checkbox( - checked = checkedGoogleAccountState, - onCheckedChange = { - checkedGoogleAccountState = !checkedGoogleAccountState - }, - colors = CheckboxDefaults.colors(MaterialTheme.colorScheme.primary), - ) - Text( - text = stringResource(id = R.string.feature_auth_ease_my_sign_up_using_google_account), - style = MaterialTheme.typography.labelSmall, - ) - } - HorizontalDivider(thickness = 48.dp, color = Color.Transparent) - } - if (showProgress) { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(top = 140.dp), - contentAlignment = Alignment.Center, - ) { - CircularProgressIndicator( - modifier = Modifier.size(64.dp), - color = Color.Black, - trackColor = MaterialTheme.colorScheme.surfaceVariant, - ) - } - } - } -} - -@Suppress("UnusedParameter") -private fun GoogleIdTokenCredential?.signUpWithMifos( - context: Context, - mifosSavingsProductId: Int, - signOutGoogleClient: () -> Unit, -) { - val googleIdTokenCredential = this - // Todo:navigate to MobileVerificationScreen with googleIdTokenCredential.givenName,profilePictureUri, - // familyName,mifosSavingsProductId,displayName,data.getString("com.google.android.libraries.identity.googleid.BUNDLE_KEY_ID") - signOutGoogleClient.invoke() -} - -@Preview -@Composable -private fun SignupMethodContentScreenPreview() { - MifosTheme { - SignupMethodContentScreen( - showProgress = true, - onSignUpAsMerchant = {}, - onSignupAsCustomer = {}, - ) - } -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/utils/ValidateUtil.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/utils/ValidateUtil.kt deleted file mode 100644 index 543bead45..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/utils/ValidateUtil.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.utils - -import android.util.Patterns - -object ValidateUtil { - fun String.isValidEmail() = this.isNotEmpty() && Patterns.EMAIL_ADDRESS.matcher(this).matches() -} diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt index 2fafcf592..ae6028573 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt @@ -11,7 +11,6 @@ package org.mifospay.feature.kyc import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import org.mifospay.core.model.entity.kyc.KYCLevel1Details import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -21,6 +20,7 @@ import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.kyc.FetchKYCLevel1Details import org.mifospay.core.data.repository.local.LocalRepository +import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.mifospay.feature.kyc.KYCDescriptionUiState.Loading class KYCDescriptionViewModel( @@ -74,7 +74,7 @@ class KYCDescriptionViewModel( } sealed interface KYCDescriptionUiState { - data class KYCDescription(val kycLevel1Details: org.mifospay.core.model.entity.kyc.KYCLevel1Details?) : KYCDescriptionUiState + data class KYCDescription(val kycLevel1Details: KYCLevel1Details?) : KYCDescriptionUiState data object Error : KYCDescriptionUiState data object Loading : KYCDescriptionUiState } diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt index e55a6d61b..aaa456791 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt @@ -10,13 +10,13 @@ package org.mifospay.feature.kyc import androidx.lifecycle.ViewModel -import org.mifospay.core.model.entity.kyc.KYCLevel1Details import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.kyc.UploadKYCLevel1Details import org.mifospay.core.data.repository.local.LocalRepository +import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.mifospay.feature.kyc.KYCLevel1UiState.Loading class KYCLevel1ViewModel( diff --git a/gradle.properties b/gradle.properties index 79d506e00..577ab461e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -47,6 +47,7 @@ kotlin.code.style=official android.defaults.buildfeatures.resvalues=false android.defaults.buildfeatures.shaders=false android.testOptions.unitTests.isIncludeAndroidResources = true +org.jetbrains.compose.experimental.jscanvas.enabled=true RblClientIdProp=a RblClientSecretProp=b diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fa9c118ff..d75f55986 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ androidxCoreSplashscreen = "1.0.1" androidxDataStore = "1.1.1" androidxLifecycle = "2.8.6" androidxMetrics = "1.0.0-beta01" -androidxNavigation = "2.8.1" +androidxNavigation = "2.8.2" androidxProfileinstaller = "1.4.0" androidxTracing = "1.3.0-alpha02" appcompatVersion = "1.7.0" @@ -24,9 +24,9 @@ cameraLifecycleVersion = "1.3.4" cameraViewVersion = "1.3.4" coil = "3.0.0-alpha10" compileSdk = "34" -compose-plugin = "1.6.11" +compose-plugin = "1.7.0-rc01" coreKtxVersion = "1.13.1" -credentialsVersion = "1.2.2" +credentialsVersion = "1.3.0" datastore = "1.1.1" dependencyGuard = "0.5.0" detekt = "1.23.7" @@ -46,15 +46,14 @@ koinAnnotationsVersion = "1.4.0-RC4" koinComposeMultiplatform = "1.2.0-Beta4" kotlin = "2.0.20" kotlinInject = "0.7.2" -kotlinStdlibVersion = "2.0.20" kotlinxCoroutines = "1.9.0" -kotlinxDatetime = "0.6.0" +kotlinxDatetime = "0.6.1" kotlinxImmutable = "0.3.8" kotlinxSerializationJson = "1.7.2" kotlinxSerializationJsonVersion = "1.3.0" -ksp = "2.0.20-1.0.24" +ksp = "2.0.20-1.0.25" ktlint = "12.1.1" -ktorVersion = "2.3.4" +ktorVersion = "3.0.0-rc-1" ktorfit = "2.1.0" ktorfitKsp = "2.1.0-1.0.25" libphonenumberAndroidVersion = "8.13.35" @@ -77,6 +76,7 @@ roborazzi = "1.26.0" room = "2.6.1" rxandroidVersion = "1.1.0" rxjavaVersion = "1.3.8" +sandwichVersion = "2.0.9" secrets = "2.0.1" sheets_compose_dialogs_core = "1.3.0" spotlessVersion = "6.25.0" @@ -87,29 +87,46 @@ uiDesktopVersion = "1.7.0" versionCatalogLinterVersion = "1.0.3" wire = "5.0.0" zxingVersion = "3.5.3" +lifecycle-viewmodel-compose = "2.8.2" +navigation-compose = "2.8.0-alpha02" +windowsSizeClass="0.5.0" + +composeJB = "1.7.0-rc01" +composeLifecycle = "2.8.2" +composeJetpackRuntime = "1.6.8" +composeNavigation = "2.8.0-alpha10" +jbCoreBundle = "1.0.1" +jbSavedState = "1.2.2" [libraries] accompanist-pager = { group = "com.google.accompanist", name = "accompanist-pager", version.ref = "accompanistPagerVersion" } + android-desugarJdkLibs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "androidDesugarJdkLibs" } android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" } android-tools-common = { group = "com.android.tools", name = "common", version.ref = "androidTools" } + androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidxActivity" } androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "activityVersion" } + androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompatVersion" } androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidxBrowser" } + androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "cameraLifecycleVersion" } androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "cameraViewVersion" } + androidx-compose-animation = { group = "androidx.compose.animation", name = "animation" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "androidxComposeBom" } androidx-compose-compiler = { group = "androidx.compose.compiler", name = "compiler", version.ref = "androidxComposeCompiler" } androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" } androidx-compose-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout" } + androidx-compose-material-iconsExtended = { group = "androidx.compose.material", name = "material-icons-extended" } androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } androidx-compose-material3-adaptive = { group = "androidx.compose.material3.adaptive", name = "adaptive", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-adaptive-layout = { group = "androidx.compose.material3.adaptive", name = "adaptive-layout", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-adaptive-navigation = { group = "androidx.compose.material3.adaptive", name = "adaptive-navigation", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-windowSizeClass = { group = "androidx.compose.material3", name = "material3-window-size-class" } + androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime" } androidx-compose-runtime-tracing = { group = "androidx.compose.runtime", name = "runtime-tracing", version.ref = "androidxComposeRuntimeTracing" } androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } @@ -118,35 +135,52 @@ androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui- androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-compose-ui-util = { group = "androidx.compose.ui", name = "ui-util" } + androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtxVersion" } + androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidxCoreSplashscreen" } + androidx-credentials = { group = "androidx.credentials", name = "credentials", version.ref = "credentialsVersion" } androidx-credentials-play-services-auth = { group = "androidx.credentials", name = "credentials-play-services-auth", version.ref = "credentialsVersion" } + androidx-dataStore-core = { group = "androidx.datastore", name = "datastore", version.ref = "androidxDataStore" } + androidx-lifecycle-extensions = { group = "androidx.lifecycle", name = "lifecycle-extensions", version.ref = "lifecycleExtensionsVersion" } androidx-lifecycle-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleVersion" } androidx-lifecycle-runtimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycle" } +androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidxLifecycle" } androidx-lifecycle-runtimeTesting = { group = "androidx.lifecycle", name = "lifecycle-runtime-testing", version.ref = "androidxLifecycle" } androidx-lifecycle-viewModelCompose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" } + androidx-metrics = { group = "androidx.metrics", name = "metrics-performance", version.ref = "androidxMetrics" } + androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "androidxNavigation" } androidx-navigation-testing = { group = "androidx.navigation", name = "navigation-testing", version.ref = "androidxNavigation" } + androidx-profileinstaller = { group = "androidx.profileinstaller", name = "profileinstaller", version.ref = "androidxProfileinstaller" } + androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" } androidx-tracing-ktx = { group = "androidx.tracing", name = "tracing-ktx", version.ref = "androidxTracing" } + androidx-ui-desktop = { group = "androidx.compose.ui", name = "ui-desktop", version.ref = "uiDesktopVersion" } + back-handler= {group="com.arkivanov.essenty", name="back-handler",version.ref="backHandlerVersion"} + coil-core = { group = "io.coil-kt.coil3", name = "coil-core", version.ref = "coil" } coil-kt = { group = "io.coil-kt.coil3", name = "coil", version.ref = "coil" } coil-kt-compose = { group = "io.coil-kt.coil3", name = "coil-compose-core", version.ref = "coil" } coil-network-ktor = { group = "io.coil-kt.coil3", name = "coil-network-ktor3", version.ref = "coil" } coil-svg = { group = "io.coil-kt.coil3", name = "coil-svg", version.ref = "coil" } + compose-gradlePlugin = { group = "org.jetbrains.kotlin", name = "compose-compiler-gradle-plugin", version.ref = "kotlin" } + datastore = { group = "androidx.datastore", name = "datastore-core-okio", version.ref = "datastore" } + detekt-formatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" } detekt-gradlePlugin = { group = "io.gitlab.arturbosch.detekt", name = "detekt-gradle-plugin", version.ref = "detekt" } -espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" } -fineract-sdk = { group = "com.github.openMF", name = "mifos-android-sdk-arch", version.ref = "fineractSdk" } +twitter-detekt-compose = { group = "com.twitter.compose.rules", name = "detekt", version.ref = "twitter-detekt-compose" } + + firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics-ktx" } firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" } firebase-cloud-messaging = { group = "com.google.firebase", name = "firebase-messaging-ktx" } @@ -154,14 +188,30 @@ firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashly firebase-crashlytics-gradlePlugin = { group = "com.google.firebase", name = "firebase-crashlytics-gradle", version.ref = "firebaseCrashlyticsPlugin" } firebase-performance = { group = "com.google.firebase", name = "firebase-perf-ktx" } firebase-performance-gradlePlugin = { group = "com.google.firebase", name = "perf-plugin", version.ref = "firebasePerfPlugin" } + google-oss-licenses = { group = "com.google.android.gms", name = "play-services-oss-licenses", version.ref = "googleOss" } google-oss-licenses-plugin = { group = "com.google.android.gms", name = "oss-licenses-plugin", version.ref = "googleOssPlugin" } google-play-services-code-scanner = { group = "com.google.android.gms", name = "play-services-code-scanner", version.ref = "playServicesCodeScanner" } googleid = { group = "com.google.android.libraries.identity.googleid", name = "googleid", version.ref = "googleidVersion" } -jetbrains-kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlinStdlibVersion" } + +# jb Compose +jb-kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" } +jb-kotlin-stdlib-js = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-js", version.ref = "kotlin" } +jb-kotlin-dom = { group = "org.jetbrains.kotlin", name = "kotlin-dom-api-compat", version.ref = "kotlin" } +jb-composeRuntime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "composeJB" } +jb-composeViewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "composeLifecycle" } +jb-lifecycleViewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "composeLifecycle" } +jb-lifecycleViewmodelSavedState = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate", version.ref = "composeLifecycle" } +jb-bundle = { module = "org.jetbrains.androidx.core:core-bundle", version.ref = "jbCoreBundle" } +jb-savedstate = { module = "org.jetbrains.androidx.savedstate:savedstate", version.ref = "jbSavedState" } +jb-composeNavigation = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "composeNavigation" } +jb-navigation = { module = "org.jetbrains.androidx.navigation:navigation-common", version.ref = "composeNavigation" } + junit = { group = "junit", name = "junit", version.ref = "junitVersion" } + kermit-logging = { group = "co.touchlab", name = "kermit", version.ref = "kermit" } kermit-simple = { group = "co.touchlab", name = "kermit-simple", version.ref = "kermit" } + koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } koin-androidx-compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } koin-androidx-navigation = { group = "io.insert-koin", name = "koin-androidx-navigation", version.ref = "koin" } @@ -169,33 +219,42 @@ koin-annotations = { group = "io.insert-koin", name = "koin-annotations", versio koin-bom = { group = "io.insert-koin", name = "koin-bom", version.ref = "koin" } koin-compose = { group = "io.insert-koin", name = "koin-compose", version.ref = "koinComposeMultiplatform" } koin-compose-viewmodel = { group = "io.insert-koin", name = "koin-compose-viewmodel", version.ref = "koinComposeMultiplatform" } +koin-compose-navigation = { group = "io.insert-koin", name = "koin-compose-viewmodel-navigation", version.ref = "koinComposeMultiplatform" } koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } koin-core-viewmodel = { group = "io.insert-koin", name = "koin-core-viewmodel", version.ref = "koin" } koin-ksp-compiler = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koinAnnotationsVersion" } koin-test = { group = "io.insert-koin", name = "koin-test", version.ref = "koin" } koin-test-junit4 = { group = "io.insert-koin", name = "koin-test-junit4", version.ref = "koin" } koin-test-junit5 = { group = "io.insert-koin", name = "koin-test-junit5", version.ref = "koin" } + kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } kotlin-inject-compiler-ksp = { group = "me.tatarka.inject", name = "kotlin-inject-compiler-ksp", version.ref = "kotlinInject" } kotlin-inject-runtime = { group = "me.tatarka.inject", name = "kotlin-inject-runtime", version.ref = "kotlinInject" } kotlin-inject-runtime-kmp = { group = "me.tatarka.inject", name = "kotlin-inject-runtime-kmp", version.ref = "kotlinInject" } kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" } +kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" } kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin" } + kotlinx-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinxImmutable" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } +kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinxCoroutines" } kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" } kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" } kotlinx-serialization-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-core", version.ref = "kotlinxSerializationJson" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } + ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } + ktlint-gradlePlugin = { group = "org.jlleitschuh.gradle", name = "ktlint-gradle", version.ref = "ktlint" } + ktor-client-android = { group = "io.ktor", name = "ktor-client-android", version.ref = "ktorVersion" } ktor-client-auth = { group = "io.ktor", name = "ktor-client-auth", version.ref = "ktorVersion" } ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktorVersion" } ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktorVersion" } ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktorVersion" } ktor-client-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktorVersion" } +ktor-client-okhttp = { group = "io.ktor", name = "ktor-client-okhttp", version.ref = "ktorVersion" } ktor-client-java = { group = "io.ktor", name = "ktor-client-java", version.ref = "ktorVersion" } ktor-client-js = { group = "io.ktor", name = "ktor-client-js", version.ref = "ktorVersion" } ktor-client-json = { group = "io.ktor", name = "ktor-client-json", version.ref = "ktorVersion" } @@ -204,41 +263,61 @@ ktor-client-serialization = { group = "io.ktor", name = "ktor-client-serializati ktor-client-websockets = { group = "io.ktor", name = "ktor-client-websockets", version.ref = "ktorVersion" } ktor-client-winhttp = { group = "io.ktor", name = "ktor-client-winhttp", version.ref = "ktorVersion" } ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktorVersion" } +ktor-server-auth = { group = "io.ktor", name = "ktor-server-auth", version.ref = "ktorVersion" } + ktorfit-converters-call = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-converters-call", version.ref = "ktorfit" } ktorfit-converters-flow = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-converters-flow", version.ref = "ktorfit" } ktorfit-ksp = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-ksp", version.ref = "ktorfitKsp" } -ktorfit-lib = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-lib", version.ref = "ktorfit" } +ktorfit-lib = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-lib-ktor-3.0.0-beta-2", version.ref = "ktorfit" } + libphonenumber-android = { group = "io.michaelrocks", name = "libphonenumber-android", version.ref = "libphonenumberAndroidVersion" } + lint-api = { group = "com.android.tools.lint", name = "lint-api", version.ref = "androidTools" } lint-checks = { group = "com.android.tools.lint", name = "lint-checks", version.ref = "androidTools" } lint-tests = { group = "com.android.tools.lint", name = "lint-tests", version.ref = "androidTools" } + logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logbackClassicVersion" } + multiplatform-settings = { group = "com.russhwolf", name = "multiplatform-settings-no-arg", version.ref = "multiplatformSettings" } multiplatform-settings-coroutines = { group = "com.russhwolf", name = "multiplatform-settings-coroutines", version.ref = "multiplatformSettings" } multiplatform-settings-serialization = { group = "com.russhwolf", name = "multiplatform-settings-serialization", version.ref = "multiplatformSettings" } multiplatform-settings-test = { group = "com.russhwolf", name = "multiplatform-settings-test", version.ref = "multiplatformSettings" } + moko-permission = {group="dev.icerock.moko", name="permissions", version.ref="mokoPermission"} moko-permission-compose = {group="dev.icerock.moko", name="permissions-compose", version.ref="mokoPermission"} + play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "playServicesAuthVersion" } + protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version.ref = "protobuf" } protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" } -reactivex-rxjava = { group = "io.reactivex", name = "rxjava", version.ref = "rxjavaVersion" } -reactivex-rxjava-android = { group = "io.reactivex", name = "rxandroid", version.ref = "rxandroidVersion" } -retrofit-kotlin-serialization = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofitKotlinxSerializationJson" } + room-gradlePlugin = { group = "androidx.room", name = "room-gradle-plugin", version.ref = "room" } + +sandwich = { module = "com.github.skydoves:sandwich", version.ref = "sandwichVersion" } +sandwich-ktorfit = { module = "com.github.skydoves:sandwich-ktorfit", version.ref = "sandwichVersion" } + squareup-okio = { group = "com.squareup.okio", name = "okio", version.ref = "okioVersion" } + sheets-compose-dialogs-calender = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "calendar", version.ref = "sheets_compose_dialogs_core" } sheets-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "core", version.ref = "sheets_compose_dialogs_core" } + spotless-gradle = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version.ref = "spotlessVersion" } + squareup-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okHttp3Version" } squareup-okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okHttp3Version" } squareup-retrofit-adapter-rxjava = { group = "com.squareup.retrofit2", name = "adapter-rxjava", version.ref = "retrofitVersion" } squareup-retrofit-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofitVersion" } squareup-retrofit2 = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofitVersion" } + truth = { group = "com.google.truth", name = "truth", version.ref = "truth" } -twitter-detekt-compose = { group = "com.twitter.compose.rules", name = "detekt", version.ref = "twitter-detekt-compose" } +espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" } + zxing = { group = "com.google.zxing", name = "core", version.ref = "zxingVersion" } + fineract-api = { group = "io.github.niyajali", name = "fineract-client-kmp", version.ref = "fineractSdk" } +fineract-sdk = { group = "com.github.openMF", name = "mifos-android-sdk-arch", version.ref = "fineractSdk" } + +window-size = {group="dev.chrisbanes.material3",name="material3-window-size-class-multiplatform",version.ref="windowsSizeClass"} [bundles] androidx-compose-ui-test = [ diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock new file mode 100644 index 000000000..4a3dfa000 --- /dev/null +++ b/kotlin-js-store/yarn.lock @@ -0,0 +1,2882 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@js-joda/core@3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@js-joda/core/-/core-3.2.0.tgz#3e61e21b7b2b8a6be746df1335cf91d70db2a273" + integrity sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg== + +"@leichtgewicht/ip-codec@^2.0.1": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1" + integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw== + +"@socket.io/component-emitter@~3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz#821f8442f4175d8f0467b9daf26e3a18e2d02af2" + integrity sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA== + +"@types/body-parser@*": + version "1.19.5" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bonjour@^3.5.9": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.13.tgz#adf90ce1a105e81dd1f9c61fdc5afda1bfb92956" + integrity sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ== + dependencies: + "@types/node" "*" + +"@types/connect-history-api-fallback@^1.3.5": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz#7de71645a103056b48ac3ce07b3520b819c1d5b3" + integrity sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + +"@types/cors@^2.8.12": + version "2.8.17" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" + integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.1.tgz#d5795ad732ce81715f27f75da913004a56751584" + integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.5": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz#91f06cda1049e8f17eeab364798ed79c97488a1c" + integrity sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express-serve-static-core@^4.17.33": + version "4.19.6" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz#e01324c2a024ff367d92c66f48553ced0ab50267" + integrity sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@*": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.0.tgz#13a7d1f75295e90d19ed6e74cab3678488eaa96c" + integrity sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^5.0.0" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/express@^4.17.13": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/http-errors@*": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== + +"@types/http-proxy@^1.17.8": + version "1.17.15" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36" + integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ== + dependencies: + "@types/node" "*" + +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + +"@types/node-forge@^1.3.0": + version "1.3.11" + resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da" + integrity sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ== + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@>=10.0.0": + version "22.7.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.4.tgz#e35d6f48dca3255ce44256ddc05dee1c23353fcc" + integrity sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg== + dependencies: + undici-types "~6.19.2" + +"@types/qs@*": + version "6.9.16" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" + integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== + +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/send@*": + version "0.17.4" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-index@^1.9.1": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.4.tgz#e6ae13d5053cb06ed36392110b4f9a49ac4ec898" + integrity sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug== + dependencies: + "@types/express" "*" + +"@types/serve-static@*", "@types/serve-static@^1.13.10": + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@types/send" "*" + +"@types/sockjs@^0.3.33": + version "0.3.36" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.36.tgz#ce322cf07bcc119d4cbf7f88954f3a3bd0f67535" + integrity sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q== + dependencies: + "@types/node" "*" + +"@types/ws@^8.5.5": + version "8.5.12" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.12.tgz#619475fe98f35ccca2a2f6c137702d85ec247b7e" + integrity sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ== + dependencies: + "@types/node" "*" + +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" + integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" + integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" + integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.12.1" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + +"@webassemblyjs/wasm-gen@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" + integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" + integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" + integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" + integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" + integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== + +"@webpack-cli/info@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" + integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== + +"@webpack-cli/serve@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" + integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abort-controller@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== + +acorn@^8.7.1, acorn@^8.8.2: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.9.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64id@2.0.0, base64id@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" + integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +body-parser@1.20.3, body-parser@^1.19.0: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.13.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +bonjour-service@^1.0.11: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.2.1.tgz#eb41b3085183df3321da1264719fbada12478d02" + integrity sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw== + dependencies: + fast-deep-equal "^3.1.3" + multicast-dns "^7.2.5" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browser-stdout@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserslist@^4.21.10: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== + dependencies: + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001663: + version "1.0.30001667" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" + integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^3.5.1, chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" + integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.10, colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +connect-history-api-fallback@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" + integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== + +connect@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +cookie@~0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cors@~2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +custom-event@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg== + +date-format@^4.0.14: + version "4.0.14" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" + integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.1.0, debug@^4.3.4, debug@^4.3.5, debug@~4.3.1, debug@~4.3.2, debug@~4.3.4: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +di@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA== + +diff@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + +dns-packet@^5.2.2: + version "5.6.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.1.tgz#ae888ad425a9d1478a0674256ab866de1012cf2f" + integrity sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + +dom-serialize@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ== + dependencies: + custom-event "~1.0.0" + ent "~2.2.0" + extend "^3.0.0" + void-elements "^2.0.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.5.28: + version "1.5.32" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz#4a05ee78e29e240aabaf73a67ce9fe73f52e1bc7" + integrity sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +engine.io-parser@~5.2.1: + version "5.2.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f" + integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q== + +engine.io@~6.6.0: + version "6.6.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.6.1.tgz#a82b1e5511239a0e95fac14516870ee9138febc8" + integrity sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og== + dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" + accepts "~1.3.4" + base64id "2.0.0" + cookie "~0.4.1" + cors "~2.8.5" + debug "~4.3.1" + engine.io-parser "~5.2.1" + ws "~8.17.1" + +enhanced-resolve@^5.17.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +ent@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.1.tgz#68dc99a002f115792c26239baedaaea9e70c0ca2" + integrity sha512-QHuXVeZx9d+tIQAz/XztU0ZwZf2Agg9CcXcgE1rurqvdBeDBrpSwjl8/6XUqMg7tw2Y7uAdKb2sRv+bSEFqQ5A== + dependencies: + punycode "^1.4.1" + +envinfo@^7.7.3: + version "7.14.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.14.0.tgz#26dac5db54418f2a4c1159153a0b2ae980838aae" + integrity sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg== + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-module-lexer@^1.2.1: + version "1.5.4" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" + integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== + +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +express@^4.17.3: + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.3" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.3.1" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.3" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.10" + proxy-addr "~2.0.7" + qs "6.13.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.19.0" + serve-static "1.16.2" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-uri@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.2.tgz#d78b298cf70fd3b752fd951175a3da6a7b48f024" + integrity sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== + dependencies: + debug "2.6.9" + encodeurl "~2.0.0" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.2.7: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +follow-redirects@^1.0.0: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + +format-util@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" + integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-monkey@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.6.tgz#8ead082953e88d992cf3ff844faa907b26756da2" + integrity sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.1.3, glob@^7.1.7: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +hasown@^2.0.0, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^2.3.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" + integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +http-proxy-middleware@^2.0.3: + version "2.0.7" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz#915f236d92ae98ef48278a95dedf17e991936ec6" + integrity sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA== + dependencies: + "@types/http-proxy" "^1.17.8" + http-proxy "^1.18.1" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.2" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + dependencies: + hasown "^2.0.2" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isbinaryfile@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" + integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +karma-chrome-launcher@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz#eb9c95024f2d6dfbb3748d3415ac9b381906b9a9" + integrity sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q== + dependencies: + which "^1.2.1" + +karma-mocha@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d" + integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ== + dependencies: + minimist "^1.2.3" + +karma-sourcemap-loader@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.4.0.tgz#b01d73f8f688f533bcc8f5d273d43458e13b5488" + integrity sha512-xCRL3/pmhAYF3I6qOrcn0uhbQevitc2DERMPH82FMnG+4WReoGcGFZb1pURf2a5apyrOHRdvD+O6K7NljqKHyA== + dependencies: + graceful-fs "^4.2.10" + +karma-webpack@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.1.tgz#4eafd31bbe684a747a6e8f3e4ad373e53979ced4" + integrity sha512-oo38O+P3W2mSPCSUrQdySSPv1LvPpXP+f+bBimNomS5sW+1V4SuhCuW8TfJzV+rDv921w2fDSDw0xJbPe6U+kQ== + dependencies: + glob "^7.1.3" + minimatch "^9.0.3" + webpack-merge "^4.1.5" + +karma@6.4.3: + version "6.4.3" + resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.3.tgz#763e500f99597218bbb536de1a14acc4ceea7ce8" + integrity sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q== + dependencies: + "@colors/colors" "1.5.0" + body-parser "^1.19.0" + braces "^3.0.2" + chokidar "^3.5.1" + connect "^3.7.0" + di "^0.0.1" + dom-serialize "^2.2.1" + glob "^7.1.7" + graceful-fs "^4.2.6" + http-proxy "^1.18.1" + isbinaryfile "^4.0.8" + lodash "^4.17.21" + log4js "^6.4.1" + mime "^2.5.2" + minimatch "^3.0.4" + mkdirp "^0.5.5" + qjobs "^1.2.0" + range-parser "^1.2.1" + rimraf "^3.0.2" + socket.io "^4.7.2" + source-map "^0.6.1" + tmp "^0.2.1" + ua-parser-js "^0.7.30" + yargs "^16.1.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +launch-editor@^2.6.0: + version "2.9.1" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.9.1.tgz#253f173bd441e342d4344b4dae58291abb425047" + integrity sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w== + dependencies: + picocolors "^1.0.0" + shell-quote "^1.8.1" + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash@^4.17.15, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log4js@^6.4.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.9.1.tgz#aba5a3ff4e7872ae34f8b4c533706753709e38b6" + integrity sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + flatted "^3.2.7" + rfdc "^1.3.0" + streamroller "^3.1.5" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memfs@^3.4.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6" + integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ== + dependencies: + fs-monkey "^1.0.4" + +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.2: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +"mime-db@>= 1.43.0 < 2": + version "1.53.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" + integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== + +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.5.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1, minimatch@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.3: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.3, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^0.5.5: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mocha@10.7.0: + version "10.7.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.7.0.tgz#9e5cbed8fa9b37537a25bd1f7fb4f6fc45458b9a" + integrity sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns@^7.2.5: + version "7.2.5" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" + integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== + dependencies: + dns-packet "^5.2.2" + thunky "^1.0.2" + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^8.0.9: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-retry@^4.5.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== + +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +qjobs@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" + integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== + +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== + dependencies: + side-channel "^1.0.6" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^2.0.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.20.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +rfdc@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" + integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== + +selfsigned@^2.1.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0" + integrity sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q== + dependencies: + "@types/node-forge" "^1.3.0" + node-forge "^1" + +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-javascript@^6.0.1, serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== + dependencies: + encodeurl "~2.0.0" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.19.0" + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +socket.io-adapter@~2.5.2: + version "2.5.5" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz#c7a1f9c703d7756844751b6ff9abfc1780664082" + integrity sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg== + dependencies: + debug "~4.3.4" + ws "~8.17.1" + +socket.io-parser@~4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83" + integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + +socket.io@^4.7.2: + version "4.8.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.8.0.tgz#33d05ae0915fad1670bd0c4efcc07ccfabebe3b1" + integrity sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA== + dependencies: + accepts "~1.3.4" + base64id "~2.0.0" + cors "~2.8.5" + debug "~4.3.2" + engine.io "~6.6.0" + socket.io-adapter "~2.5.2" + socket.io-parser "~4.2.4" + +sockjs@^0.3.24: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +source-map-js@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map-loader@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-5.0.0.tgz#f593a916e1cc54471cfc8851b905c8a845fc7e38" + integrity sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA== + dependencies: + iconv-lite "^0.6.3" + source-map-js "^1.0.2" + +source-map-support@0.5.21, source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.4.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +streamroller@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" + integrity sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + fs-extra "^8.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0, supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.3.10: + version "5.3.10" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.20" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.26.0" + +terser@^5.26.0: + version "5.34.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.34.1.tgz#af40386bdbe54af0d063e0670afd55c3105abeb6" + integrity sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +tmp@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@5.5.4: + version "5.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" + integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + +ua-parser-js@^0.7.30: + version "0.7.39" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.39.tgz#c71efb46ebeabc461c4612d22d54f88880fabe7e" + integrity sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== + +watchpack@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" + integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +webpack-cli@5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" + integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^2.1.1" + "@webpack-cli/info" "^2.0.2" + "@webpack-cli/serve" "^2.0.5" + colorette "^2.0.14" + commander "^10.0.1" + cross-spawn "^7.0.3" + envinfo "^7.7.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^3.1.1" + rechoir "^0.8.0" + webpack-merge "^5.7.3" + +webpack-dev-middleware@^5.3.4: + version "5.3.4" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517" + integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== + dependencies: + colorette "^2.0.10" + memfs "^3.4.3" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^4.0.0" + +webpack-dev-server@4.15.2: + version "4.15.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz#9e0c70a42a012560860adb186986da1248333173" + integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g== + dependencies: + "@types/bonjour" "^3.5.9" + "@types/connect-history-api-fallback" "^1.3.5" + "@types/express" "^4.17.13" + "@types/serve-index" "^1.9.1" + "@types/serve-static" "^1.13.10" + "@types/sockjs" "^0.3.33" + "@types/ws" "^8.5.5" + ansi-html-community "^0.0.8" + bonjour-service "^1.0.11" + chokidar "^3.5.3" + colorette "^2.0.10" + compression "^1.7.4" + connect-history-api-fallback "^2.0.0" + default-gateway "^6.0.3" + express "^4.17.3" + graceful-fs "^4.2.6" + html-entities "^2.3.2" + http-proxy-middleware "^2.0.3" + ipaddr.js "^2.0.1" + launch-editor "^2.6.0" + open "^8.0.9" + p-retry "^4.5.0" + rimraf "^3.0.2" + schema-utils "^4.0.0" + selfsigned "^2.1.1" + serve-index "^1.9.1" + sockjs "^0.3.24" + spdy "^4.0.2" + webpack-dev-middleware "^5.3.4" + ws "^8.13.0" + +webpack-merge@^4.1.5: + version "4.2.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" + integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== + dependencies: + lodash "^4.17.15" + +webpack-merge@^5.7.3: + version "5.10.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" + integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== + dependencies: + clone-deep "^4.0.1" + flat "^5.0.2" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@5.93.0: + version "5.93.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.93.0.tgz#2e89ec7035579bdfba9760d26c63ac5c3462a5e5" + integrity sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.5" + "@webassemblyjs/ast" "^1.12.1" + "@webassemblyjs/wasm-edit" "^1.12.1" + "@webassemblyjs/wasm-parser" "^1.12.1" + acorn "^8.7.1" + acorn-import-attributes "^1.9.5" + browserslist "^4.21.10" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.17.0" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.11" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.2.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.10" + watchpack "^2.4.1" + webpack-sources "^3.2.3" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + +ws@^8.13.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + +ws@~8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@^20.2.2, yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@^16.1.1, yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/mifospay-android/.gitignore b/mifospay-android/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/mifospay-android/.gitignore @@ -0,0 +1 @@ +/build diff --git a/mifospay/README.md b/mifospay-android/README.md similarity index 100% rename from mifospay/README.md rename to mifospay-android/README.md diff --git a/mifospay/build.gradle.kts b/mifospay-android/build.gradle.kts similarity index 76% rename from mifospay/build.gradle.kts rename to mifospay-android/build.gradle.kts index 5921928a6..cb965ffb9 100644 --- a/mifospay/build.gradle.kts +++ b/mifospay-android/build.gradle.kts @@ -87,36 +87,8 @@ android { } dependencies { + implementation(projects.mifospayShared) implementation(projects.core.data) - implementation(projects.core.ui) - implementation(projects.core.designsystem) - - implementation(projects.feature.receipt) - implementation(projects.feature.profile) - implementation(projects.feature.auth) - implementation(projects.feature.makeTransfer) - implementation(projects.feature.faq) - implementation(projects.feature.editpassword) - implementation(projects.feature.notification) - implementation(projects.feature.requestMoney) - implementation(projects.feature.upiSetup) - implementation(projects.feature.settings) - implementation(projects.feature.savedcards) - implementation(projects.feature.qr) - implementation(projects.feature.invoices) - implementation(projects.feature.merchants) - implementation(projects.feature.history) - implementation(projects.feature.kyc) - implementation(projects.feature.home) - implementation(projects.feature.accounts) - implementation(projects.feature.finance) - implementation(projects.feature.payments) - implementation(projects.feature.sendMoney) - implementation(projects.feature.standingInstruction) - implementation(projects.feature.search) - - implementation(projects.libs.mifosPasscode) - implementation(projects.libs.material3Navigation) // Compose implementation(libs.androidx.core.ktx) @@ -124,14 +96,12 @@ dependencies { implementation(libs.androidx.activity.compose) implementation(libs.androidx.activity.ktx) implementation(libs.androidx.core.splashscreen) - + implementation(libs.androidx.compose.material3) implementation(libs.androidx.compose.material3.adaptive) implementation(libs.androidx.compose.material3.adaptive.layout) implementation(libs.androidx.compose.material3.adaptive.navigation) - implementation(libs.androidx.compose.material3.windowSizeClass) implementation(libs.androidx.compose.runtime.tracing) - implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.android) @@ -144,10 +114,14 @@ dependencies { implementation(libs.androidx.profileinstaller) implementation(libs.androidx.tracing.ktx) + implementation(libs.koin.core) + implementation(libs.koin.android) + implementation(libs.koin.compose) + implementation(libs.koin.compose.viewmodel) + runtimeOnly(libs.androidx.compose.runtime) debugImplementation(libs.androidx.compose.ui.tooling) - testImplementation(libs.junit) testImplementation(libs.androidx.compose.ui.test) @@ -155,9 +129,6 @@ dependencies { androidTestImplementation(libs.espresso.core) androidTestImplementation(libs.androidx.test.ext.junit) - implementation(libs.koin.android) - implementation(libs.ktor.client.core) - testImplementation(kotlin("test")) testImplementation(libs.koin.test) testImplementation(libs.koin.test.junit4) diff --git a/mifospay-android/dependencies/prodReleaseRuntimeClasspath.tree.txt b/mifospay-android/dependencies/prodReleaseRuntimeClasspath.tree.txt new file mode 100644 index 000000000..bc79941e6 --- /dev/null +++ b/mifospay-android/dependencies/prodReleaseRuntimeClasspath.tree.txt @@ -0,0 +1,2022 @@ ++--- androidx.databinding:databinding-common:8.5.2 ++--- androidx.databinding:databinding-runtime:8.5.2 +| +--- androidx.collection:collection:1.0.0 -> 1.4.4 +| | \--- androidx.collection:collection-jvm:1.4.4 +| | +--- androidx.annotation:annotation:1.8.1 +| | | \--- androidx.annotation:annotation-jvm:1.8.1 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 +| | | +--- org.jetbrains:annotations:13.0 -> 23.0.0 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.0.20 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0 -> 2.0.20 (c) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:2.0.20 (c) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- androidx.collection:collection-ktx:1.4.4 (c) +| | \--- androidx.collection:collection-ktx:1.3.0 -> 1.4.4 (c) +| +--- androidx.databinding:databinding-common:8.5.2 +| +--- androidx.databinding:viewbinding:8.5.2 +| | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| \--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 +| \--- androidx.lifecycle:lifecycle-runtime-android:2.8.6 +| +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| +--- androidx.arch.core:core-common:2.2.0 +| | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| +--- androidx.arch.core:core-runtime:2.2.0 +| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | \--- androidx.arch.core:core-common:2.2.0 (*) +| +--- androidx.lifecycle:lifecycle-common:2.8.6 +| | \--- androidx.lifecycle:lifecycle-common-jvm:2.8.6 +| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 +| | | +--- org.jetbrains:annotations:23.0.0 +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.9.0 (c) +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.9.0 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 +| | +--- androidx.annotation:annotation:1.8.1 (*) +| | +--- androidx.concurrent:concurrent-futures:1.1.0 +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava +| | +--- androidx.startup:startup-runtime:1.1.1 +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | \--- androidx.tracing:tracing:1.0.0 -> 1.3.0-alpha02 +| | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | \--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (c) +| | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) ++--- androidx.databinding:databinding-adapters:8.5.2 +| +--- androidx.databinding:databinding-runtime:8.5.2 (*) +| \--- androidx.databinding:databinding-common:8.5.2 ++--- androidx.databinding:databinding-ktx:8.5.2 +| +--- androidx.databinding:databinding-runtime:8.5.2 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20 -> 2.0.20 +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1 -> 1.9.0 (*) +| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.6 +| | \--- androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.6 +| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata:2.6.1 -> 2.8.6 +| | +--- androidx.arch.core:core-common:2.2.0 (*) +| | +--- androidx.arch.core:core-runtime:2.2.0 (*) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 +| | | +--- androidx.arch.core:core-common:2.2.0 (*) +| | | +--- androidx.arch.core:core-runtime:2.2.0 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-process:2.6.1 -> 2.8.6 +| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) +| | +--- androidx.startup:startup-runtime:1.1.1 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-service:2.6.1 -> 2.8.6 +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| \--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 +| \--- androidx.lifecycle:lifecycle-viewmodel-android:2.8.6 +| +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) ++--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) ++--- androidx.compose:compose-bom:2024.09.02 +| +--- androidx.compose.material3:material3:1.3.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) +| +--- androidx.compose.runtime:runtime:1.7.2 (c) +| +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| +--- androidx.compose.runtime:runtime-saveable:1.7.2 (c) +| +--- androidx.compose.ui:ui:1.7.2 (c) +| +--- androidx.compose.material3.adaptive:adaptive-android:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 (c) +| +--- androidx.compose.animation:animation:1.7.2 (c) +| +--- androidx.compose.foundation:foundation-layout:1.7.2 (c) +| +--- androidx.compose.material3:material3-android:1.3.0 (c) +| +--- androidx.compose.runtime:runtime-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-tooling-preview-android:1.7.2 (c) +| +--- androidx.compose.foundation:foundation:1.7.2 (c) +| +--- androidx.compose.runtime:runtime-saveable-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| +--- androidx.compose.animation:animation-core:1.7.2 (c) +| +--- androidx.compose.ui:ui-util:1.7.2 (c) +| +--- androidx.compose.animation:animation-android:1.7.2 (c) +| +--- androidx.compose.foundation:foundation-layout-android:1.7.2 (c) +| +--- androidx.compose.material:material-icons-core:1.7.2 (c) +| +--- androidx.compose.material:material-ripple:1.7.2 (c) +| +--- androidx.compose.ui:ui-text:1.7.2 (c) +| +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| +--- androidx.compose.foundation:foundation-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| +--- androidx.compose.material:material-icons-extended:1.7.2 (c) +| +--- androidx.compose.material:material:1.7.2 (c) +| +--- androidx.compose.ui:ui-geometry-android:1.7.2 (c) +| +--- androidx.compose.animation:animation-core-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-util-android:1.7.2 (c) +| +--- androidx.compose.material:material-icons-core-android:1.7.2 (c) +| +--- androidx.compose.material:material-ripple-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-text-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-graphics-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-unit-android:1.7.2 (c) +| +--- androidx.compose.material:material-icons-extended-android:1.7.2 (c) +| \--- androidx.compose.material:material-android:1.7.2 (c) ++--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 +| \--- androidx.compose.ui:ui-tooling-preview-android:1.7.2 +| +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| +--- androidx.compose.runtime:runtime:1.7.2 +| | \--- androidx.compose.runtime:runtime-android:1.7.2 +| | +--- androidx.annotation:annotation-experimental:1.4.1 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) +| | +--- androidx.collection:collection:1.4.4 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | \--- androidx.compose.runtime:runtime-saveable:1.7.2 (c) +| +--- androidx.compose.ui:ui:1.7.2 (c) +| +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| +--- androidx.compose.ui:ui-text:1.7.2 (c) +| +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| \--- androidx.compose.ui:ui-util:1.7.2 (c) ++--- com.google.firebase:firebase-bom:33.3.0 +| +--- com.google.firebase:firebase-perf-ktx:21.0.1 (c) +| +--- com.google.firebase:firebase-crashlytics-ktx:19.1.0 (c) +| +--- com.google.firebase:firebase-analytics-ktx:22.1.0 (c) +| +--- com.google.firebase:firebase-messaging-ktx:24.0.1 (c) +| +--- com.google.firebase:firebase-perf:21.0.1 (c) +| +--- com.google.firebase:firebase-common:21.0.0 (c) +| +--- com.google.firebase:firebase-common-ktx:21.0.0 (c) +| +--- com.google.firebase:firebase-crashlytics:19.1.0 (c) +| +--- com.google.firebase:firebase-analytics:22.1.0 (c) +| +--- com.google.firebase:firebase-messaging:24.0.1 (c) +| +--- com.google.firebase:firebase-config:22.0.0 (c) +| +--- com.google.firebase:firebase-installations:18.0.0 (c) +| \--- com.google.firebase:firebase-encoders:17.0.0 (c) ++--- com.google.firebase:firebase-analytics-ktx -> 22.1.0 +| +--- com.google.firebase:firebase-analytics:22.1.0 +| | +--- com.google.android.gms:play-services-measurement:22.1.0 +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | +--- androidx.legacy:legacy-support-core-utils:1.0.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | +--- androidx.core:core:1.0.0 -> 1.13.1 +| | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) +| | | | | +--- androidx.interpolator:interpolator:1.0.0 +| | | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 -> 2.8.6 (*) +| | | | | +--- androidx.versionedparcelable:versionedparcelable:1.1.1 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | \--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | \--- androidx.core:core-ktx:1.13.1 (c) +| | | | +--- androidx.documentfile:documentfile:1.0.0 +| | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 +| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.8.6 (*) +| | | | | \--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | +--- androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 +| | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | \--- androidx.print:print:1.0.0 +| | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 +| | | | \--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 +| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.2.0 -> 1.13.1 (*) +| | | | \--- androidx.fragment:fragment:1.1.0 -> 1.8.2 +| | | | +--- androidx.activity:activity:1.8.1 -> 1.9.2 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- androidx.core:core:1.13.0 -> 1.13.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.6 +| | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 +| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.core:core:1.13.1 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | | \--- androidx.core:core:1.13.1 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) +| | | | | | +--- androidx.savedstate:savedstate:1.2.1 +| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) +| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.8.6 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) +| | | | | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | | | | \--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | +--- androidx.tracing:tracing:1.0.0 -> 1.3.0-alpha02 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- androidx.activity:activity-compose:1.9.2 (c) +| | | | | \--- androidx.activity:activity-ktx:1.9.2 (c) +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 (*) +| | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- androidx.viewpager:viewpager:1.0.0 +| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) +| | | | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | \--- androidx.fragment:fragment-ktx:1.8.2 (c) +| | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 +| | | | \--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | +--- com.google.android.gms:play-services-measurement-impl:22.1.0 +| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.9.0 -> 1.13.1 (*) +| | | | +--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 +| | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core-ktx:1.8.0 -> 1.13.1 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | | | \--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 (c) +| | | | +--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 +| | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | | +--- androidx.concurrent:concurrent-futures:1.1.0 (*) +| | | | | +--- androidx.core:core-ktx:1.8.0 -> 1.13.1 (*) +| | | | | +--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 (*) +| | | | | +--- com.google.guava:guava:31.1-android +| | | | | | +--- com.google.guava:failureaccess:1.0.1 +| | | | | | +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava +| | | | | | +--- com.google.code.findbugs:jsr305:3.0.2 +| | | | | | +--- org.checkerframework:checker-qual:3.12.0 +| | | | | | +--- com.google.errorprone:error_prone_annotations:2.11.0 -> 2.26.0 +| | | | | | \--- com.google.j2objc:j2objc-annotations:1.3 +| | | | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | | | \--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 (c) +| | | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 (*) +| | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) +| | | | +--- com.google.android.gms:play-services-stats:17.0.2 +| | | | | +--- androidx.legacy:legacy-support-core-utils:1.0.0 (*) +| | | | | \--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) +| | | | \--- com.google.guava:guava:31.1-android (*) +| | | \--- com.google.android.gms:play-services-stats:17.0.2 (*) +| | +--- com.google.android.gms:play-services-measurement-api:22.1.0 +| | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 (*) +| | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) +| | | +--- com.google.android.gms:play-services-measurement-sdk-api:22.1.0 +| | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | | \--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) +| | | +--- com.google.android.gms:play-services-tasks:18.2.0 +| | | | \--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | +--- com.google.firebase:firebase-common:21.0.0 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4 -> 1.9.0 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | | | | +--- com.google.android.gms:play-services-tasks:16.0.1 -> 18.2.0 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- com.google.firebase:firebase-components:18.0.0 +| | | | | +--- com.google.firebase:firebase-annotations:16.2.0 +| | | | | | \--- javax.inject:javax.inject:1 +| | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) +| | | | | \--- com.google.errorprone:error_prone_annotations:2.26.0 +| | | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) +| | | | +--- androidx.concurrent:concurrent-futures:1.1.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) +| | | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 +| | | | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| | | | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | | | \--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | | +--- com.google.firebase:firebase-installations:17.0.1 -> 18.0.0 +| | | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | | | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | | | +--- com.google.firebase:firebase-installations-interop:17.1.1 -> 17.2.0 +| | | | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | | | | \--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- com.google.firebase:firebase-installations-interop:17.0.0 -> 17.2.0 (*) +| | | +--- com.google.firebase:firebase-measurement-connector:19.0.0 -> 20.0.1 +| | | | +--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) +| | | | \--- com.google.firebase:firebase-annotations:16.0.0 -> 16.2.0 (*) +| | | +--- com.google.guava:guava:31.1-android (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) +| | \--- com.google.android.gms:play-services-measurement-sdk:22.1.0 +| | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | +--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) +| | \--- com.google.android.gms:play-services-measurement-impl:22.1.0 (*) +| +--- com.google.firebase:firebase-common:21.0.0 (*) +| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| +--- com.google.firebase:firebase-components:18.0.0 (*) +| \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) ++--- com.google.firebase:firebase-perf-ktx -> 21.0.1 +| +--- com.google.firebase:firebase-perf:21.0.1 +| | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) +| | +--- com.google.firebase:protolite-well-known-types:18.0.0 +| | | \--- com.google.protobuf:protobuf-javalite:3.14.0 -> 4.26.0 +| | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | +--- com.google.firebase:firebase-config:21.5.0 -> 22.0.0 +| | | +--- com.google.firebase:firebase-config-interop:16.0.1 +| | | | +--- com.google.firebase:firebase-encoders-json:18.0.1 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 -> 2.0.20 (*) +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | \--- com.google.firebase:firebase-encoders:17.0.0 +| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | \--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) +| | | +--- com.google.firebase:firebase-abt:21.1.1 +| | | | +--- com.google.firebase:firebase-measurement-connector:18.0.0 -> 20.0.1 (*) +| | | | \--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) +| | | +--- com.google.firebase:firebase-measurement-connector:18.0.0 -> 20.0.1 (*) +| | | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) +| | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) +| | +--- com.google.firebase:firebase-sessions:2.0.0 -> 2.0.4 +| | | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | | +--- com.google.firebase:firebase-installations-interop:17.2.0 (*) +| | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | | +--- com.google.firebase:firebase-encoders-json:18.0.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| | | +--- com.google.firebase:firebase-installations:18.0.0 (*) +| | | +--- com.google.firebase:firebase-datatransport:19.0.0 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- com.google.android.datatransport:transport-api:3.1.0 -> 3.2.0 +| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- com.google.android.datatransport:transport-backend-cct:3.2.0 -> 3.3.0 +| | | | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) +| | | | | +--- com.google.android.datatransport:transport-runtime:3.3.0 +| | | | | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) +| | | | | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| | | | | | +--- javax.inject:javax.inject:1 +| | | | | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | | | | | \--- com.google.firebase:firebase-encoders-proto:16.0.0 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | \--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | | | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | | | | +--- com.google.firebase:firebase-encoders-json:18.0.0 -> 18.0.1 (*) +| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- com.google.android.datatransport:transport-runtime:3.2.0 -> 3.3.0 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.datastore:datastore-preferences:1.0.0 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | +--- androidx.datastore:datastore:1.0.0 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.9.0 (*) +| | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | | \--- androidx.datastore:datastore-core:1.0.0 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.9.0 (*) +| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | \--- androidx.datastore:datastore-preferences-core:1.0.0 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | \--- androidx.datastore:datastore-core:1.0.0 (*) +| | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) +| | | \--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) +| | +--- com.google.firebase:firebase-datatransport:18.1.8 -> 19.0.0 (*) +| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | +--- androidx.lifecycle:lifecycle-process:2.3.1 -> 2.8.6 (*) +| | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | +--- com.google.protobuf:protobuf-javalite:3.21.11 -> 4.26.0 +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- androidx.appcompat:appcompat:1.2.0 -> 1.7.0 +| | | +--- androidx.activity:activity:1.7.0 -> 1.9.2 (*) +| | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| | | +--- androidx.appcompat:appcompat-resources:1.7.0 +| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.6.0 -> 1.13.1 (*) +| | | | +--- androidx.vectordrawable:vectordrawable:1.1.0 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.vectordrawable:vectordrawable-animated:1.1.0 +| | | | | +--- androidx.vectordrawable:vectordrawable:1.1.0 (*) +| | | | | +--- androidx.interpolator:interpolator:1.0.0 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | \--- androidx.appcompat:appcompat:1.7.0 (c) +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | +--- androidx.core:core:1.13.0 -> 1.13.1 (*) +| | | +--- androidx.core:core-ktx:1.13.0 -> 1.13.1 (*) +| | | +--- androidx.cursoradapter:cursoradapter:1.0.0 +| | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | +--- androidx.drawerlayout:drawerlayout:1.0.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) +| | | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 (*) +| | | +--- androidx.emoji2:emoji2:1.3.0 +| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-process:2.4.1 -> 2.8.6 (*) +| | | | +--- androidx.startup:startup-runtime:1.0.0 -> 1.1.1 (*) +| | | | \--- androidx.emoji2:emoji2-views-helper:1.3.0 (c) +| | | +--- androidx.emoji2:emoji2-views-helper:1.2.0 -> 1.3.0 +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) +| | | | +--- androidx.emoji2:emoji2:1.3.0 (*) +| | | | \--- androidx.emoji2:emoji2:1.3.0 (c) +| | | +--- androidx.fragment:fragment:1.5.4 -> 1.8.2 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | +--- androidx.resourceinspection:resourceinspection-annotation:1.0.1 +| | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | \--- androidx.appcompat:appcompat-resources:1.7.0 (c) +| | +--- com.google.android.datatransport:transport-api:3.0.0 -> 3.2.0 (*) +| | +--- com.google.dagger:dagger:2.27 +| | | \--- javax.inject:javax.inject:1 +| | \--- com.squareup.okhttp3:okhttp:3.12.1 -> 4.12.0 +| | +--- com.squareup.okio:okio:3.6.0 -> 3.9.1 +| | | \--- com.squareup.okio:okio-jvm:3.9.1 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.25 -> 2.0.20 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 2.0.20 (*) +| +--- com.google.firebase:firebase-common:21.0.0 (*) +| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| \--- com.google.firebase:firebase-components:18.0.0 (*) ++--- com.google.firebase:firebase-crashlytics-ktx -> 19.1.0 +| +--- com.google.firebase:firebase-crashlytics:19.1.0 +| | +--- com.google.firebase:firebase-sessions:2.0.4 (*) +| | +--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | +--- com.google.firebase:firebase-config-interop:16.0.1 (*) +| | +--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | +--- com.google.firebase:firebase-encoders-json:18.0.1 (*) +| | +--- com.google.firebase:firebase-installations:18.0.0 (*) +| | +--- com.google.firebase:firebase-installations-interop:17.2.0 (*) +| | +--- com.google.firebase:firebase-measurement-connector:20.0.1 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| | +--- com.google.android.datatransport:transport-api:3.2.0 (*) +| | +--- com.google.android.datatransport:transport-backend-cct:3.3.0 (*) +| | +--- com.google.android.datatransport:transport-runtime:3.3.0 (*) +| | \--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) +| +--- com.google.firebase:firebase-common:21.0.0 (*) +| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| \--- com.google.firebase:firebase-components:18.0.0 (*) ++--- com.google.firebase:firebase-messaging-ktx -> 24.0.1 +| +--- com.google.firebase:firebase-messaging:24.0.1 +| | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | +--- com.google.firebase:firebase-datatransport:18.2.0 -> 19.0.0 (*) +| | +--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | +--- com.google.firebase:firebase-encoders-json:18.0.0 -> 18.0.1 (*) +| | +--- com.google.firebase:firebase-encoders-proto:16.0.0 (*) +| | +--- com.google.firebase:firebase-iid-interop:17.1.0 +| | | +--- com.google.android.gms:play-services-basement:17.0.0 -> 18.4.0 (*) +| | | \--- com.google.android.gms:play-services-tasks:17.0.0 -> 18.2.0 (*) +| | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) +| | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) +| | +--- com.google.firebase:firebase-measurement-connector:19.0.0 -> 20.0.1 (*) +| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | +--- com.google.android.datatransport:transport-api:3.1.0 -> 3.2.0 (*) +| | +--- com.google.android.datatransport:transport-backend-cct:3.1.8 -> 3.3.0 (*) +| | +--- com.google.android.datatransport:transport-runtime:3.1.8 -> 3.3.0 (*) +| | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | +--- androidx.core:core:1.2.0 -> 1.13.1 (*) +| | | +--- androidx.fragment:fragment:1.0.0 -> 1.8.2 (*) +| | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) +| | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | +--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) +| | +--- com.google.android.gms:play-services-cloud-messaging:17.2.0 +| | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) +| | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | +--- com.google.android.gms:play-services-stats:17.0.2 (*) +| | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | +--- com.google.errorprone:error_prone_annotations:2.9.0 -> 2.26.0 +| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- com.google.firebase:firebase-common:21.0.0 (*) +| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| \--- com.google.firebase:firebase-components:18.0.0 (*) ++--- project :mifospay-shared +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 +| | \--- androidx.lifecycle:lifecycle-runtime-compose-android:2.8.6 +| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | +--- androidx.compose.runtime:runtime:1.7.1 -> 1.7.2 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 +| | \--- androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.6 +| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | +--- androidx.compose.runtime:runtime:1.6.0 -> 1.7.2 (*) +| | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 +| | | \--- androidx.compose.ui:ui-android:1.7.2 +| | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.9.2 +| | | | +--- androidx.activity:activity:1.9.2 (*) +| | | | +--- androidx.core:core-ktx:1.13.0 -> 1.13.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.6 +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) +| | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- androidx.activity:activity:1.9.2 (c) +| | | | \--- androidx.activity:activity-compose:1.9.2 (c) +| | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | +--- androidx.autofill:autofill:1.0.0 +| | | | \--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 +| | | | \--- androidx.compose.runtime:runtime-saveable-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | \--- androidx.compose.runtime:runtime:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-geometry:1.7.2 +| | | | \--- androidx.compose.ui:ui-geometry-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 +| | | | | \--- androidx.compose.ui:ui-util-android:1.7.2 +| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | | \--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-graphics:1.7.2 +| | | | \--- androidx.compose.ui:ui-graphics-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 +| | | | | \--- androidx.compose.ui:ui-unit-android:1.7.2 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | +--- androidx.collection:collection-ktx:1.2.0 -> 1.4.4 +| | | | | | +--- androidx.collection:collection:1.4.4 (*) +| | | | | | \--- androidx.collection:collection:1.4.4 (c) +| | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) +| | | | +--- androidx.graphics:graphics-path:1.0.1 +| | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-text:1.7.2 +| | | | \--- androidx.compose.ui:ui-text-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) +| | | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) +| | | +--- androidx.customview:customview-poolingcontainer:1.0.0 +| | | | +--- androidx.core:core-ktx:1.5.0 -> 1.13.1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) +| | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.3 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | \--- androidx.compose.foundation:foundation:1.7.2 (c) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 +| | +--- androidx.tracing:tracing:1.3.0-alpha02 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | \--- androidx.tracing:tracing:1.3.0-alpha02 (c) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-compose:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-compose-viewmodel:4.0.0-RC2 (c) +| | \--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (c) +| +--- io.insert-koin:koin-android:4.0.0-RC2 +| | +--- io.insert-koin:koin-core:4.0.0-RC2 +| | | \--- io.insert-koin:koin-core-jvm:4.0.0-RC2 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- co.touchlab:stately-concurrency:2.0.7 +| | | | \--- co.touchlab:stately-concurrency-jvm:2.0.7 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | | | \--- co.touchlab:stately-strict:2.0.7 +| | | | \--- co.touchlab:stately-strict-jvm:2.0.7 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | | \--- co.touchlab:stately-concurrent-collections:2.0.7 +| | | \--- co.touchlab:stately-concurrent-collections-jvm:2.0.7 +| | | +--- co.touchlab:stately-concurrency:2.0.7 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 +| | | \--- io.insert-koin:koin-core-viewmodel-jvm:4.0.0-RC2 +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.0 -> 2.8.3-rc01 +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.5 -> 2.8.6 (*) +| | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 +| | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 -> 2.8.2 +| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 -> 2.8.6 (*) +| | | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 +| | | | | \--- org.jetbrains.androidx.core:core-bundle-android:1.0.1 +| | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 +| | | | | +--- androidx.lifecycle:lifecycle-common:2.8.5 -> 2.8.6 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 +| | | | | +--- androidx.arch.core:core-common:2.2.0 (*) +| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0 -> 1.9.0 (*) +| | | +--- org.jetbrains.androidx.core:core-bundle:1.0.0 -> 1.0.1 (*) +| | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.0 -> 1.2.2 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- androidx.appcompat:appcompat:1.7.0 (*) +| | +--- androidx.activity:activity-ktx:1.9.1 -> 1.9.2 (*) +| | +--- androidx.fragment:fragment-ktx:1.8.2 +| | | +--- androidx.activity:activity-ktx:1.8.1 -> 1.9.2 (*) +| | | +--- androidx.collection:collection-ktx:1.1.0 -> 1.4.4 (*) +| | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) +| | | +--- androidx.fragment:fragment:1.8.2 (*) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | \--- androidx.fragment:fragment:1.8.2 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 -> 2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 -> 2.8.6 +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-compose:4.0.0-RC2 +| | | \--- io.insert-koin:koin-compose-jvm:4.0.0-RC2 +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 -> 1.7.0-rc01 +| | | | +--- androidx.compose.runtime:runtime:1.7.1 -> 1.7.2 (*) +| | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 +| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlinx:atomicfu:0.23.2 +| | | | | \--- org.jetbrains.kotlinx:atomicfu-jvm:0.23.2 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:{prefer 1.9.21} -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.9.24 -> 2.0.20 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:atomicfu:0.23.2 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.2 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 -> 2.8.6 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | +--- androidx.navigation:navigation-fragment-ktx:2.7.7 -> 2.8.2 +| | | +--- androidx.navigation:navigation-fragment:2.8.2 +| | | | +--- androidx.fragment:fragment-ktx:1.6.2 -> 1.8.2 (*) +| | | | +--- androidx.navigation:navigation-runtime:2.8.2 +| | | | | +--- androidx.activity:activity-ktx:1.7.1 -> 1.9.2 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.4.2 -> 1.4.4 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.6 (*) +| | | | | +--- androidx.navigation:navigation-common:2.8.2 +| | | | | | +--- androidx.annotation:annotation:1.8.1 (*) +| | | | | | +--- androidx.collection:collection-ktx:1.4.2 -> 1.4.4 (*) +| | | | | | +--- androidx.core:core-ktx:1.1.0 -> 1.13.1 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 +| | | | | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 (c) +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (c) +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 (c) +| | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (c) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (c) +| | | | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | | | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | | | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | | | +--- androidx.navigation:navigation-common:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | | +--- androidx.slidingpanelayout:slidingpanelayout:1.2.0 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.customview:customview:1.1.0 (*) +| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | | +--- androidx.window:window:1.0.0 -> 1.3.0 +| | | | | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| | | | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | | | +--- androidx.core:core:1.8.0 -> 1.13.1 (*) +| | | | | | +--- androidx.window.extensions.core:core:1.0.0 +| | | | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.20 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | | | | \--- androidx.window:window-core:1.3.0 (c) +| | | | | \--- androidx.transition:transition:1.4.1 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | | +--- androidx.navigation:navigation-common:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.2 +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 +| | | | | +--- androidx.navigation:navigation-common:2.8.2 (*) +| | | | | +--- androidx.navigation:navigation-common:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.2 (*) +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | | \--- androidx.navigation:navigation-common:2.8.2 (c) +| | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | \--- androidx.navigation:navigation-common:2.8.2 (c) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- project :core:data +| | +--- androidx.core:core-ktx:1.13.1 (*) +| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | +--- project :core:common +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (*) +| | | +--- io.coil-kt.coil3:coil:3.0.0-alpha10 +| | | | \--- io.coil-kt.coil3:coil-android:3.0.0-alpha10 +| | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 +| | | | | \--- io.coil-kt.coil3:coil-core-android:3.0.0-alpha10 +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 -> 2.8.6 (*) +| | | | | +--- androidx.annotation:annotation:1.8.1 (*) +| | | | | +--- androidx.appcompat:appcompat-resources:1.7.0 (*) +| | | | | +--- androidx.core:core-ktx:1.13.1 (*) +| | | | | +--- androidx.exifinterface:exifinterface:1.3.7 +| | | | | | \--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 -> 1.9.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | | | \--- com.squareup.okio:okio:3.9.0 -> 3.9.1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | +--- io.coil-kt.coil3:coil-svg:3.0.0-alpha10 +| | | | \--- io.coil-kt.coil3:coil-svg-android:3.0.0-alpha10 +| | | | +--- androidx.core:core-ktx:1.13.1 (*) +| | | | +--- com.caverock:androidsvg-aar:1.4 +| | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | +--- io.coil-kt.coil3:coil-network-ktor3:3.0.0-alpha10 +| | | | \--- io.coil-kt.coil3:coil-network-ktor3-android:3.0.0-alpha10 +| | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | | +--- io.coil-kt.coil3:coil-network-core:3.0.0-alpha10 +| | | | | \--- io.coil-kt.coil3:coil-network-core-android:3.0.0-alpha10 +| | | | | +--- androidx.core:core-ktx:1.13.1 (*) +| | | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-beta-2 -> 3.0.0-rc-1 +| | | | | \--- io.ktor:ktor-client-core-jvm:3.0.0-rc-1 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 +| | | | | | \--- io.ktor:ktor-http-jvm:3.0.0-rc-1 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-utils:3.0.0-rc-1 +| | | | | | | \--- io.ktor:ktor-utils-jvm:3.0.0-rc-1 +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | | +--- io.ktor:ktor-io:3.0.0-rc-1 +| | | | | | | | \--- io.ktor:ktor-io-jvm:3.0.0-rc-1 +| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-io-core:0.5.3 +| | | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.5.3 +| | | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-io-bytestring:0.5.3 +| | | | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.5.3 +| | | | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | +--- io.ktor:ktor-events:3.0.0-rc-1 +| | | | | | \--- io.ktor:ktor-events-jvm:3.0.0-rc-1 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | | +--- io.ktor:ktor-utils:3.0.0-rc-1 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | +--- io.ktor:ktor-websocket-serialization:3.0.0-rc-1 +| | | | | | \--- io.ktor:ktor-websocket-serialization-jvm:3.0.0-rc-1 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | | +--- io.ktor:ktor-serialization:3.0.0-rc-1 +| | | | | | | \--- io.ktor:ktor-serialization-jvm:3.0.0-rc-1 +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | | | +--- io.ktor:ktor-websockets:3.0.0-rc-1 +| | | | | | | | \--- io.ktor:ktor-websockets-jvm:3.0.0-rc-1 +| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | +--- io.ktor:ktor-sse:3.0.0-rc-1 +| | | | | | \--- io.ktor:ktor-sse-jvm:3.0.0-rc-1 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.8.1 -> 1.9.0 +| | | | | +--- org.slf4j:slf4j-api:1.7.32 -> 2.0.16 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | +--- co.touchlab:kermit:2.0.4 +| | | | \--- co.touchlab:kermit-android:2.0.4 +| | | | +--- co.touchlab:kermit-core:2.0.4 +| | | | | \--- co.touchlab:kermit-core-android:2.0.4 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| | | +--- com.squareup.okio:okio:3.9.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 +| | | | \--- io.insert-koin:koin-annotations-jvm:1.4.0-RC4 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | \--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.20 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- project :core:datastore +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- com.russhwolf:multiplatform-settings-no-arg:1.2.0 +| | | | \--- com.russhwolf:multiplatform-settings-no-arg-android:1.2.0 +| | | | +--- androidx.startup:startup-runtime:1.1.1 (*) +| | | | +--- com.russhwolf:multiplatform-settings:1.2.0 +| | | | | \--- com.russhwolf:multiplatform-settings-android:1.2.0 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | +--- com.russhwolf:multiplatform-settings-serialization:1.2.0 +| | | | \--- com.russhwolf:multiplatform-settings-serialization-android:1.2.0 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- com.russhwolf:multiplatform-settings:1.2.0 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | +--- com.russhwolf:multiplatform-settings-coroutines:1.2.0 +| | | | \--- com.russhwolf:multiplatform-settings-coroutines-android:1.2.0 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- com.russhwolf:multiplatform-settings:1.2.0 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | +--- project :core:model +| | | | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.1 +| | | | | \--- org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 +| | | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (c) +| | | | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) +| | | +--- project :core:common (*) +| | | \--- project :core:datastore-proto +| | | +--- com.google.protobuf:protobuf-kotlin-lite:4.26.0 +| | | | +--- com.google.protobuf:protobuf-javalite:4.26.0 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.0 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | +--- project :core:network +| | | +--- io.ktor:ktor-client-okhttp:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-okhttp-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | +--- com.squareup.okhttp3:okhttp:4.12.0 (*) +| | | | +--- com.squareup.okhttp3:okhttp-sse:4.12.0 +| | | | | +--- com.squareup.okhttp3:okhttp:4.12.0 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 2.0.20 (*) +| | | | +--- com.squareup.okio:okio:3.9.0 -> 3.9.1 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.1 (*) +| | | +--- project :core:common (*) +| | | +--- project :core:model (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- project :core:datastore (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (*) +| | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | +--- io.ktor:ktor-client-json:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-json-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.ktor:ktor-client-logging:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-logging-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.8.1 -> 1.9.0 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.ktor:ktor-client-serialization:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-serialization-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (*) +| | | | +--- io.ktor:ktor-client-json:3.0.0-rc-1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.ktor:ktor-client-content-negotiation:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-content-negotiation-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | +--- io.ktor:ktor-serialization:3.0.0-rc-1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.ktor:ktor-client-auth:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-auth-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.ktor:ktor-serialization-kotlinx-json:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-serialization-kotlinx-json-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | +--- io.ktor:ktor-serialization-kotlinx:3.0.0-rc-1 +| | | | | \--- io.ktor:ktor-serialization-kotlinx-jvm:3.0.0-rc-1 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | +--- io.ktor:ktor-serialization:3.0.0-rc-1 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- de.jensklingenberg.ktorfit:ktorfit-lib-ktor-3.0.0-beta-2:2.1.0 +| | | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-ktor-3.0.0-beta-2-android:2.1.0 +| | | | +--- io.ktor:ktor-client-cio-jvm:3.0.0-beta-2 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:2.0.13 -> 2.0.16 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | +--- io.ktor:ktor-client-core:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | +--- io.ktor:ktor-http-cio:3.0.0-beta-2 +| | | | | | \--- io.ktor:ktor-http-cio-jvm:3.0.0-beta-2 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.13 -> 2.0.16 +| | | | | | +--- io.ktor:ktor-network:3.0.0-beta-2 +| | | | | | | \--- io.ktor:ktor-network-jvm:3.0.0-beta-2 +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -> 2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 -> 2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | | | +--- org.slf4j:slf4j-api:2.0.13 -> 2.0.16 +| | | | | | | +--- io.ktor:ktor-utils:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | +--- io.ktor:ktor-websockets:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | +--- io.ktor:ktor-network-tls:3.0.0-beta-2 +| | | | | | \--- io.ktor:ktor-network-tls-jvm:3.0.0-beta-2 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.13 -> 2.0.16 +| | | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | | +--- io.ktor:ktor-network:3.0.0-beta-2 (*) +| | | | | | +--- io.ktor:ktor-utils:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- de.jensklingenberg.ktorfit:ktorfit-lib-light-ktor-3.0.0-beta-2:2.1.0 +| | | | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light-ktor-3.0.0-beta-2-android:2.1.0 +| | | | | +--- de.jensklingenberg.ktorfit:ktorfit-annotations:2.1.0 +| | | | | | \--- de.jensklingenberg.ktorfit:ktorfit-annotations-android:2.1.0 +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | +--- io.ktor:ktor-client-core:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | \--- com.squareup.okio:okio:3.9.1 (*) +| | +--- project :core:model (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | +--- project :core:analytics +| | | +--- com.google.firebase:firebase-bom:33.3.0 (*) +| | | +--- com.google.firebase:firebase-analytics-ktx -> 22.1.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | \--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) +| +--- org.jetbrains.compose.material3:material3:1.7.0-rc01 +| | +--- androidx.compose.material3:material3:1.3.0 +| | | \--- androidx.compose.material3:material3-android:1.3.0 +| | | +--- androidx.activity:activity-compose:1.8.2 -> 1.9.2 +| | | | +--- androidx.activity:activity-ktx:1.9.2 (*) +| | | | +--- androidx.compose.runtime:runtime:1.0.1 -> 1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime-saveable:1.0.1 -> 1.7.2 (*) +| | | | +--- androidx.compose.ui:ui:1.0.1 -> 1.7.2 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- androidx.activity:activity:1.9.2 (c) +| | | | \--- androidx.activity:activity-ktx:1.9.2 (c) +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | +--- androidx.compose.animation:animation-core:1.6.0 -> 1.7.2 +| | | | \--- androidx.compose.animation:animation-core-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | | \--- androidx.compose.animation:animation:1.7.2 (c) +| | | +--- androidx.compose.foundation:foundation:1.7.0 -> 1.7.2 +| | | | \--- androidx.compose.foundation:foundation-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.animation:animation:1.7.2 +| | | | | \--- androidx.compose.animation:animation-android:1.7.2 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | +--- androidx.compose.animation:animation-core:1.7.2 (*) +| | | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 +| | | | | | \--- androidx.compose.foundation:foundation-layout-android:1.7.2 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | | +--- androidx.compose.animation:animation-core:1.2.1 -> 1.7.2 (*) +| | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | \--- androidx.compose.foundation:foundation:1.7.2 (c) +| | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | \--- androidx.compose.animation:animation-core:1.7.2 (c) +| | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-text:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | +--- androidx.core:core:1.13.1 (*) +| | | | +--- androidx.emoji2:emoji2:1.3.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | \--- androidx.compose.foundation:foundation-layout:1.7.2 (c) +| | | +--- androidx.compose.foundation:foundation-layout:1.7.0 -> 1.7.2 (*) +| | | +--- androidx.compose.material:material-icons-core:1.6.0 -> 1.7.2 +| | | | \--- androidx.compose.material:material-icons-core-android:1.7.2 +| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.compose.material:material-ripple:1.7.0 -> 1.7.2 +| | | | \--- androidx.compose.material:material-ripple-android:1.7.2 +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.animation:animation:1.7.2 (*) +| | | | +--- androidx.compose.foundation:foundation:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.compose.runtime:runtime:1.7.0 -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui-text:1.6.0 -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.2 (*) +| | | \--- androidx.lifecycle:lifecycle-common-java8:2.6.1 -> 2.8.6 (*) +| | +--- org.jetbrains.compose.animation:animation-core:1.7.0-rc01 +| | | +--- androidx.compose.animation:animation-core:1.7.1 -> 1.7.2 (*) +| | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 +| | | | +--- androidx.compose.ui:ui:1.7.1 -> 1.7.2 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.3-rc01 +| | | | | +--- androidx.arch.core:core-common:2.2.0 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.5 -> 2.8.6 (*) +| | | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.3-rc01 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.3-rc01 +| | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.5 -> 2.8.6 (*) +| | | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.3-rc01 (*) +| | | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.3-rc01 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 -> 1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.3-rc01 (*) +| | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.runtime:runtime-saveable:1.7.0-rc01 +| | | | | +--- androidx.compose.runtime:runtime-saveable:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 +| | | | | +--- androidx.compose.ui:ui-geometry:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 +| | | | | \--- androidx.compose.ui:ui-util:1.7.1 -> 1.7.2 (*) +| | | | +--- org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 +| | | | | +--- androidx.compose.ui:ui-graphics:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 +| | | | | | +--- androidx.compose.ui:ui-unit:1.7.1 -> 1.7.2 (*) +| | | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | | +--- org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 (*) +| | | | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui-text:1.7.0-rc01 +| | | | | +--- androidx.compose.ui:ui-text:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime-saveable:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.kotlinx:atomicfu:0.23.2 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | +--- org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:atomicfu:0.23.2 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | +--- org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 +| | | +--- androidx.compose.foundation:foundation:1.7.1 -> 1.7.2 (*) +| | | +--- org.jetbrains.compose.animation:animation:1.7.0-rc01 +| | | | +--- androidx.compose.animation:animation:1.7.1 -> 1.7.2 (*) +| | | | +--- org.jetbrains.compose.animation:animation-core:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.foundation:foundation-layout:1.7.0-rc01 +| | | | | +--- androidx.compose.foundation:foundation-layout:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 (*) +| | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.foundation:foundation-layout:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui-text:1.7.0-rc01 (*) +| | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.foundation:foundation-layout:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.material:material-icons-core:1.7.0-rc01 +| | | +--- androidx.compose.material:material-icons-core:1.7.1 -> 1.7.2 (*) +| | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 (*) +| | | \--- org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.material:material-ripple:1.7.0-rc01 +| | | +--- androidx.compose.material:material-ripple:1.7.1 -> 1.7.2 (*) +| | | +--- org.jetbrains.compose.animation:animation:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.ui:ui-text:1.7.0-rc01 (*) +| | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| +--- org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 +| | \--- org.jetbrains.compose.components:components-ui-tooling-preview-android:1.7.0-rc01 +| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| +--- org.jetbrains.compose.components:components-resources:1.7.0-rc01 +| | \--- org.jetbrains.compose.components:components-resources-android:1.7.0-rc01 +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| +--- dev.chrisbanes.material3:material3-window-size-class-multiplatform:0.5.0 +| | \--- dev.chrisbanes.material3:material3-window-size-class-multiplatform-android:0.5.0 +| | +--- androidx.window:window:1.2.0 -> 1.3.0 (*) +| | +--- org.jetbrains.compose.ui:ui:1.6.0 -> 1.7.0-rc01 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-compose:1.2.0-Beta4 -> 4.0.0-RC2 (*) +| +--- io.insert-koin:koin-compose-viewmodel:1.2.0-Beta4 -> 4.0.0-RC2 +| | \--- io.insert-koin:koin-compose-viewmodel-jvm:4.0.0-RC2 +| | +--- io.insert-koin:koin-compose:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0 -> 2.8.2 +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 -> 2.8.6 (*) +| | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime-saveable:1.6.11 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui:1.6.11 -> 1.7.0-rc01 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- project :feature:auth +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| | +--- project :libs:country-code-picker +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) +| | | +--- androidx.compose:compose-bom:2024.09.02 (*) +| | | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| | | +--- androidx.compose.foundation:foundation -> 1.7.2 (*) +| | | +--- androidx.compose.foundation:foundation-layout -> 1.7.2 (*) +| | | +--- androidx.compose.material:material-icons-extended -> 1.7.2 +| | | | \--- androidx.compose.material:material-icons-extended-android:1.7.2 +| | | | \--- androidx.compose.material:material-icons-core:1.7.2 (*) +| | | +--- androidx.compose.material3:material3 -> 1.3.0 (*) +| | | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui-util -> 1.7.2 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 +| | | | \--- org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.8 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) +| | | \--- io.michaelrocks:libphonenumber-android:8.13.35 +| | +--- androidx.credentials:credentials:1.3.0 +| | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | \--- androidx.credentials:credentials-play-services-auth:1.3.0 (c) +| | +--- androidx.credentials:credentials-play-services-auth:1.3.0 +| | | +--- androidx.credentials:credentials:1.3.0 (*) +| | | +--- com.google.android.gms:play-services-auth:21.1.1 -> 21.2.0 +| | | | +--- androidx.fragment:fragment:1.5.7 -> 1.8.2 (*) +| | | | +--- androidx.loader:loader:1.1.0 (*) +| | | | +--- com.google.android.gms:play-services-auth-api-phone:18.0.2 +| | | | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) +| | | | | +--- com.google.android.gms:play-services-basement:18.0.2 -> 18.4.0 (*) +| | | | | \--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | | | +--- com.google.android.gms:play-services-auth-base:18.0.10 +| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) +| | | | | +--- com.google.android.gms:play-services-basement:18.2.0 -> 18.4.0 (*) +| | | | | \--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | | | +--- com.google.android.gms:play-services-base:18.3.0 (*) +| | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) +| | | | +--- com.google.android.gms:play-services-fido:20.0.1 -> 21.0.0 +| | | | | +--- com.google.android.gms:play-services-base:18.3.0 (*) +| | | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) +| | | | | +--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | | +--- com.google.android.gms:play-services-fido:21.0.0 (*) +| | | +--- com.google.android.libraries.identity.googleid:googleid:1.1.0 -> 1.1.1 +| | | | +--- androidx.credentials:credentials:1.3.0-beta01 -> 1.3.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.0 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | \--- androidx.credentials:credentials:1.3.0 (c) +| | +--- com.google.android.libraries.identity.googleid:googleid:1.1.1 (*) +| | +--- com.google.android.gms:play-services-auth:21.2.0 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | +--- project :core:ui +| | | +--- androidx.metrics:metrics-performance:1.0.0-beta01 +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.5.0 -> 1.13.1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.browser:browser:1.8.0 +| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) +| | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | +--- androidx.interpolator:interpolator:1.0.0 (*) +| | | | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava +| | | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| | | +--- com.google.accompanist:accompanist-pager:0.34.0 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.9.0 (*) +| | | | +--- androidx.compose.foundation:foundation:1.6.0 -> 1.7.2 (*) +| | | | +--- dev.chrisbanes.snapper:snapper:0.2.2 +| | | | | +--- androidx.compose.foundation:foundation:1.1.1 -> 1.7.2 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.10 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| | | +--- project :core:analytics (*) +| | | +--- project :core:designsystem +| | | | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| | | | +--- androidx.activity:activity-compose:1.9.2 (*) +| | | | +--- project :core:model (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | | +--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 +| | | | | \--- io.coil-kt.coil3:coil-compose-core-android:3.0.0-alpha10 +| | | | | +--- com.google.accompanist:accompanist-drawablepainter:0.34.0 +| | | | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.9.0 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| | | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | | | +--- org.jetbrains.compose.foundation:foundation:1.6.11 -> 1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.material:material:1.7.0-rc01 +| | | | | +--- androidx.compose.material:material:1.7.1 -> 1.7.2 +| | | | | | \--- androidx.compose.material:material-android:1.7.2 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | | +--- androidx.compose.animation:animation:1.7.2 (*) +| | | | | | +--- androidx.compose.animation:animation-core:1.7.2 (*) +| | | | | | +--- androidx.compose.foundation:foundation:1.7.2 (*) +| | | | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) +| | | | | | +--- androidx.compose.material:material-ripple:1.7.2 (*) +| | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.compose.animation:animation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.animation:animation-core:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.foundation:foundation-layout:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.material:material-icons-core:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.material:material-ripple:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-text:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.material3:material3:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.material:material-icons-extended:1.7.0-rc01 +| | | | | +--- androidx.compose.material:material-icons-extended:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.material:material-icons-core:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.components:components-resources:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 (*) +| | | | \--- com.arkivanov.essenty:back-handler:2.1.0 +| | | | \--- com.arkivanov.essenty:back-handler-android:2.1.0 +| | | | +--- androidx.activity:activity-ktx:1.8.1 -> 1.9.2 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | \--- com.arkivanov.essenty:utils-internal:2.1.0 +| | | | \--- com.arkivanov.essenty:utils-internal-android:2.1.0 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | +--- project :core:model (*) +| | | +--- project :core:common (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | | +--- io.coil-kt.coil3:coil:3.0.0-alpha10 (*) +| | | +--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) +| | | +--- org.jetbrains.compose.material3:material3:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.components:components-resources:1.7.0-rc01 (*) +| | | \--- org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 (*) +| | +--- project :core:designsystem (*) +| | +--- project :core:data (*) +| | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2 (*) +| | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | +--- org.jetbrains.androidx.navigation:navigation-compose:2.8.0-alpha10 +| | | +--- androidx.activity:activity-compose:1.8.0 -> 1.9.2 (*) +| | | +--- androidx.navigation:navigation-compose:2.8.0-rc01 -> 2.8.2 +| | | | +--- androidx.activity:activity-compose:1.8.0 -> 1.9.2 (*) +| | | | +--- androidx.compose.animation:animation:1.7.2 (*) +| | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2 -> 2.8.6 (*) +| | | | +--- androidx.navigation:navigation-runtime-ktx:2.8.2 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | | +--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | | \--- androidx.navigation:navigation-common:2.8.2 (c) +| | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | | +--- org.jetbrains.androidx.navigation:navigation-common:2.8.0-alpha10 +| | | | +--- androidx.core:core-ktx:1.1.0 -> 1.13.1 (*) +| | | | +--- androidx.navigation:navigation-common:2.8.0-rc01 -> 2.8.2 (*) +| | | | +--- androidx.profileinstaller:profileinstaller:1.3.0 -> 1.4.0 (*) +| | | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.2 -> 1.7.2 (*) +| | | +--- org.jetbrains.androidx.navigation:navigation-runtime:2.8.0-alpha10 +| | | | +--- androidx.activity:activity-ktx:1.7.1 -> 1.9.2 (*) +| | | | +--- androidx.navigation:navigation-runtime:2.8.0-rc01 -> 2.8.2 (*) +| | | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | | | +--- org.jetbrains.androidx.navigation:navigation-common:2.8.0-alpha10 (*) +| | | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.2 -> 1.7.2 (*) +| | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| | | +--- org.jetbrains.compose.animation:animation:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.animation:animation-core:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.foundation:foundation-layout:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime-saveable:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.2 -> 1.7.2 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| | +--- project :core:domain +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- project :core:common (*) +| | | +--- project :core:data (*) +| | | \--- project :core:model (*) +| | +--- org.jetbrains.compose.material3:material3:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.components:components-resources:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 (*) +| | +--- io.insert-koin:koin-compose-viewmodel:1.2.0-Beta4 -> 4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-compose:1.2.0-Beta4 -> 4.0.0-RC2 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- org.jetbrains.kotlin:kotlin-reflect:2.0.20 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| +--- project :core:ui (*) +| +--- project :core:designsystem (*) +| +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2 (*) +| +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| +--- org.jetbrains.androidx.navigation:navigation-compose:2.8.0-alpha10 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- project :core:domain (*) +| \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) ++--- project :core:data (*) ++--- androidx.core:core-ktx:1.13.1 (*) ++--- androidx.appcompat:appcompat:1.7.0 (*) ++--- androidx.activity:activity-compose:1.9.2 (*) ++--- androidx.activity:activity-ktx:1.9.2 (*) ++--- androidx.core:core-splashscreen:1.0.1 +| +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) ++--- androidx.compose.material3:material3 -> 1.3.0 (*) ++--- androidx.compose.material3.adaptive:adaptive:1.0.0 +| \--- androidx.compose.material3.adaptive:adaptive-android:1.0.0 +| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.2 (*) +| +--- androidx.window:window:1.3.0 (*) +| +--- androidx.window:window-core:1.3.0 +| | \--- androidx.window:window-core-android:1.3.0 +| | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | \--- androidx.window:window:1.3.0 (c) +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) +| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) +| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) ++--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 +| \--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 +| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| +--- androidx.compose.animation:animation:1.7.0 -> 1.7.2 (*) +| +--- androidx.compose.animation:animation-core:1.7.0 -> 1.7.2 (*) +| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.foundation:foundation-layout:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (*) +| +--- androidx.compose.ui:ui:1.7.0 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.2 (*) +| +--- androidx.window:window-core:1.3.0 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) +| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) ++--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 +| \--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 +| +--- androidx.activity:activity-compose:1.8.2 -> 1.9.2 (*) +| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (*) +| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.2 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) +| \--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) ++--- androidx.compose.runtime:runtime-tracing:1.0.0-beta01 +| +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| +--- androidx.compose.runtime:runtime:1.3.3 -> 1.7.2 (*) +| +--- androidx.startup:startup-runtime:1.1.1 (*) +| +--- androidx.tracing:tracing-perfetto:1.0.0 +| | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| | +--- androidx.startup:startup-runtime:1.1.1 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) ++--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) ++--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (*) ++--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) ++--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) ++--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (*) ++--- androidx.lifecycle:lifecycle-extensions:2.2.0 +| +--- androidx.lifecycle:lifecycle-runtime:2.2.0 -> 2.8.6 (*) +| +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) +| +--- androidx.arch.core:core-runtime:2.1.0 -> 2.2.0 (*) +| +--- androidx.fragment:fragment:1.2.0 -> 1.8.2 (*) +| +--- androidx.lifecycle:lifecycle-common:2.2.0 -> 2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-livedata:2.2.0 -> 2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-process:2.2.0 -> 2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-service:2.2.0 -> 2.8.6 (*) +| \--- androidx.lifecycle:lifecycle-viewmodel:2.2.0 -> 2.8.6 (*) ++--- androidx.navigation:navigation-compose:2.8.2 (*) ++--- androidx.profileinstaller:profileinstaller:1.4.0 (*) ++--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) ++--- io.insert-koin:koin-core:4.0.0-RC2 (*) ++--- io.insert-koin:koin-android:4.0.0-RC2 (*) ++--- io.insert-koin:koin-compose:1.2.0-Beta4 -> 4.0.0-RC2 (*) ++--- io.insert-koin:koin-compose-viewmodel:1.2.0-Beta4 -> 4.0.0-RC2 (*) +\--- androidx.compose.runtime:runtime -> 1.7.2 (*) diff --git a/mifospay/dependencies/prodReleaseRuntimeClasspath.txt b/mifospay-android/dependencies/prodReleaseRuntimeClasspath.txt similarity index 69% rename from mifospay/dependencies/prodReleaseRuntimeClasspath.txt rename to mifospay-android/dependencies/prodReleaseRuntimeClasspath.txt index d808c3e69..005b3158c 100644 --- a/mifospay/dependencies/prodReleaseRuntimeClasspath.txt +++ b/mifospay-android/dependencies/prodReleaseRuntimeClasspath.txt @@ -4,36 +4,13 @@ :core:datastore :core:datastore-proto :core:designsystem +:core:domain :core:model :core:network :core:ui -:feature:accounts :feature:auth -:feature:editpassword -:feature:faq -:feature:finance -:feature:history -:feature:home -:feature:invoices -:feature:kyc -:feature:make-transfer -:feature:merchants -:feature:notification -:feature:payments -:feature:profile -:feature:qr -:feature:receipt -:feature:request-money -:feature:savedcards -:feature:search -:feature:send-money -:feature:settings -:feature:standing-instruction -:feature:upi-setup :libs:country-code-picker -:libs:material3-navigation -:libs:mifos-passcode -:libs:pullrefresh +:mifospay-shared androidx.activity:activity-compose:1.9.2 androidx.activity:activity-ktx:1.9.2 androidx.activity:activity:1.9.2 @@ -46,18 +23,12 @@ androidx.arch.core:core-common:2.2.0 androidx.arch.core:core-runtime:2.2.0 androidx.autofill:autofill:1.0.0 androidx.browser:browser:1.8.0 -androidx.camera:camera-core:1.3.4 -androidx.camera:camera-lifecycle:1.3.4 -androidx.camera:camera-video:1.3.4 -androidx.camera:camera-view:1.3.4 androidx.collection:collection-jvm:1.4.4 androidx.collection:collection-ktx:1.4.4 androidx.collection:collection:1.4.4 androidx.compose.animation:animation-android:1.7.2 androidx.compose.animation:animation-core-android:1.7.2 androidx.compose.animation:animation-core:1.7.2 -androidx.compose.animation:animation-graphics-android:1.7.2 -androidx.compose.animation:animation-graphics:1.7.2 androidx.compose.animation:animation:1.7.2 androidx.compose.foundation:foundation-android:1.7.2 androidx.compose.foundation:foundation-layout-android:1.7.2 @@ -70,8 +41,6 @@ androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 androidx.compose.material3.adaptive:adaptive:1.0.0 androidx.compose.material3:material3-android:1.3.0 -androidx.compose.material3:material3-window-size-class-android:1.3.0 -androidx.compose.material3:material3-window-size-class:1.3.0 androidx.compose.material3:material3:1.3.0 androidx.compose.material:material-android:1.7.2 androidx.compose.material:material-icons-core-android:1.7.2 @@ -105,8 +74,8 @@ androidx.concurrent:concurrent-futures:1.1.0 androidx.core:core-ktx:1.13.1 androidx.core:core-splashscreen:1.0.1 androidx.core:core:1.13.1 -androidx.credentials:credentials-play-services-auth:1.3.0-beta01 -androidx.credentials:credentials:1.3.0-beta01 +androidx.credentials:credentials-play-services-auth:1.3.0 +androidx.credentials:credentials:1.3.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.1.0 @@ -153,13 +122,13 @@ androidx.lifecycle:lifecycle-viewmodel:2.8.6 androidx.loader:loader:1.1.0 androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 androidx.metrics:metrics-performance:1.0.0-beta01 -androidx.navigation:navigation-common-ktx:2.8.1 -androidx.navigation:navigation-common:2.8.1 -androidx.navigation:navigation-compose:2.8.1 -androidx.navigation:navigation-fragment-ktx:2.8.1 -androidx.navigation:navigation-fragment:2.8.1 -androidx.navigation:navigation-runtime-ktx:2.8.1 -androidx.navigation:navigation-runtime:2.8.1 +androidx.navigation:navigation-common-ktx:2.8.2 +androidx.navigation:navigation-common:2.8.2 +androidx.navigation:navigation-compose:2.8.2 +androidx.navigation:navigation-fragment-ktx:2.8.2 +androidx.navigation:navigation-fragment:2.8.2 +androidx.navigation:navigation-runtime-ktx:2.8.2 +androidx.navigation:navigation-runtime:2.8.2 androidx.print:print:1.0.0 androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 @@ -181,12 +150,20 @@ androidx.window.extensions.core:core:1.0.0 androidx.window:window-core-android:1.3.0 androidx.window:window-core:1.3.0 androidx.window:window:1.3.0 +co.touchlab:kermit-android:2.0.4 +co.touchlab:kermit-core-android:2.0.4 +co.touchlab:kermit-core:2.0.4 +co.touchlab:kermit:2.0.4 co.touchlab:stately-concurrency-jvm:2.0.7 co.touchlab:stately-concurrency:2.0.7 co.touchlab:stately-concurrent-collections-jvm:2.0.7 co.touchlab:stately-concurrent-collections:2.0.7 co.touchlab:stately-strict-jvm:2.0.7 co.touchlab:stately-strict:2.0.7 +com.arkivanov.essenty:back-handler-android:2.1.0 +com.arkivanov.essenty:back-handler:2.1.0 +com.arkivanov.essenty:utils-internal-android:2.1.0 +com.arkivanov.essenty:utils-internal:2.1.0 com.caverock:androidsvg-aar:1.4 com.google.accompanist:accompanist-drawablepainter:0.34.0 com.google.accompanist:accompanist-pager:0.34.0 @@ -200,7 +177,6 @@ com.google.android.gms:play-services-auth:21.2.0 com.google.android.gms:play-services-base:18.3.0 com.google.android.gms:play-services-basement:18.4.0 com.google.android.gms:play-services-cloud-messaging:17.2.0 -com.google.android.gms:play-services-code-scanner:16.1.0 com.google.android.gms:play-services-fido:21.0.0 com.google.android.gms:play-services-measurement-api:22.1.0 com.google.android.gms:play-services-measurement-base:22.1.0 @@ -211,10 +187,7 @@ com.google.android.gms:play-services-measurement:22.1.0 com.google.android.gms:play-services-stats:17.0.2 com.google.android.gms:play-services-tasks:18.2.0 com.google.android.libraries.identity.googleid:googleid:1.1.1 -com.google.android.odml:image:1.0.0-beta1 -com.google.auto.value:auto-value-annotations:1.6.3 com.google.code.findbugs:jsr305:3.0.2 -com.google.code.gson:gson:2.10.1 com.google.dagger:dagger:2.27 com.google.errorprone:error_prone_annotations:2.26.0 com.google.firebase:firebase-abt:21.1.1 @@ -247,14 +220,8 @@ com.google.guava:failureaccess:1.0.1 com.google.guava:guava:31.1-android com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava com.google.j2objc:j2objc-annotations:1.3 -com.google.mlkit:barcode-scanning-common:17.0.0 -com.google.mlkit:common:18.9.0 -com.google.mlkit:vision-common:17.0.0 com.google.protobuf:protobuf-javalite:4.26.0 com.google.protobuf:protobuf-kotlin-lite:4.26.0 -com.google.zxing:core:3.5.3 -com.maxkeppeler.sheets-compose-dialogs:calendar:1.3.0 -com.maxkeppeler.sheets-compose-dialogs:core:1.3.0 com.russhwolf:multiplatform-settings-android:1.2.0 com.russhwolf:multiplatform-settings-coroutines-android:1.2.0 com.russhwolf:multiplatform-settings-coroutines:1.2.0 @@ -263,22 +230,19 @@ com.russhwolf:multiplatform-settings-no-arg:1.2.0 com.russhwolf:multiplatform-settings-serialization-android:1.2.0 com.russhwolf:multiplatform-settings-serialization:1.2.0 com.russhwolf:multiplatform-settings:1.2.0 +com.squareup.okhttp3:okhttp-sse:4.12.0 com.squareup.okhttp3:okhttp:4.12.0 -com.squareup.okio:okio-jvm:3.9.0 -com.squareup.okio:okio:3.9.0 -com.squareup.retrofit2:converter-gson:2.11.0 -com.squareup.retrofit2:retrofit:2.11.0 +com.squareup.okio:okio-jvm:3.9.1 +com.squareup.okio:okio:3.9.1 de.jensklingenberg.ktorfit:ktorfit-annotations-android:2.1.0 de.jensklingenberg.ktorfit:ktorfit-annotations:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-converters-call-android:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-converters-call:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-converters-flow-android:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-converters-flow:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-lib-android:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-lib-light-android:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-lib:2.1.0 -dev.chrisbanes.snapper:snapper:0.3.0 +de.jensklingenberg.ktorfit:ktorfit-lib-ktor-3.0.0-beta-2-android:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-lib-ktor-3.0.0-beta-2:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-lib-light-ktor-3.0.0-beta-2-android:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-lib-light-ktor-3.0.0-beta-2:2.1.0 +dev.chrisbanes.material3:material3-window-size-class-multiplatform-android:0.5.0 +dev.chrisbanes.material3:material3-window-size-class-multiplatform:0.5.0 +dev.chrisbanes.snapper:snapper:0.2.2 io.coil-kt.coil3:coil-android:3.0.0-alpha10 io.coil-kt.coil3:coil-compose-core-android:3.0.0-alpha10 io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 @@ -298,75 +262,101 @@ io.insert-koin:koin-annotations-jvm:1.4.0-RC4 io.insert-koin:koin-annotations:1.4.0-RC4 io.insert-koin:koin-bom:4.0.0-RC2 io.insert-koin:koin-compose-jvm:4.0.0-RC2 +io.insert-koin:koin-compose-viewmodel-jvm:4.0.0-RC2 +io.insert-koin:koin-compose-viewmodel:4.0.0-RC2 io.insert-koin:koin-compose:4.0.0-RC2 io.insert-koin:koin-core-jvm:4.0.0-RC2 io.insert-koin:koin-core-viewmodel-jvm:4.0.0-RC2 io.insert-koin:koin-core-viewmodel:4.0.0-RC2 io.insert-koin:koin-core:4.0.0-RC2 -io.ktor:ktor-client-android-jvm:2.3.4 -io.ktor:ktor-client-android:2.3.4 -io.ktor:ktor-client-cio-jvm:2.3.12 -io.ktor:ktor-client-content-negotiation-jvm:2.3.4 -io.ktor:ktor-client-content-negotiation:2.3.4 -io.ktor:ktor-client-core-jvm:3.0.0-beta-2 -io.ktor:ktor-client-core:3.0.0-beta-2 -io.ktor:ktor-client-json-jvm:2.3.4 -io.ktor:ktor-client-json:2.3.4 -io.ktor:ktor-client-logging-jvm:2.3.4 -io.ktor:ktor-client-logging:2.3.4 -io.ktor:ktor-client-serialization-jvm:2.3.4 -io.ktor:ktor-client-serialization:2.3.4 -io.ktor:ktor-events-jvm:3.0.0-beta-2 -io.ktor:ktor-events:3.0.0-beta-2 -io.ktor:ktor-http-cio-jvm:2.3.12 -io.ktor:ktor-http-cio:2.3.12 -io.ktor:ktor-http-jvm:3.0.0-beta-2 -io.ktor:ktor-http:3.0.0-beta-2 -io.ktor:ktor-io-jvm:3.0.0-beta-2 -io.ktor:ktor-io:3.0.0-beta-2 -io.ktor:ktor-network-jvm:2.3.12 -io.ktor:ktor-network-tls-jvm:2.3.12 -io.ktor:ktor-network-tls:2.3.12 -io.ktor:ktor-network:2.3.12 -io.ktor:ktor-serialization-jvm:3.0.0-beta-2 -io.ktor:ktor-serialization-kotlinx-json-jvm:2.3.4 -io.ktor:ktor-serialization-kotlinx-json:2.3.4 -io.ktor:ktor-serialization-kotlinx-jvm:2.3.4 -io.ktor:ktor-serialization-kotlinx:2.3.4 -io.ktor:ktor-serialization:3.0.0-beta-2 -io.ktor:ktor-sse-jvm:3.0.0-beta-2 -io.ktor:ktor-sse:3.0.0-beta-2 -io.ktor:ktor-utils-jvm:3.0.0-beta-2 -io.ktor:ktor-utils:3.0.0-beta-2 -io.ktor:ktor-websocket-serialization-jvm:3.0.0-beta-2 -io.ktor:ktor-websocket-serialization:3.0.0-beta-2 -io.ktor:ktor-websockets-jvm:3.0.0-beta-2 -io.ktor:ktor-websockets:3.0.0-beta-2 +io.ktor:ktor-client-auth-jvm:3.0.0-rc-1 +io.ktor:ktor-client-auth:3.0.0-rc-1 +io.ktor:ktor-client-cio-jvm:3.0.0-beta-2 +io.ktor:ktor-client-content-negotiation-jvm:3.0.0-rc-1 +io.ktor:ktor-client-content-negotiation:3.0.0-rc-1 +io.ktor:ktor-client-core-jvm:3.0.0-rc-1 +io.ktor:ktor-client-core:3.0.0-rc-1 +io.ktor:ktor-client-json-jvm:3.0.0-rc-1 +io.ktor:ktor-client-json:3.0.0-rc-1 +io.ktor:ktor-client-logging-jvm:3.0.0-rc-1 +io.ktor:ktor-client-logging:3.0.0-rc-1 +io.ktor:ktor-client-okhttp-jvm:3.0.0-rc-1 +io.ktor:ktor-client-okhttp:3.0.0-rc-1 +io.ktor:ktor-client-serialization-jvm:3.0.0-rc-1 +io.ktor:ktor-client-serialization:3.0.0-rc-1 +io.ktor:ktor-events-jvm:3.0.0-rc-1 +io.ktor:ktor-events:3.0.0-rc-1 +io.ktor:ktor-http-cio-jvm:3.0.0-beta-2 +io.ktor:ktor-http-cio:3.0.0-beta-2 +io.ktor:ktor-http-jvm:3.0.0-rc-1 +io.ktor:ktor-http:3.0.0-rc-1 +io.ktor:ktor-io-jvm:3.0.0-rc-1 +io.ktor:ktor-io:3.0.0-rc-1 +io.ktor:ktor-network-jvm:3.0.0-beta-2 +io.ktor:ktor-network-tls-jvm:3.0.0-beta-2 +io.ktor:ktor-network-tls:3.0.0-beta-2 +io.ktor:ktor-network:3.0.0-beta-2 +io.ktor:ktor-serialization-jvm:3.0.0-rc-1 +io.ktor:ktor-serialization-kotlinx-json-jvm:3.0.0-rc-1 +io.ktor:ktor-serialization-kotlinx-json:3.0.0-rc-1 +io.ktor:ktor-serialization-kotlinx-jvm:3.0.0-rc-1 +io.ktor:ktor-serialization-kotlinx:3.0.0-rc-1 +io.ktor:ktor-serialization:3.0.0-rc-1 +io.ktor:ktor-sse-jvm:3.0.0-rc-1 +io.ktor:ktor-sse:3.0.0-rc-1 +io.ktor:ktor-utils-jvm:3.0.0-rc-1 +io.ktor:ktor-utils:3.0.0-rc-1 +io.ktor:ktor-websocket-serialization-jvm:3.0.0-rc-1 +io.ktor:ktor-websocket-serialization:3.0.0-rc-1 +io.ktor:ktor-websockets-jvm:3.0.0-rc-1 +io.ktor:ktor-websockets:3.0.0-rc-1 io.michaelrocks:libphonenumber-android:8.13.35 javax.inject:javax.inject:1 org.checkerframework:checker-qual:3.12.0 -org.jetbrains.androidx.core:core-bundle-android:1.0.0 -org.jetbrains.androidx.core:core-bundle:1.0.0 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.0 -org.jetbrains.androidx.savedstate:savedstate:1.2.0 -org.jetbrains.compose.components:components-resources-android:1.6.11 -org.jetbrains.compose.components:components-resources:1.6.11 -org.jetbrains.compose.components:components-ui-tooling-preview-android:1.6.11 -org.jetbrains.compose.components:components-ui-tooling-preview:1.6.11 -org.jetbrains.compose.foundation:foundation:1.6.11 -org.jetbrains.compose.material3:material3:1.6.11 -org.jetbrains.compose.material:material-icons-extended:1.6.11 -org.jetbrains.compose.material:material:1.6.11 -org.jetbrains.compose.runtime:runtime:1.6.11 -org.jetbrains.compose.ui:ui-util:1.6.11 -org.jetbrains.compose.ui:ui:1.6.11 +org.jetbrains.androidx.core:core-bundle-android:1.0.1 +org.jetbrains.androidx.core:core-bundle:1.0.1 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.3-rc01 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.3-rc01 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.3-rc01 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.3-rc01 +org.jetbrains.androidx.navigation:navigation-common:2.8.0-alpha10 +org.jetbrains.androidx.navigation:navigation-compose:2.8.0-alpha10 +org.jetbrains.androidx.navigation:navigation-runtime:2.8.0-alpha10 +org.jetbrains.androidx.savedstate:savedstate:1.2.2 +org.jetbrains.compose.animation:animation-core:1.7.0-rc01 +org.jetbrains.compose.animation:animation:1.7.0-rc01 +org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 +org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 +org.jetbrains.compose.components:components-resources-android:1.7.0-rc01 +org.jetbrains.compose.components:components-resources:1.7.0-rc01 +org.jetbrains.compose.components:components-ui-tooling-preview-android:1.7.0-rc01 +org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 +org.jetbrains.compose.foundation:foundation-layout:1.7.0-rc01 +org.jetbrains.compose.foundation:foundation:1.7.0-rc01 +org.jetbrains.compose.material3:material3:1.7.0-rc01 +org.jetbrains.compose.material:material-icons-core:1.7.0-rc01 +org.jetbrains.compose.material:material-icons-extended:1.7.0-rc01 +org.jetbrains.compose.material:material-ripple:1.7.0-rc01 +org.jetbrains.compose.material:material:1.7.0-rc01 +org.jetbrains.compose.runtime:runtime-saveable:1.7.0-rc01 +org.jetbrains.compose.runtime:runtime:1.7.0-rc01 +org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 +org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 +org.jetbrains.compose.ui:ui-text:1.7.0-rc01 +org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 +org.jetbrains.compose.ui:ui-util:1.7.0-rc01 +org.jetbrains.compose.ui:ui:1.7.0-rc01 org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.20 org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 +org.jetbrains.kotlin:kotlin-reflect:2.0.20 org.jetbrains.kotlin:kotlin-stdlib-common:2.0.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 org.jetbrains.kotlin:kotlin-stdlib:2.0.20 +org.jetbrains.kotlinx:atomicfu-jvm:0.23.2 +org.jetbrains.kotlinx:atomicfu:0.23.2 org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.8 org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 @@ -376,16 +366,16 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.9.0 org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0 org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.9.0 -org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.0 -org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 -org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.5.1 -org.jetbrains.kotlinx:kotlinx-io-bytestring:0.5.1 -org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.5.1 -org.jetbrains.kotlinx:kotlinx-io-core:0.5.1 +org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1 +org.jetbrains.kotlinx:kotlinx-datetime:0.6.1 +org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.5.3 +org.jetbrains.kotlinx:kotlinx-io-bytestring:0.5.3 +org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.5.3 +org.jetbrains.kotlinx:kotlinx-io-core:0.5.3 org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 org.jetbrains:annotations:23.0.0 -org.slf4j:slf4j-api:2.0.13 +org.slf4j:slf4j-api:2.0.16 diff --git a/mifospay/google-services.json b/mifospay-android/google-services.json similarity index 100% rename from mifospay/google-services.json rename to mifospay-android/google-services.json diff --git a/mifospay/lint-baseline.xml b/mifospay-android/lint-baseline.xml similarity index 100% rename from mifospay/lint-baseline.xml rename to mifospay-android/lint-baseline.xml diff --git a/mifospay/prodRelease-badging.txt b/mifospay-android/prodRelease-badging.txt similarity index 81% rename from mifospay/prodRelease-badging.txt rename to mifospay-android/prodRelease-badging.txt index 0b23830ab..7d11a2720 100644 --- a/mifospay/prodRelease-badging.txt +++ b/mifospay-android/prodRelease-badging.txt @@ -1,4 +1,4 @@ -package: name='org.mifospay' versionCode='1' versionName='0.0.2-beta.0.2' platformBuildVersionName='14' platformBuildVersionCode='34' compileSdkVersion='34' compileSdkVersionCodename='14' +package: name='org.mifospay' versionCode='1' versionName='0.0.4-beta.0.7' platformBuildVersionName='14' platformBuildVersionCode='34' compileSdkVersion='34' compileSdkVersionCodename='14' sdkVersion:'26' targetSdkVersion:'34' uses-permission: name='android.permission.INTERNET' @@ -7,7 +7,6 @@ uses-permission: name='android.permission.READ_EXTERNAL_STORAGE' uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE' uses-permission: name='android.permission.READ_CONTACTS' uses-permission: name='android.permission.ACCESS_NETWORK_STATE' -uses-permission: name='android.permission.VIBRATE' uses-permission: name='android.permission.POST_NOTIFICATIONS' uses-permission: name='android.permission.WAKE_LOCK' uses-permission: name='com.google.android.c2dm.permission.RECEIVE' @@ -29,14 +28,12 @@ application-label-ca:'Mifos Pay' application-label-cs:'Mifos Pay' application-label-da:'Mifos Pay' application-label-de:'Mifos Pay' -application-label-de-DE:'Mifos Pay' application-label-el:'Mifos Pay' application-label-en-AU:'Mifos Pay' application-label-en-CA:'Mifos Pay' application-label-en-GB:'Mifos Pay' application-label-en-IN:'Mifos Pay' application-label-en-XC:'Mifos Pay' -application-label-eo:'Mifos Pay' application-label-es:'Mifos Pay' application-label-es-US:'Mifos Pay' application-label-et:'Mifos Pay' @@ -45,8 +42,6 @@ application-label-fa:'Mifos Pay' application-label-fi:'Mifos Pay' application-label-fr:'Mifos Pay' application-label-fr-CA:'Mifos Pay' -application-label-ga:'Mifos Pay' -application-label-gd:'Mifos Pay' application-label-gl:'Mifos Pay' application-label-gu:'Mifos Pay' application-label-hi:'Mifos Pay' @@ -54,21 +49,17 @@ application-label-hr:'Mifos Pay' application-label-hu:'Mifos Pay' application-label-hy:'Mifos Pay' application-label-in:'Mifos Pay' -application-label-in-ID:'Mifos Pay' application-label-is:'Mifos Pay' application-label-it:'Mifos Pay' application-label-it-IT:'Mifos Pay' application-label-iw:'Mifos Pay' application-label-ja:'Mifos Pay' -application-label-jv:'Mifos Pay' application-label-ka:'Mifos Pay' application-label-kk:'Mifos Pay' application-label-km:'Mifos Pay' application-label-kn:'Mifos Pay' application-label-ko:'Mifos Pay' -application-label-ku:'Mifos Pay' application-label-ky:'Mifos Pay' -application-label-lb:'Mifos Pay' application-label-lo:'Mifos Pay' application-label-lt:'Mifos Pay' application-label-lv:'Mifos Pay' @@ -81,7 +72,6 @@ application-label-my:'Mifos Pay' application-label-nb:'Mifos Pay' application-label-ne:'Mifos Pay' application-label-nl:'Mifos Pay' -application-label-no:'Mifos Pay' application-label-or:'Mifos Pay' application-label-pa:'Mifos Pay' application-label-pl:'Mifos Pay' @@ -130,14 +120,12 @@ feature-group: label='' uses-feature-not-required: name='android.hardware.camera' uses-feature: name='android.hardware.faketouch' uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps' - uses-feature: name='android.hardware.screen.portrait' - uses-implied-feature: name='android.hardware.screen.portrait' reason='one or more activities have specified a portrait orientation' main other-activities other-receivers other-services supports-screens: 'small' 'normal' 'large' 'xlarge' supports-any-density: 'true' -locales: '--_--' 'af' 'am' 'ar' 'as' 'az' 'be' 'bg' 'bn' 'bs' 'ca' 'cs' 'da' 'de' 'de-DE' 'el' 'en-AU' 'en-CA' 'en-GB' 'en-IN' 'en-XC' 'eo' 'es' 'es-US' 'et' 'eu' 'fa' 'fi' 'fr' 'fr-CA' 'ga' 'gd' 'gl' 'gu' 'hi' 'hr' 'hu' 'hy' 'in' 'in-ID' 'is' 'it' 'it-IT' 'iw' 'ja' 'jv' 'ka' 'kk' 'km' 'kn' 'ko' 'ku' 'ky' 'lb' 'lo' 'lt' 'lv' 'mk' 'ml' 'mn' 'mr' 'ms' 'my' 'nb' 'ne' 'nl' 'no' 'or' 'pa' 'pl' 'pt' 'pt-BR' 'pt-PT' 'ro' 'ru' 'ru-RU' 'si' 'sk' 'sl' 'so' 'sq' 'sr' 'sr-Latn' 'sv' 'sw' 'ta' 'te' 'th' 'tl' 'tr' 'tr-TR' 'uk' 'ur' 'uz' 'vi' 'zh' 'zh-CN' 'zh-HK' 'zh-TW' 'zu' +locales: '--_--' 'af' 'am' 'ar' 'as' 'az' 'be' 'bg' 'bn' 'bs' 'ca' 'cs' 'da' 'de' 'el' 'en-AU' 'en-CA' 'en-GB' 'en-IN' 'en-XC' 'es' 'es-US' 'et' 'eu' 'fa' 'fi' 'fr' 'fr-CA' 'gl' 'gu' 'hi' 'hr' 'hu' 'hy' 'in' 'is' 'it' 'it-IT' 'iw' 'ja' 'ka' 'kk' 'km' 'kn' 'ko' 'ky' 'lo' 'lt' 'lv' 'mk' 'ml' 'mn' 'mr' 'ms' 'my' 'nb' 'ne' 'nl' 'or' 'pa' 'pl' 'pt' 'pt-BR' 'pt-PT' 'ro' 'ru' 'ru-RU' 'si' 'sk' 'sl' 'so' 'sq' 'sr' 'sr-Latn' 'sv' 'sw' 'ta' 'te' 'th' 'tl' 'tr' 'tr-TR' 'uk' 'ur' 'uz' 'vi' 'zh' 'zh-CN' 'zh-HK' 'zh-TW' 'zu' densities: '160' '240' '320' '480' '640' native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64' diff --git a/mifospay/proguard-rules.pro b/mifospay-android/proguard-rules.pro similarity index 100% rename from mifospay/proguard-rules.pro rename to mifospay-android/proguard-rules.pro diff --git a/mifospay/release_keystore.keystore b/mifospay-android/release_keystore.keystore similarity index 100% rename from mifospay/release_keystore.keystore rename to mifospay-android/release_keystore.keystore diff --git a/mifospay/src/androidTest/java/org/mifospay/ExampleInstrumentedTest.kt b/mifospay-android/src/androidTest/java/org/mifospay/ExampleInstrumentedTest.kt similarity index 100% rename from mifospay/src/androidTest/java/org/mifospay/ExampleInstrumentedTest.kt rename to mifospay-android/src/androidTest/java/org/mifospay/ExampleInstrumentedTest.kt diff --git a/mifospay/src/main/AndroidManifest.xml b/mifospay-android/src/main/AndroidManifest.xml similarity index 94% rename from mifospay/src/main/AndroidManifest.xml rename to mifospay-android/src/main/AndroidManifest.xml index c2e70fff0..7e621eda9 100644 --- a/mifospay/src/main/AndroidManifest.xml +++ b/mifospay-android/src/main/AndroidManifest.xml @@ -73,10 +73,6 @@ - - true + is MainUiState.Success -> false + } + } + + setContent { + MifosPaySharedApp( + networkMonitor = networkMonitor, + timeZoneMonitor = timeZoneMonitor, + ) + } + } +} diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/MyApplication.kt b/mifospay-android/src/main/kotlin/org/mifospay/MifosPayApp.kt similarity index 58% rename from shared/src/androidMain/kotlin/org/mifospay/shared/MyApplication.kt rename to mifospay-android/src/main/kotlin/org/mifospay/MifosPayApp.kt index 6fccb03bf..de10c0aba 100644 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/MyApplication.kt +++ b/mifospay-android/src/main/kotlin/org/mifospay/MifosPayApp.kt @@ -7,18 +7,22 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared +package org.mifospay import android.app.Application import org.koin.android.ext.koin.androidContext -import org.mifospay.shared.di.initKoin - -class MyApplication : Application() { +import org.koin.android.ext.koin.androidLogger +import org.koin.core.context.GlobalContext.startKoin +import org.mifospay.shared.di.KoinModules +class MifosPayApp : Application() { override fun onCreate() { super.onCreate() - initKoin { - androidContext(this@MyApplication) + + startKoin { + androidContext(this@MifosPayApp) + androidLogger() + modules(KoinModules.allModules) } } } diff --git a/mifospay/src/main/java/org/mifospay/data/firebase/api/services/MifosPayMessagingService.kt b/mifospay-android/src/main/kotlin/org/mifospay/data/firebase/api/services/MifosPayMessagingService.kt similarity index 100% rename from mifospay/src/main/java/org/mifospay/data/firebase/api/services/MifosPayMessagingService.kt rename to mifospay-android/src/main/kotlin/org/mifospay/data/firebase/api/services/MifosPayMessagingService.kt diff --git a/mifospay/src/main/java/org/mifospay/utils/NotificationUtils.kt b/mifospay-android/src/main/kotlin/org/mifospay/utils/NotificationUtils.kt similarity index 100% rename from mifospay/src/main/java/org/mifospay/utils/NotificationUtils.kt rename to mifospay-android/src/main/kotlin/org/mifospay/utils/NotificationUtils.kt diff --git a/mifospay/src/main/res/drawable/bg_splash.xml b/mifospay-android/src/main/res/drawable/bg_splash.xml similarity index 100% rename from mifospay/src/main/res/drawable/bg_splash.xml rename to mifospay-android/src/main/res/drawable/bg_splash.xml diff --git a/mifospay/src/main/res/drawable/bg_splash_12.xml b/mifospay-android/src/main/res/drawable/bg_splash_12.xml similarity index 100% rename from mifospay/src/main/res/drawable/bg_splash_12.xml rename to mifospay-android/src/main/res/drawable/bg_splash_12.xml diff --git a/mifospay-android/src/main/res/drawable/feature_accounts_ic_bank.xml b/mifospay-android/src/main/res/drawable/feature_accounts_ic_bank.xml new file mode 100644 index 000000000..a7856762d --- /dev/null +++ b/mifospay-android/src/main/res/drawable/feature_accounts_ic_bank.xml @@ -0,0 +1,28 @@ + + + + + + \ No newline at end of file diff --git a/mifospay-android/src/main/res/drawable/feature_receipt_mifospay_round_logo.png b/mifospay-android/src/main/res/drawable/feature_receipt_mifospay_round_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..38b8ada8c5730a9b3d395a4ab9a6d8e68ab465f0 GIT binary patch literal 39075 zcmeFZgQ_tMcXTqkkx5(|!YO!5k@8!f+f3bib{AkNw(fG9<#r?_-nu!cMFIZjP7m zGn>AawnyhjGyZ&jBTOtTEMbvoN}>O~q=X=jY)EhG-h}^s)~*l=i6w;pcS$IkH;WX! zm`~GJ5yB+(?~BMV_s;*lVJhUijRnhtS3e@4yZ!I0uziW@|K8Bu&coESSihe(mwXE| z>E9PR$=d(kVE%d>3Q@H$+)DW0W7&|x82^(>${s>wD0;`%?|+Y#f_IAiClL5ll(4XU zgq*F3@jn^pfK-G3dqeO&>lQj;JU% z|EuEvJE|yr1kY^Rs}JJ4o8hjo+{bzPXmx(!`g+&7Zuh6UiP%mT^G~;n;E*K(eCW00 z`gJEW-M+dBFC|}O6rHOQ-pE}HdQ&Cj_HGTmsm|(EOVFkFa8?mKW6z8AC4_l} z$FBG$Ih!a@RZn|M4Nkv^TyZyF5t}|B9g3vNlDV{nbkpA^xQBNetNa#x4axKq3aJ(` z(JvOHX^d8T!DTtR7+X6T4C|t&t0H$!AAB+WVCB=LX@enGr8haNSWN_)H$4bI*b2Tf z5I7?p>w(|}qt!-{ny#y)FS=(;qC7REy0hNRrJy!?!9Si4!Hrn~(pcrJzNm-hx52T?Elcb~jVSee_@MH0>- z3|LGTSe|XJ;dcUTLSc_n5|Uj!X&;KR<2*&(m;n@tg6!lR9bI5OO)&D-7bx+E3b*vW zg7J9$av89xszB1#H~p>3bi@#hq51Zz5bCCs#Ckc2GbusUNugDkY0xxkY9|uK?rdhdDqd$B~j&7fFPR^`3;$f*2k6VZpvC|^<_gg^K1>jN4^inWFZI<;d@b}ny3A2b(pudiQs09 zVvJI76gl@qEe~83e>n5Q9@%rVKM#EQD#9Y|!wyZVh!BKBVrRD+CpgjZ&2Dz85-haA z?kfe!jTc7CKT@BP8&AnA!7pex2qnqKMfi!kKE<2XfADd8(&@JE@@__n0s%@^Sj;m@*q`;t0u~6tRNki#t|x%i<-i6cSEc$XeP)JAA)K@Kn9f zrnQ`G_7#@sIG6IP&X-oAz+>KGzxSaguoQ6Zzz;f@QKxEoHrhz{O9Ycmflk@M=e;q3 z=ORCl01hM|FH)lY-MwJHclPGn55HAWM-WxmR0^$zbIGQPMZZ8vwZ`sbt3i%$wo8yr z?dSK?d(8)R+b4lFa z5IfZ&G*Nebh-b2Q0SoH4Wp`;$mdIGS+Xy!ysA_mUo__n4oqInG>Z&j>6F>9N@7phi zV20ZS^@&mmk6)3EEm|JrZXI)Ix#a??EYbbdbnO&{h&U+yf`2n>IR?UZUMs1eZOf|4=KvR;4%< zF@E97T7eTbpLz?kUhT%ObG~yVF}|L0HB3eeQUjMxMohICqY)6oY4vH4u2ya2-$vnX z($>rbbnxqYHs6v+3Vh4pYZU3|sh_>9$ZqxzzsSOa61N~xYIk>XaVUKDtJ~gtsbl4K zXNXV#YKI2*nBqEQs(B}tIw@2LSZ4F9?pibaddh-Ojn&;Qq{t)s(+b0zY7peTb(t`p zUoSbHm8r?U!NDDQt$HL4p#i(IPexApOIk{sTa3?*`Y3;O4j%9uN%aT2PPQvp8+>z3{)%+)Lxkq;6}OB12)J=wq<;jz#{4z?2+PQ3Jy5)%*PBoJ>k ziq$(GM7IgTRkm^Y&{oQ#awU2FGDeb z0Aj?pgtaT)K|a_>e+Wq0)^=?QJt_2g`>o&M?I6ry!9q}q*XLsbVtbvm!k&w7!GHWk z4tS8_efv&#cd@7!F{?~?1mACP3ZJN8Zv7G7*;W1RhXbyiyc1~h}3~fp|4!J+-pEdJbX*_-s_(RTYnD_=EAz8n_mUaxfHZgsJjmbho@H-k@ ztXOY&I+i~3>jb6ZA|8;%bF; z6efwy)|esdOgE}y!tY6DCu(aR!TSa!r6(eIdLx8!X1OW51U-JZy?giXhNkj=Jj^h^ zJ#ZUp{VR1mv+wgh-)DhaSg^@Bm?`6iI#vEv0M4qLxTPbmH&9t9TFSkeDzp1KW^U1O zujnIWAnG^3$y1p5Da!8t7e!cS!m@$#%fHC&rvyYVX6;M0U(QX1ydnd^y}8s%m!w`RcK~TSv6N82higT>5{#?h!=HvPaoN5?nKgp=5V7Xs!R}4c!{# zMwQQ$rPRsPL$YCePNf$fA!iJE3DmpGkZI$GJ8+C?XYP{%a&k44P~3pv-eS z!hD{ZlQfVuf1?QpqXa2}YtR(A=WBS-8`WTfn7uozdC;J{LJMCfk`X5we;>f z?~RlviBkFH>mQa{NZyelMnl3qnPl-m!jL1ou>Xo+%=qqd!Ye1&dFHN}Aa`?L5|$)R zYf)IR5S4)H+9w|L%?5S2?W@eHdA~tKp6L#$&0n<;{HDF#Q1|r8SnYeg4E;4uUou1` z6ap4SU6>RI)e!0Y4|{Ak zh6KO{=TA;krW;i)6Wqg934a+(S?D~c-6fEMSeF6*L>kw%ZFA8V{><{Cpi3YLal;aX zqGJY)HVK-!XwQe`8+Y4c!3ew0{zL};J{sd>IZCShdrc!+lwW1SZCB{~&0Cxr=|D@$ ztUXCnk9ZF1s96pZ-2Pr9a!=DHi!mXg8R*5*MR9N;9zI%^{hhDzuSQlGd5XMznmf{A zqv!}ozYRSqADW7uwgc8>7}j3bvRSB+>WTP0&Y`XiBHIX`5RGichq9!ejxd%O4pX2m zBm~ay7;0|zoG5QIttPAq@jDsP&tysBF}}Sy{$?=TS_6)JNsNh+dm92|(KkT(?M!*cCc9bl|h>WHlcr z8MKyLPKEu%Rirl^|C(D;XcHP1Y9LyT_LKagN!G0Emw>xB=p{+2-nr}BJHs*RX1qWR zbH6&w&3~vKw#PpKv_d{ta<=)Fscy+#ZZC?Cka^ffnGs6Dm|=;U_rfw#)A>h=X6D~N zWYIsI2Aov5pSf-y9^qf2~ z+yUT*;`ki%C)5pi@F%pe_Hp9@9~9|Ns)(Cg6VWF@RoMh_UBgGvtJ$qS91gr`=XDsU znvMJLvg|dfJH?nxHUQ+n$?=qKvdgEJ<+Dbk7$f%+wj+QA-!4(`cA=ucF^y|WFcB>D z;r}PFwzHu*AqJfTO*83Dqi=HRHK-+GuLvxWXJ)lGb)yUj?L`MpFUKoDkaL&#}QiH?BFv@V|zj|GKDXxyh@ zW8wcx59-n-(VOy2;5f#YGJBR;R5H7OH7I2=7FlWSRV+L`b9y5UDb=rhSh&+ZkNBp{O8(I0tdZfw$(%Tu);$A(nbr4 zCZKgZ6|->bP`dAEHxlw-!lgBIKPM&VJzk1$bknpz7xs zRA?)r)JC07rUC<0xa=F~==!(r_-*vL&a{^04Ex=2K!3sVH#GB5!d=Kmr;e;6QN31z zlWBV|AW*4SF^z;T0>VkH)?Sv~t`6-0^)4`}%q*$&r3U2s>slpB0vkIaoJ~q}{ZN?> zo1)v0Ag01vVKwQWHR?0+Y>z7rzxP!x zYoLA_!j8P43R})_d$rNz<-y21F~sO4{LfZE33~F`sgHu^Z=-wK)D)fH{*wjiPyEHa zptmiJjf~6?K2H{X@poeh9QHNoLDbGY{cs^n%!a(U7r1gUM zm03&8sC->y1t{k^q~-WPK$n{5f!{LW1wX@!e_}fwJP-}gTb47?zR%t{s9Wvbxp6Y7 zgt&&->|O5mR=&wg9*P%#Z3T$geN)3)5*mTx_hnBv2p~cC4I6j)t~4%?`-QX$OL+f2 zJV_L8kRusAEbfG#nh3(jDcNt@kOKM9#Ei3NM82R1{c9>agoc7VRBBKX-?rP%0icxX zx3<|4s(*ft+t+pq7N~@yX}gWU#o;FzWlL5sySSxKHgZQ-CR%!?K zN{Nyxj^7dDnz!54=6jCo);Ze=Vr%)l9}R2OY*+2;3=d%GCauKb?;d%yQko3sV}p=< z$J|?P^}vz%u)W?+$KsSuP`{zah-NxbQv1GZY2@NC1~x-p6y*#zpcB4qvwnDb&JJ7f zA{qV=bnDDQg=5(EsV2o3x4|vfQeyd>QcJdcq1bL;Rwfp!KZ~lhr~DzC%2Z;09m^8B zuA2OQcFjNDP&JNmzGP_NE!&9F*lzU_qIslY(m5uXXwjMfQP_8#WGOQTuNiMzXfy#3 z`<0uxxr!YRNH=H8J~XCswi}qATseq0q|P zOOXWMV|rQPs#s;XGZD{=UTt|?lE}!Shg*rmR&XgW#W6#~kquWwp$@Cmkts!RgyUJNQ0&e=oL zrqQ@dyim9zBFgLKJsfiz!D~Er>k_bek3P#!U%$%fV8aXw@TTm?Y6Hlo^|6Qy6|$Bjl_j2IuN^BMP{YxI@2 zthvbiIVm=-H6LQ-Ug&z+U#AJvAOVcL%Og+jYtC~8F=97W-~8GNvDt)%&6mpM&Ulal zpE9_RvG_`|00YScHL^fszta%rPBKIKW=npAw_v5`c}A7K?9m)q%NR%M&{1*5wDR17 zAZ@qT^5n9DjZ5i{p{d2(1I2v#lsl!apODx3P1@l?UZW4it~&x|V+4=+9Apa4eoZ0c zh9ya&>JlOS{dmgHORB4e6yChtFY8gRoGXyHZS>i*B&aD!lIcTf?vIof>>b2`W4Kn8 z$@3f37Mz{tRW>z!xi{Pxf^kaAy%LPuvJ~K z<&o>gyx~5Dn);=inD;Q}3`A=k9yWzM{)3w|ib#lYnRP$x^_+P??uUhruvXcp*!#3f z%u^q}DXwJKRxF!;c^xzbqU9SudzB9fgdh!>spA-FWqn%D%xEDiX<)iP$6t;Ea?1M1 zyY#@JrA}I*U!G3dt#Yl;-wIL~u&sE`(q0LNN=RlqcYZG(#WHyI-qAlU_-(D~0~_Fq zVb>z0i`A87Se_hvP4=7h0tGgmB_Of7mQ^Z1jdC>5;RE$vj|*1$ zm`86ZBD$OgN2TP6$G}L-Gp~K~w{vJi&fa2Yh9c#U;V5+3DV`^r;pk=u7R_(l9=Ig1 z5bKbNq`YrEu0NFU|HOdF60&1VoAOfh(|*^A8d-}?!QQQrA{(@911_t;@!aWrr{2c7 z<(W^JZEDvBKD-6bw{#vfm|hTMh#To)3t0 zt_Vlb@Zvv_Y%`P`H+VsL)!^`G-DScRn^Mv#JiGW$BSze(Ex>*FKV)}mm83OJFgYs1 zuok#{v&s0Zztd4#xoh%lbis8p?WD9PolW&_#EkldFm#`pz69GptG24>XK>pM8aJn{ z^Ez`A0fdtmq{8n7oFpVSuNqVC~S|so$xfx<|p+zoKE0)^+l+ zmW97yovluDxdU^a(&MQo`ckx8*Jaz@Z>Ln^wf&KfhQ=QoP(mSWNd6)K_1?LLmm9^* z(%1VuYto%dZh2UxHoKCsQc#_BT$cao_l5P~v0d*~7RK4PE)SvO{7hzjjuZM9jJS#Z z1mq);!U6^ovVex#%ot-yA@h4Y^rW`TMjOf@ZVE~oEw{?RD}+3u^BI@MQWKr3G|&HQZ@VSe$deI(Rq=Of3cJBhk^{Mh&D zOf|vavAY7=Mp!gWE(K~Pr%ge>zjmA;t@TPe%o3Z!Iqs}Zt3#{F!b2aeqdk9e_#pq> zvSk71swhzHz*+0_dVK~%5#G`M;~smlB-Cs@7w+i8pbsbR2L<~X25+@29J^T!M1!YZ zza2GsVmEuij4<+Q2azGcSMs-z1>42zn?P62T7+4?w+X%ee5OL%MW(WWIIQdu}Y)gV+A2cKj->qW!u#6vv4hq1EbKG2*^^EHpGcLO=b@?T(yn zn(79PM7#tD4x=<}{Dt#;Ds~d;r+v40X~>1mCq2ZsAFHqSZa!@Y{HB$x+8uk8mymP2 z$A<~>yDNeQk8+oLUsP=OPh0(f2MQM(3+BgGY^JC!8r@S$wEC>T;gUYq#nE{{+eU(h z{14N<%{L2@jEf}3Dq#-sNzDr@pH3VG68fl6LH4c+VfxCf30p=)>&VlRreG2%4t{ z=nhNsY)G+tl~W_U(VH1veqNc3Y+UrWi_P*PbqwM@`I{WY^yYsU!;(i}q)zvj?!=U( zX1KrdZZnFG%_s|r*ILCk;p0k$poTq-VLz zg`2jqa1~Mgoq>C+M3*!hZdSfV6>6V&1~wPI+KR`(GNPL+e^%C~z$G#paA=3-P=}cT zeo51p(Rpo8BC{wj{ZwVcJx@ObJcT|Y{Ud&i&9x9S{LSY^6qZegHP&tFonGGQoLlZK z_S1KdF|{okK66OW-?n91NV#1#^0XtUMDMQ8Gcs9GVRg9X#-}V{-{EHlFKq7Pe2&MQ z+kTFEq{lI2ye1YJ!`e#pO36<#PE_c@rOJlmhG9<**3&m~`R-2U4 z1{Cz4wm}<>i9rpTI#a3q>Vq>kPL>LR?)kZt)9R&mQtH`&yXR3gqAfre{IZwMxQkgH z`E$o8g}U2S4CDdKI_`a*jQhBrNBIO#&vVJ?a`tV#S|3F+^i!+kkMHT4$jfyybn~T( zQ+`eSG!(J`YW%5!gvO_gSm@`!pl;e;n+J7yT5R@jZS>x{3dguvAF4TkjMUVd{sikq z(9m^QztExa%Y!`9%E0`8fctV|QKvKLLuTHxGi@QL8w#34-?z=GhRr_5a+Nf8`;pl7 zUvi&OOhyTEWDtuJ8;ra%JIyhnDEScf@sbY{^X0wu{nRcqad+Rf4ErQOrqio3yN(Pi zP`c;)Ayj~intDw8OjHIu9Pt11u<5$(@R#k_Gj1fi%E5kanc+_In|9C7z2#*FOGg#T z;>qk|R~)I*A8V~aDZTTp@YYyLgkQ?ZV5&?q3X`+j=TkIv-SI5y^{>)D9C63N z-F=H7eG6~#239FQpZS%~vuyN;5~#3Tb*Jq7(cAVBuOs0dRX6M;<2%}j8@h@%WD}Yh zyc@raUmt_Y7DLzPh#P1QV0P=)2q8%^=dg7=KE;Cl@Etka!qkj+J5;gUS3SzA^ebrI z;NL6AR7oxtx7dj;JH+5FG@H8c4gZzZq1=QqXk1&WO@uw~wtX`XLQ>p7$|}oc?}s_`-p)9mVt?KcGCFDIN!%}BiB+ykmgRrQ z;fFY=CBjLF(MpLG#f~@es@}hI9{UufQefMpZY`Ign5&S^(0?dPZ;RviHQj_WRl=0V z%+0Pqr()ra+KJP;#1O`j4)&DL#}4I@;VxRv&!Er^a#N0E5OEcW+TjMx)t<3S`?+qQ z8|wERxUpbP#M*lMfo6|@v*%nkIhMf(?L-E21fhhTc}t3oN1$ZLmsiIM3vs7XpIwB1 z%PT&bd63@(-*>-=@tf9t(=)QZz75>;{2YL(dm7`_ZG-RrWa?!$^oFeCius6ZOdQmo zgfG)l?mOw2d7L%!SLl-UYtLeE7##LMRa&so5%Y3+$7>ED1tx)M#cOXu&Dkn3&?~J# z8q8L-GixEBBaT^V&mW?~hM6}bz7wIb#^+L3WYiF(n920DAEiIsdhewELfpBDE&yNM zM9_=_OWeqRG$Yr+Sm+IL%$m=0k3XPO@%w7Pwbs(^&^ZoQAa(}lbmdq2iO(Mo_s4tw z#){_!Hku)(@#E!ImN4qfi!VM6gbxF`FEz}yElz_(FNH!s>XjRW%tus(2hTH%glzu?(t|mYho}C}Nm>Rc=FAvFp_v7h4}VGp15v z;&ud}s+eW}oV=6dao@xYro*Twt+W!sy=8#ZewsX9wp2CnwKMwHEe)du+=A@({mCw~ z3Yq{0BwMxE>vBDl_b}wjn~dBOPu==3)YOHC?#u>6HBN&5OW#2bO5EbkLAxFd z3s(2`6|sI5nw%4)-<&dV4l6obB_9hG13Oj#VHsk4EkvhpkC-`W;)$MaLZ$8m#HDBd=_|E;iMDCw~!b@ez}{WiEG%8GP81ykqjY zG4W;d1MZ{!`?*at#r@%(J$Y|fkZ}RSUIZGPKoQWxsb2~8XTK+@lOzXYN&}G!;--XE zb>(=P@I(F0n3FeUe-0Sn0f;RT9~|q9osNBR`y1Yog^vw+)w%jhZV`j8Zh5((OKoFI zxg8K74uQlJ1i2T25REe)V^gg1a|Y4B)SSvfU|XE1r8c3VXLaRQ=yiSm^HXA)1R)2u@f0yk9c}V zCb-Ba>y^vFZNeC!pQ{-L_QB{y`MI6Ux8pVI{^Wi{Cgpof*lo?jxrQJ97p3$@<h8 zQeNnCdoZ_@vLUrqc~#)3lV$F*C*Krd9sWWFXY9xw5AQVGHx3Ky!d_}K8->F(-xJgN z!oPJ)Q+z8Aosxwgh8*NPFqheWK!OItyQ2A#-kyy-qZK>93<$|VO+1?in^zw4aFe}K zm)KCURr3LuS_vKX?~x&#{EhFRYjgq^bgRiRLci~1okDf)!ClQ?DC z=LphG)(*D!6il|^Mt!NE8{Fj_Kd_Ww@Lbd4c2fC#b%VIXXD041bD0E{XbA6zUds=? zubk2;TTbg@%pm=x4E>}_D!{`ApWi(4k>7Ii;(GhMJllB`McPo}WcDKoG>brW7ty;7 zxV=WN+8Y(SwCw!wN7fr3hhDfwF_32T+Z}&t;LZ9>T@_T=4&kwwCJAb^NHn0+bKXj5 zCn(@(6UV4t`=TVT0k;)MMnOG_v)egz=qPcYJBAe4_W8T{z|+6VM!;7*H--yqIuxay zs<7FSDU36x%7MCA{pnjFeGe{l4BRN!A8w{|y4SsrPBxA6q2P=lM zjG#tOER+?NJwbkvU1J=eFfV!T&wzYG$Y@)CoZik`*0cYjUR&Ox7@<2h{2~(4zsLA> zN(J%y{E!Wq!slYxdP~2!KD#$g@}Qq&AR+j5z7)l&p7pSmBm9%g!uu#w6>qAx*H$ zqu&{>JhQ7-^wNp!10b2P+0&Bv@!`vO1c~9cggG32M*R$}eE5+M3la=lNrQfBUbZ`0 zGRhflOOlMz@UZoUqf|_Kr4wT0w~uX%)GYL{`W*ugS9jA0^a>_1J>ZGSwb6s^=a`#FrZ&8&8}H!>iAUe^kbEST77C?tg|y`*`d6Ia3rgJ zI`B+X-Ml4!H9eM0-{w@-;yqXO1!rX(3~BPRY{9PpZeldj(t3$0Qg#of+(8G`X2{;* zmbKe$|GtpBAi3^9teTS8_g)4Iwx(gLNIoYkdTo=fi=&+X0D;n=ki%a zt+wchGK?4OML98q?=j1t><)F;;&1KXI zTCfS=Td%j4jzfO?<<-Y1zTm2@a4Lo+?29Vr{T!6Ms+-EIy0=aHIsr|8m4*<<=ZSIE zZu`G|hyb4wT}cFyVRb{x36xJQ-S6wDQAT!q>B)rqz5YCM=ct(M&><64WJt0uuRj&OOp7FHZM)9m>5C<5+PGiDe$G{lD ze&2&}F7=f{%D}u;&lS|K|3%wQ=!LQo8*-NUSyleHK9cG6dFO5ugU(q^eus8_Bnk~d zPT1&}6_S4s_WEVH6c+ds_BtBMcn?-_bEE!IV%StTbKnOyWQ~|dYMloYa-gwSy!X$| zB$Ryz?|g^OJB)tJ^1j`H&orc`rbICXb~@t3h6)5ma1uiWd?N({1MrXeXlNN0tk;}5 z5IM`~newzE{CuBkuEOuSB_c@PLE~9>&rwp4;c>?IO2Vhdt!NcHUGnJx|EA4St4c24 zCn^@b9?O8$*?_1Ys@DKvqhXBq%B5m~yk$UY_s(=Zbi~QF5|v0m?Moy99Q984N&F)F zm$5c_s$xeT>!RT_A}UPP@itYRj|?U&KO)Po+UrNBESo z?|#hqw`Z0$_wD-PV_bV9Xp4t&t9OnYuZk5fuE!lJSfD?#Ay>9IHMSwwGeMWJSZA&* zhatcE;Tw5=Q59?{fmM5s|7rS!+nGM*YS2Qq+I(tQZO6X*thil8eSBC?M8APl=mwb# z>^RDXiCy+-SGU@tO*B`q?w!0NR=L|tst^c8LfEV0SdbUY)p4-O3r^$#k%2y`q4E%E z!waP4Y1p-C2IDD&db^?V+TYt{OUKuLKcDOn1I!2QnG1llpz*X9gW3Pp4tK}e&X;q( zy3-{s_j-x7<|(x8(wSKQ4)W4)X#~DuURU{-aMf1SR}@#%q25$!3H z;SKqDR(;O*Y9gt>t6HGT06kfps@S}ztGr-F2GLgnA|)iI$GK9Ewx*_uYI<1ZKDxeV zYXa{={~}Z*!ZtDm45OKxexL*cEIIS0s`p@J%?n31wHu&q%L(*>JRmVDjfRHYgPFes z5^CfF{J5Z6|J1%;Twm1gc|9YmUumP$#ORUkxvQsLMPzt< zf+d6xOq(+KLsAWiK8JpTX!ijmwhDtf#3h*iW}|fR4CiBD<6qOc(GgXh#OR1X^KEg8 zw62Uf=cyKww26;GwBcJ`YD5C*MVc0Kcb0yQ729-Yz)r!v{M8%+;GL7VbzmJpIg|>5Y3*{1iK1BI_s7U;%}LIWLpbIw49y{Oy||o{4#Lw_$-299j>f-x!^COStj5t0O$=on86g&{&hdB% z)>s`H_se}!1MzgC@u`+XO?{`MCZuP8+RbQ)e5(90bBsjnG2Q+Qo*v#g6wS0C?$J{`MZ84|@5buc`0&7X-0i2la@20=D1EaquN5^*zk(X~2zi_-az=9Q; z$6}on1%9(BG}sY;!P0>^IS_F_7(@vyHh7rk?qKpaURG}LRkWuB)_`f1t-g@{tEM(| zL_UM64;=NfM_b;+|0c9l#?c`I1lYn0v`ro{=FE0i{O-hR_UiR|$Uu>UYg!{tdM!eG zyLUKk`mV1ZO(BsX64k2GKq?S)!VCJ-UDOe8D?jeN7JO$UTE!mBU(rtSPhYhoO?tHB zz0^HeiyVR+O&`ogemEcPPUf`UCzL<#J_6IHVqz9t>SnDKiao*eFDAqd;UoqMc!u9N zNV-Pgi@jFfe4->%f$IgKyq|O;S~HnI#7o$55epH=iab~Ma(n8Hwto0v$o-K_pwcpWa)d_I;M(-keMi`KBbRhbe zsLNJyfF_^FlNP7Tbx+v5Wqg00san3G3hMK!rK_o)&i;ZLI}%J))B8R8Ak2yf>c@&6 zZ6gbRhRT$pl9---T?=w~6D^C=BV|WhILcu+z1jEM`2{!EsPTy)N7u&Xw1x&_;9E^= z^5SrTw?u}XTY3p?)no=1{*2WC4nFysuENky2)AVd8;zP_Ee1Jnt06`8gANM`YTftz zRB-JZi-UpqKpo-3TP-=-77qiPHnWI+5tlPze|qy&Q_G@(u@bQ*97&=VBZ`whY*0N5 zQZ*s4@5%zw`7vZ^`^~-VzO;El@1mbSUf$4)!L*(5#sQLan&rcF490$tZG8*x.! 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.! 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 nL!kVqlF@Jh7Ky_ + + + Mifos Pay + Home + Payments + Finance + Profile + Settings + ⚠️ You aren’t connected to the internet + FAQ + + \ No newline at end of file diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt new file mode 100644 index 000000000..20ae14177 --- /dev/null +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.shared + +import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi +import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.compose.rememberNavController +import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneMonitor +import org.mifospay.core.designsystem.theme.MifosTheme +import org.mifospay.core.ui.LocalTimeZone +import org.mifospay.shared.MainUiState.Success +import org.mifospay.shared.navigation.MifosNavGraph.LOGIN_GRAPH +import org.mifospay.shared.navigation.MifosNavGraph.MAIN_GRAPH +import org.mifospay.shared.navigation.RootNavGraph +import org.mifospay.shared.ui.rememberMifosAppState + +@Composable +fun MifosPaySharedApp( + modifier: Modifier = Modifier, + networkMonitor: NetworkMonitor = koinInject(), + timeZoneMonitor: TimeZoneMonitor = koinInject(), +) { + MifosPayApp(modifier, networkMonitor, timeZoneMonitor) +} + +@OptIn(ExperimentalMaterial3WindowSizeClassApi::class) +@Composable +private fun MifosPayApp( + modifier: Modifier = Modifier, + networkMonitor: NetworkMonitor, + timeZoneMonitor: TimeZoneMonitor, + viewModel: MifosPayViewModel = koinViewModel(), +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val navController = rememberNavController() + + val appState = rememberMifosAppState( + windowSizeClass = calculateWindowSizeClass(), + networkMonitor = networkMonitor, + timeZoneMonitor = timeZoneMonitor, + ) + + val currentTimeZone by appState.currentTimeZone.collectAsStateWithLifecycle() + + val navDestination = when (uiState) { + is MainUiState.Loading -> LOGIN_GRAPH + is Success -> if ((uiState as Success).userData.authenticated) { + MAIN_GRAPH + } else { + LOGIN_GRAPH + } + } + + CompositionLocalProvider( + LocalTimeZone provides currentTimeZone, + ) { + MifosTheme { + RootNavGraph( + appState = appState, + navHostController = navController, + startDestination = navDestination, + modifier = modifier, + onClickLogout = { + viewModel.logOut() + navController.navigate(LOGIN_GRAPH) { + popUpTo(navController.graph.id) { + inclusive = true + } + } + }, + ) + } + } +} diff --git a/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt similarity index 54% rename from mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt index 165bf0451..634d6eb60 100644 --- a/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt @@ -7,41 +7,38 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay +package org.mifospay.shared import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import org.mifospay.core.model.UserData import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import org.mifos.library.passcode.data.PasscodeManager -import org.mifospay.core.data.repository.auth.UserDataRepository +import org.mifospay.core.datastore.UserPreferencesRepository +import org.mifospay.core.model.UserInfo -class MainActivityViewModel( - private val userDataRepository: UserDataRepository, - private val passcodeManager: PasscodeManager, +class MifosPayViewModel( + private val userDataRepository: UserPreferencesRepository, ) : ViewModel() { - - val uiState: StateFlow = userDataRepository.userData.map { - MainActivityUiState.Success(it) + val uiState: StateFlow = userDataRepository.userInfo.map { + MainUiState.Success(it) }.stateIn( scope = viewModelScope, - initialValue = MainActivityUiState.Loading, + initialValue = MainUiState.Loading, started = SharingStarted.WhileSubscribed(5_000), ) fun logOut() { viewModelScope.launch { userDataRepository.logOut() - passcodeManager.clearPasscode() +// passcodeManager.clearPasscode() } } } -sealed interface MainActivityUiState { - data object Loading : MainActivityUiState - data class Success(val userData: UserData) : MainActivityUiState +sealed interface MainUiState { + data object Loading : MainUiState + data class Success(val userData: UserInfo) : MainUiState } diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt new file mode 100644 index 000000000..042388040 --- /dev/null +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.shared.di + +import org.koin.core.context.startKoin +import org.koin.core.module.dsl.viewModelOf +import org.koin.dsl.KoinAppDeclaration +import org.koin.dsl.koinApplication +import org.koin.dsl.module +import org.mifospay.core.common.di.DispatchersModule +import org.mifospay.core.data.di.RepositoryModule +import org.mifospay.core.datastore.di.PreferencesModule +import org.mifospay.core.domain.di.DomainModule +import org.mifospay.core.network.di.LocalModule +import org.mifospay.core.network.di.NetworkModule +import org.mifospay.feature.auth.di.AuthModule +import org.mifospay.shared.MifosPayViewModel + +object KoinModules { + private val commonModules = module { + includes(DispatchersModule) + } + private val dataModules = module { + includes(RepositoryModule) + } + private val domainModules = module { + includes(DomainModule) + } + private val coreDataStoreModules = module { + includes(PreferencesModule) + } + private val networkModules = module { + includes(LocalModule, NetworkModule) + } + private val sharedModule = module { + viewModelOf(::MifosPayViewModel) + } + private val featureModules = module { + includes( + AuthModule, + ) + } + + val allModules = listOf( + commonModules, + dataModules, + domainModules, + coreDataStoreModules, + networkModules, + featureModules, + sharedModule, + ) +} + +fun koinConfiguration() = koinApplication { + modules(KoinModules.allModules) +} + +fun initKoin(config: KoinAppDeclaration? = null) { + startKoin { + config?.invoke(this) + modules(KoinModules.allModules) + } +} diff --git a/mifospay/src/main/java/org/mifospay/navigation/LoginNavGraph.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/LoginNavGraph.kt similarity index 55% rename from mifospay/src/main/java/org/mifospay/navigation/LoginNavGraph.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/LoginNavGraph.kt index 4daf2ca6b..fdf8ac1de 100644 --- a/mifospay/src/main/java/org/mifospay/navigation/LoginNavGraph.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/LoginNavGraph.kt @@ -7,18 +7,19 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.navigation +package org.mifospay.shared.navigation import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.navigation -import org.mifos.library.passcode.navigateToPasscodeScreen -import org.mifospay.core.common.Constants import org.mifospay.feature.auth.navigation.LOGIN_ROUTE import org.mifospay.feature.auth.navigation.loginScreen import org.mifospay.feature.auth.navigation.mobileVerificationScreen +import org.mifospay.feature.auth.navigation.navigateToLogin import org.mifospay.feature.auth.navigation.navigateToSignup import org.mifospay.feature.auth.navigation.signupScreen +import org.mifospay.feature.auth.socialSignup.navigateToSignupMethod +import org.mifospay.feature.auth.socialSignup.signupMethodScreen internal fun NavGraphBuilder.loginNavGraph(navController: NavController) { navigation( @@ -26,26 +27,28 @@ internal fun NavGraphBuilder.loginNavGraph(navController: NavController) { startDestination = LOGIN_ROUTE, ) { loginScreen( - onNavigateToPasscodeScreen = navController::navigateToPasscodeScreen, - onNavigateToSignupScreen = navController::navigateToSignup, + onNavigateBack = navController::popBackStack, + // TODO:: we should navigate to passcode graph + onNavigateToPasscodeScreen = navController::navigateToMainGraph, + onNavigateToSignupScreen = navController::navigateToSignupMethod, + ) + + signupMethodScreen( + onNavigateBack = navController::popBackStack, + onNavigateToSignUp = { + navController.navigateToSignup(savingsProductId = it) + }, ) signupScreen( - onLoginSuccess = navController::navigateToPasscodeScreen, - onRegisterSuccess = navController::navigateToPasscodeScreen, + onNavigateBack = navController::popBackStack, + onNavigateToLogin = navController::navigateToLogin, ) mobileVerificationScreen( - onOtpVerificationSuccess = { fullNumber, extraData -> - navController.navigateToSignup( - savingProductId = extraData[Constants.MIFOS_SAVINGS_PRODUCT_ID] as Int, - mobileNumber = fullNumber, - country = "Canada", - email = extraData[Constants.GOOGLE_EMAIL] as? String ?: "", - firstName = extraData[Constants.GOOGLE_GIVEN_NAME] as? String ?: "", - lastName = extraData[Constants.GOOGLE_FAMILY_NAME] as? String ?: "", - businessName = extraData[Constants.GOOGLE_DISPLAY_NAME] as? String ?: "", - ) + onNavigateBack = navController::popBackStack, + onOtpVerificationSuccess = { fullNumber -> + navController.navigateToSignup(mobileNumber = fullNumber) }, ) } diff --git a/mifospay/src/main/java/org/mifospay/navigation/MifosNavGraph.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavGraph.kt similarity index 93% rename from mifospay/src/main/java/org/mifospay/navigation/MifosNavGraph.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavGraph.kt index ffb539627..e3b852f6f 100644 --- a/mifospay/src/main/java/org/mifospay/navigation/MifosNavGraph.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavGraph.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.navigation +package org.mifospay.shared.navigation internal object MifosNavGraph { const val ROOT_GRAPH = "root_graph" diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavHost.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavHost.kt new file mode 100644 index 000000000..c11c5236f --- /dev/null +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavHost.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.shared.navigation + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.navigation.NavController +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navOptions +import org.mifospay.shared.ui.MifosAppState + +@Composable +internal fun MifosNavHost( + appState: MifosAppState, + onClickLogout: () -> Unit, + modifier: Modifier = Modifier, +) { + val navController = rememberNavController() + + NavHost( + route = MifosNavGraph.MAIN_GRAPH, + // HOME_ROUTE, + startDestination = "home_route", + navController = navController, + modifier = modifier, + ) { + composable(route = "home_route") { + HomeScreen( + modifier = Modifier, + onClickLogout = onClickLogout, + ) + } + } +} + +// TODO:: This could be removed, just added for testing +@Composable +private fun HomeScreen( + modifier: Modifier = Modifier, + onClickLogout: () -> Unit, +) { + Box( + modifier = modifier + .fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + Text(text = "Home Screen") + } +} + +internal fun NavController.navigateToHomeScreen() { + this.navigate("home_route") +} + +internal fun NavController.navigateToMainGraph() { + val options = navOptions { + // Pop up to the start destination of the graph to + // avoid building up a large stack of destinations + // on the back stack as users select items + popUpTo(graph.findStartDestination().id) { + saveState = false + } + // Avoid multiple copies of the same destination when + // reselecting the same item + launchSingleTop = true + // Restore state when reselecting a previously selected item + restoreState = false + } + + navigate(MifosNavGraph.MAIN_GRAPH, options) +} diff --git a/mifospay/src/main/java/org/mifospay/navigation/RootNavGraph.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/RootNavGraph.kt similarity index 87% rename from mifospay/src/main/java/org/mifospay/navigation/RootNavGraph.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/RootNavGraph.kt index 1a0735b28..be68108c2 100644 --- a/mifospay/src/main/java/org/mifospay/navigation/RootNavGraph.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/RootNavGraph.kt @@ -7,15 +7,15 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.navigation +package org.mifospay.shared.navigation import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable -import org.mifospay.ui.MifosApp -import org.mifospay.ui.MifosAppState +import org.mifospay.shared.ui.MifosApp +import org.mifospay.shared.ui.MifosAppState @Composable internal fun RootNavGraph( @@ -33,7 +33,7 @@ internal fun RootNavGraph( ) { loginNavGraph(navHostController) - passcodeNavGraph(navHostController) +// passcodeNavGraph(navHostController) composable(MifosNavGraph.MAIN_GRAPH) { MifosApp( diff --git a/mifospay/src/main/java/org/mifospay/ui/MifosApp.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosApp.kt similarity index 72% rename from mifospay/src/main/java/org/mifospay/ui/MifosApp.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosApp.kt index 49dcccfc9..628385980 100644 --- a/mifospay/src/main/java/org/mifospay/ui/MifosApp.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosApp.kt @@ -7,9 +7,8 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.ui +package org.mifospay.shared.ui -import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -18,17 +17,17 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.safeDrawingPadding import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarDuration.Indefinite @@ -43,55 +42,45 @@ 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.composed import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavDestination import androidx.navigation.NavDestination.Companion.hierarchy -import org.mifospay.R +import mobile_wallet.mifospay_shared.generated.resources.Res +import mobile_wallet.mifospay_shared.generated.resources.faq +import mobile_wallet.mifospay_shared.generated.resources.not_connected +import mobile_wallet.mifospay_shared.generated.resources.settings +import org.jetbrains.compose.resources.stringResource import org.mifospay.core.designsystem.component.MifosBackground import org.mifospay.core.designsystem.component.MifosGradientBackground import org.mifospay.core.designsystem.component.MifosNavigationBar import org.mifospay.core.designsystem.component.MifosNavigationBarItem import org.mifospay.core.designsystem.component.MifosNavigationRail import org.mifospay.core.designsystem.component.MifosNavigationRailItem -import org.mifospay.core.designsystem.component.MifosTopAppBar import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.GradientColors import org.mifospay.core.designsystem.theme.LocalGradientColors -import org.mifospay.feature.faq.navigation.navigateToFAQ -import org.mifospay.feature.settings.navigation.navigateToSettings -import org.mifospay.navigation.MifosNavHost -import org.mifospay.navigation.TopLevelDestination +import org.mifospay.shared.navigation.MifosNavHost +import org.mifospay.shared.utils.TopLevelDestination -@OptIn( - ExperimentalMaterial3Api::class, - ExperimentalComposeUiApi::class, -) @Composable -fun MifosApp( +internal fun MifosApp( appState: MifosAppState, onClickLogout: () -> Unit, modifier: Modifier = Modifier, ) { val shouldShowGradientBackground = appState.currentTopLevelDestination == TopLevelDestination.HOME - var showHomeMenuOption by rememberSaveable { mutableStateOf(false) } MifosBackground(modifier) { MifosGradientBackground( - gradientColors = - if (shouldShowGradientBackground) { + gradientColors = if (shouldShowGradientBackground) { LocalGradientColors.current } else { GradientColors() @@ -102,7 +91,7 @@ fun MifosApp( val isOffline by appState.isOffline.collectAsStateWithLifecycle() // If user is not connected to the internet show a snack bar to inform them. - val notConnectedMessage = stringResource(R.string.not_connected) + val notConnectedMessage = stringResource(Res.string.not_connected) LaunchedEffect(isOffline) { if (isOffline) { snackbarHostState.showSnackbar( @@ -112,54 +101,8 @@ fun MifosApp( } } - if (showHomeMenuOption) { - AnimatedVisibility(true) { - Box( - modifier = - Modifier - .fillMaxWidth() - .wrapContentSize(Alignment.TopEnd) - .padding(end = 24.dp) - .background(color = MaterialTheme.colorScheme.surface), - ) { - DropdownMenu( - modifier = Modifier.background(color = MaterialTheme.colorScheme.surface), - expanded = showHomeMenuOption, - onDismissRequest = { showHomeMenuOption = false }, - ) { - DropdownMenuItem( - text = { - Text( - stringResource(id = R.string.faq), - color = MaterialTheme.colorScheme.onSurface, - ) - }, - onClick = { - showHomeMenuOption = false - appState.navController.navigateToFAQ() - }, - ) - DropdownMenuItem( - text = { - Text( - stringResource(id = R.string.feature_profile_settings), - color = MaterialTheme.colorScheme.onSurface, - ) - }, - onClick = { - showHomeMenuOption = false - appState.navController.navigateToSettings() - }, - ) - } - } - } - } - Scaffold( - modifier = Modifier.semantics { - testTagsAsResourceId = true - }, + modifier = Modifier, containerColor = Color.Transparent, contentColor = MaterialTheme.colorScheme.onBackground, snackbarHost = { SnackbarHost(snackbarHostState) }, @@ -203,18 +146,11 @@ fun MifosApp( // Show the top app bar on top level destinations. val destination = appState.currentTopLevelDestination if (destination != null) { - MifosTopAppBar( - titleRes = destination.titleTextId, - actionIcon = MifosIcons.MoreVert, - actionIconContentDescription = - stringResource( - id = R.string.feature_profile_settings, - ), - colors = - TopAppBarDefaults.centerAlignedTopAppBarColors( - containerColor = Color.Transparent, - ), - onActionClick = { showHomeMenuOption = true }, + MifosAppBar( + title = stringResource(destination.titleText), + onClickLogout = onClickLogout, + onNavigateToFaq = {}, + onNavigateToSettings = {}, ) } @@ -229,6 +165,101 @@ fun MifosApp( } } +@Composable +private fun HomeMenu( + showHomeMenuOption: Boolean, + onDismissRequest: () -> Unit, + onClickLogout: () -> Unit, + onNavigateToFaq: () -> Unit, + onNavigateToSettings: () -> Unit, + modifier: Modifier = Modifier, +) { + DropdownMenu( + modifier = modifier.background(color = MaterialTheme.colorScheme.surface), + expanded = showHomeMenuOption, + onDismissRequest = onDismissRequest, + ) { + DropdownMenuItem( + text = { + Text( + text = stringResource(Res.string.faq), + color = MaterialTheme.colorScheme.onSurface, + ) + }, + onClick = { + onDismissRequest() + onNavigateToFaq() + }, + ) + + DropdownMenuItem( + text = { + Text( + text = stringResource(Res.string.settings), + color = MaterialTheme.colorScheme.onSurface, + ) + }, + onClick = { + onDismissRequest() + onNavigateToSettings() + }, + ) + + // TODO:: this could be removed, just added for testing + DropdownMenuItem( + text = { + Text( + text = "Logout", + color = MaterialTheme.colorScheme.onSurface, + ) + }, + onClick = { + onDismissRequest() + onClickLogout() + }, + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun MifosAppBar( + title: String, + onClickLogout: () -> Unit, + onNavigateToFaq: () -> Unit, + onNavigateToSettings: () -> Unit, + modifier: Modifier = Modifier, +) { + var showHomeMenuOption by rememberSaveable { mutableStateOf(false) } + + CenterAlignedTopAppBar( + title = { Text(text = title) }, + actions = { + Box { + IconButton(onClick = { showHomeMenuOption = true }) { + Icon( + imageVector = MifosIcons.MoreVert, + contentDescription = "View More", + tint = MaterialTheme.colorScheme.onSurface, + ) + } + + HomeMenu( + showHomeMenuOption = showHomeMenuOption, + onDismissRequest = { showHomeMenuOption = false }, + onClickLogout = onClickLogout, + onNavigateToFaq = onNavigateToFaq, + onNavigateToSettings = onNavigateToSettings, + ) + } + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = Color.Transparent, + ), + modifier = modifier.testTag("mifosTopAppBar"), + ) +} + @Composable private fun MifosNavRail( destinations: List, @@ -257,7 +288,7 @@ private fun MifosNavRail( contentDescription = null, ) }, - label = { Text(stringResource(destination.iconTextId)) }, + label = { Text(stringResource(destination.iconText)) }, ) } } @@ -293,7 +324,7 @@ private fun MifosBottomBar( contentDescription = null, ) }, - label = { Text(stringResource(destination.iconTextId)) }, + label = { Text(stringResource(destination.iconText)) }, ) } } diff --git a/mifospay/src/main/java/org/mifospay/ui/MifosAppState.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosAppState.kt similarity index 57% rename from mifospay/src/main/java/org/mifospay/ui/MifosAppState.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosAppState.kt index e155ef1bd..a599ab6e1 100644 --- a/mifospay/src/main/java/org/mifospay/ui/MifosAppState.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosAppState.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.ui +package org.mifospay.shared.ui import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass @@ -15,16 +15,13 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.navigation.NavController +import androidx.compose.ui.util.trace import androidx.navigation.NavDestination import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions -import androidx.tracing.trace -import com.mifos.library.material3.navigation.BottomSheetNavigator -import com.mifos.library.material3.navigation.rememberBottomSheetNavigator import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map @@ -32,30 +29,18 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.datetime.TimeZone import org.mifospay.core.data.util.NetworkMonitor import org.mifospay.core.data.util.TimeZoneMonitor -import org.mifospay.core.ui.TrackDisposableJank -import org.mifospay.feature.finance.navigation.FINANCE_ROUTE -import org.mifospay.feature.finance.navigation.navigateToFinance -import org.mifospay.feature.home.navigation.HOME_ROUTE -import org.mifospay.feature.home.navigation.navigateToHome -import org.mifospay.feature.payments.PAYMENTS_ROUTE -import org.mifospay.feature.payments.navigateToPayments -import org.mifospay.feature.profile.navigation.PROFILE_ROUTE -import org.mifospay.feature.profile.navigation.navigateToProfile -import org.mifospay.navigation.TopLevelDestination +import org.mifospay.shared.utils.TopLevelDestination @Composable -fun rememberMifosAppState( +internal fun rememberMifosAppState( windowSizeClass: WindowSizeClass, networkMonitor: NetworkMonitor, timeZoneMonitor: TimeZoneMonitor, coroutineScope: CoroutineScope = rememberCoroutineScope(), - bottomSheetNavigator: BottomSheetNavigator = rememberBottomSheetNavigator(), - navController: NavHostController = rememberNavController(bottomSheetNavigator), + navController: NavHostController = rememberNavController(), ): MifosAppState { - NavigationTrackingSideEffect(navController) return remember( navController, - bottomSheetNavigator, coroutineScope, windowSizeClass, networkMonitor, @@ -63,7 +48,6 @@ fun rememberMifosAppState( ) { MifosAppState( navController = navController, - bottomSheetNavigator = bottomSheetNavigator, coroutineScope = coroutineScope, windowSizeClass = windowSizeClass, networkMonitor = networkMonitor, @@ -73,9 +57,8 @@ fun rememberMifosAppState( } @Stable -class MifosAppState( +internal class MifosAppState( val navController: NavHostController, - val bottomSheetNavigator: BottomSheetNavigator, coroutineScope: CoroutineScope, val windowSizeClass: WindowSizeClass, networkMonitor: NetworkMonitor, @@ -87,11 +70,11 @@ class MifosAppState( val currentTopLevelDestination: TopLevelDestination? @Composable get() = when (currentDestination?.route) { - HOME_ROUTE -> TopLevelDestination.HOME - PAYMENTS_ROUTE -> TopLevelDestination.PAYMENTS - FINANCE_ROUTE -> TopLevelDestination.FINANCE - PROFILE_ROUTE -> TopLevelDestination.PROFILE - else -> null +// HOME_ROUTE -> TopLevelDestination.HOME +// PAYMENTS_ROUTE -> TopLevelDestination.PAYMENTS +// FINANCE_ROUTE -> TopLevelDestination.FINANCE +// PROFILE_ROUTE -> TopLevelDestination.PROFILE + else -> TopLevelDestination.HOME } val shouldShowBottomBar: Boolean @@ -108,10 +91,6 @@ class MifosAppState( initialValue = false, ) - /** - * Map of top level destinations to be used in the TopBar, BottomBar and NavRail. The key is the - * route. - */ val topLevelDestinations: List = TopLevelDestination.entries val currentTimeZone = timeZoneMonitor.currentTimeZone @@ -121,13 +100,6 @@ class MifosAppState( TimeZone.currentSystemDefault(), ) - /** - * UI logic for navigating to a top level destination in the app. Top level destinations have - * only one copy of the destination of the back stack, and save and restore state whenever you - * navigate to and from it. - * - * @param topLevelDestination: The destination the app needs to navigate to. - */ fun navigateToTopLevelDestination(topLevelDestination: TopLevelDestination) { trace("Navigation: ${topLevelDestination.name}") { val topLevelNavOptions = navOptions { @@ -145,29 +117,12 @@ class MifosAppState( } when (topLevelDestination) { - TopLevelDestination.HOME -> navController.navigateToHome(topLevelNavOptions) - TopLevelDestination.PAYMENTS -> navController.navigateToPayments(topLevelNavOptions) - TopLevelDestination.FINANCE -> navController.navigateToFinance(topLevelNavOptions) - TopLevelDestination.PROFILE -> navController.navigateToProfile(topLevelNavOptions) +// TopLevelDestination.HOME -> navController.navigateToHome(topLevelNavOptions) +// TopLevelDestination.PAYMENTS -> navController.navigateToPayments(topLevelNavOptions) +// TopLevelDestination.FINANCE -> navController.navigateToFinance(topLevelNavOptions) +// TopLevelDestination.PROFILE -> navController.navigateToProfile(topLevelNavOptions) + else -> Unit } } } } - -/** - * Stores information about navigation events to be used with JankStats - */ -@Composable -private fun NavigationTrackingSideEffect(navController: NavHostController) { - TrackDisposableJank(navController) { metricsHolder -> - val listener = NavController.OnDestinationChangedListener { _, destination, _ -> - metricsHolder.state?.putState("Navigation", destination.route.toString()) - } - - navController.addOnDestinationChangedListener(listener) - - onDispose { - navController.removeOnDestinationChangedListener(listener) - } - } -} diff --git a/mifospay/src/main/java/org/mifospay/navigation/TopLevelDestination.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/utils/TopLevelDestination.kt similarity index 57% rename from mifospay/src/main/java/org/mifospay/navigation/TopLevelDestination.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/utils/TopLevelDestination.kt index 84f0d3462..907fb0092 100644 --- a/mifospay/src/main/java/org/mifospay/navigation/TopLevelDestination.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/utils/TopLevelDestination.kt @@ -7,10 +7,16 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.navigation +package org.mifospay.shared.utils import androidx.compose.ui.graphics.vector.ImageVector -import org.mifospay.R +import mobile_wallet.mifospay_shared.generated.resources.Res +import mobile_wallet.mifospay_shared.generated.resources.app_name +import mobile_wallet.mifospay_shared.generated.resources.finance +import mobile_wallet.mifospay_shared.generated.resources.home +import mobile_wallet.mifospay_shared.generated.resources.payments +import mobile_wallet.mifospay_shared.generated.resources.profile +import org.jetbrains.compose.resources.StringResource import org.mifospay.core.designsystem.icon.MifosIcons /** @@ -18,34 +24,34 @@ import org.mifospay.core.designsystem.icon.MifosIcons * can contain one or more screens (based on the window size). Navigation from one screen to the * next within a single destination will be handled directly in composables. */ -enum class TopLevelDestination( +internal enum class TopLevelDestination( val selectedIcon: ImageVector, val unselectedIcon: ImageVector, - val iconTextId: Int, - val titleTextId: Int, + val iconText: StringResource, + val titleText: StringResource, ) { HOME( selectedIcon = MifosIcons.Home, unselectedIcon = MifosIcons.HomeBoarder, - iconTextId = R.string.home, - titleTextId = R.string.app_name, + iconText = Res.string.home, + titleText = Res.string.app_name, ), PAYMENTS( selectedIcon = MifosIcons.Payment, unselectedIcon = MifosIcons.Payment, - iconTextId = R.string.payments, - titleTextId = R.string.payments, + iconText = Res.string.payments, + titleText = Res.string.payments, ), FINANCE( selectedIcon = MifosIcons.Finance, unselectedIcon = MifosIcons.FinanceBoarder, - iconTextId = R.string.finance, - titleTextId = R.string.finance, + iconText = Res.string.finance, + titleText = Res.string.finance, ), PROFILE( selectedIcon = MifosIcons.Profile, unselectedIcon = MifosIcons.ProfileBoarder, - iconTextId = R.string.profile, - titleTextId = R.string.profile, + iconText = Res.string.profile, + titleText = Res.string.profile, ), } diff --git a/mifospay-web/.gitignore b/mifospay-web/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/mifospay-web/.gitignore @@ -0,0 +1 @@ +/build diff --git a/mifospay-web/README.md b/mifospay-web/README.md new file mode 100644 index 000000000..1dd276e64 --- /dev/null +++ b/mifospay-web/README.md @@ -0,0 +1,3 @@ +To run in web mode, choose the `mifospay-web-js` or `mifospay-web-wasm` profile and click run. + +_When running as WasmJs it will take some time to compile the webpack, so be patient._ \ No newline at end of file diff --git a/mifospay-web/build.gradle.kts b/mifospay-web/build.gradle.kts new file mode 100644 index 000000000..3be809017 --- /dev/null +++ b/mifospay-web/build.gradle.kts @@ -0,0 +1,62 @@ +import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig + +plugins { + alias(libs.plugins.kotlinMultiplatform) + alias(libs.plugins.jetbrainsCompose) + alias(libs.plugins.compose.compiler) +} + +kotlin { + js(IR) { + moduleName = "mifospay-web" + browser { + commonWebpackConfig { + outputFileName = "mifospay-web.js" + } + } + binaries.executable() + } + + @OptIn(ExperimentalWasmDsl::class) + wasmJs { + moduleName = "mifoswasmapp" + val rootProject = project.rootDir.path + browser { + commonWebpackConfig { + outputFileName = "mifoswasmapp.js" + devServer = (devServer ?: KotlinWebpackConfig.DevServer(port = 8081)).apply { + static = (static ?: mutableListOf()).apply { + // Serve sources to debug inside browser + add("$rootProject/mifospay-web/") + } + } + } + } + binaries.executable() + } + + applyDefaultHierarchyTemplate() + + sourceSets { + val jsWasmMain by creating { + dependsOn(commonMain.get()) + dependencies { + implementation(projects.mifospayShared) + implementation(compose.runtime) + implementation(compose.ui) + implementation(compose.foundation) + implementation(compose.material3) + implementation(compose.components.resources) + } + } + + jsMain.get().dependsOn(jsWasmMain) + wasmJsMain.get().dependsOn(jsWasmMain) + } +} + +compose.resources { + publicResClass = true + generateResClass = always +} \ No newline at end of file diff --git a/mifospay-web/src/jsMain/kotlin/Application.kt b/mifospay-web/src/jsMain/kotlin/Application.kt new file mode 100644 index 000000000..a3d5d4954 --- /dev/null +++ b/mifospay-web/src/jsMain/kotlin/Application.kt @@ -0,0 +1,15 @@ + +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.window.ComposeViewport +import kotlinx.browser.document +import org.mifospay.shared.MifosPaySharedApp +import org.mifospay.shared.di.initKoin + +@OptIn(ExperimentalComposeUiApi::class) +fun main() { + initKoin() + + ComposeViewport(document.body!!) { + MifosPaySharedApp() + } +} \ No newline at end of file diff --git a/mifospay-web/src/jsMain/resources/index.html b/mifospay-web/src/jsMain/resources/index.html new file mode 100644 index 000000000..5df6be6fb --- /dev/null +++ b/mifospay-web/src/jsMain/resources/index.html @@ -0,0 +1,15 @@ + + + + + Mifos Wallet + + + + +
+ + +
+ + \ No newline at end of file diff --git a/mifospay-web/src/jsMain/resources/styles.css b/mifospay-web/src/jsMain/resources/styles.css new file mode 100644 index 000000000..3e82a3d56 --- /dev/null +++ b/mifospay-web/src/jsMain/resources/styles.css @@ -0,0 +1,14 @@ +html, body { + height: 100%; + margin: 0px; + padding: 0px; +} + +canvas { + width: 100vw; + height: 100vh; + display: block; + position: fixed; + top: 0; + left: 0; +} \ No newline at end of file diff --git a/mifospay-web/src/wasmJsMain/kotlin/Main.kt b/mifospay-web/src/wasmJsMain/kotlin/Main.kt new file mode 100644 index 000000000..8c3a22232 --- /dev/null +++ b/mifospay-web/src/wasmJsMain/kotlin/Main.kt @@ -0,0 +1,16 @@ +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.window.CanvasBasedWindow +import org.mifospay.shared.MifosPaySharedApp +import org.mifospay.shared.di.initKoin + +@OptIn(ExperimentalComposeUiApi::class) +fun main() { + initKoin() + + CanvasBasedWindow( + title = "MifosWallet", + canvasElementId = "root", + ) { + MifosPaySharedApp() + } +} \ No newline at end of file diff --git a/mifospay-web/src/wasmJsMain/resources/index.html b/mifospay-web/src/wasmJsMain/resources/index.html new file mode 100644 index 000000000..dc3ff4f8c --- /dev/null +++ b/mifospay-web/src/wasmJsMain/resources/index.html @@ -0,0 +1,27 @@ + + + + + + Mifos Wallet + + + + + + + + \ No newline at end of file diff --git a/mifospay-web/src/wasmJsMain/resources/load.mjs b/mifospay-web/src/wasmJsMain/resources/load.mjs new file mode 100644 index 000000000..eada049a3 --- /dev/null +++ b/mifospay-web/src/wasmJsMain/resources/load.mjs @@ -0,0 +1,5 @@ +import { instantiate } from './mifoswasmapp.uninstantiated.mjs'; + +await wasmSetup; + +instantiate({ skia: Module['asm'] }); \ No newline at end of file diff --git a/mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt b/mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt deleted file mode 100644 index 9abd02dd6..000000000 --- a/mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt +++ /dev/null @@ -1,2352 +0,0 @@ -+--- androidx.databinding:databinding-common:8.5.2 -+--- androidx.databinding:databinding-runtime:8.5.2 -| +--- androidx.collection:collection:1.0.0 -> 1.4.4 -| | \--- androidx.collection:collection-jvm:1.4.4 -| | +--- androidx.annotation:annotation:1.8.1 -| | | \--- androidx.annotation:annotation-jvm:1.8.1 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 -| | | +--- org.jetbrains:annotations:13.0 -> 23.0.0 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.0.0 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0 -> 2.0.0 (c) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:2.0.20 (c) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.collection:collection-ktx:1.4.4 (c) -| | \--- androidx.collection:collection-ktx:1.3.0 -> 1.4.4 (c) -| +--- androidx.databinding:databinding-common:8.5.2 -| +--- androidx.databinding:viewbinding:8.5.2 -| | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| \--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 -| \--- androidx.lifecycle:lifecycle-runtime-android:2.8.6 -| +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| +--- androidx.arch.core:core-common:2.2.0 -| | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| +--- androidx.arch.core:core-runtime:2.2.0 -| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | \--- androidx.arch.core:core-common:2.2.0 (*) -| +--- androidx.lifecycle:lifecycle-common:2.8.6 -| | \--- androidx.lifecycle:lifecycle-common-jvm:2.8.6 -| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 -| | | +--- org.jetbrains:annotations:23.0.0 -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.9.0 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0 (c) -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.9.0 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 -| | +--- androidx.annotation:annotation:1.8.1 (*) -| | +--- androidx.concurrent:concurrent-futures:1.1.0 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| | +--- androidx.startup:startup-runtime:1.1.1 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | \--- androidx.tracing:tracing:1.0.0 -> 1.3.0-alpha02 -| | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | \--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (c) -| | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -+--- androidx.databinding:databinding-adapters:8.5.2 -| +--- androidx.databinding:databinding-runtime:8.5.2 (*) -| \--- androidx.databinding:databinding-common:8.5.2 -+--- androidx.databinding:databinding-ktx:8.5.2 -| +--- androidx.databinding:databinding-runtime:8.5.2 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20 -> 2.0.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1 -> 1.9.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.6 -| | \--- androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.6 -| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata:2.6.1 -> 2.8.6 -| | +--- androidx.arch.core:core-common:2.2.0 (*) -| | +--- androidx.arch.core:core-runtime:2.2.0 (*) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 -| | | +--- androidx.arch.core:core-common:2.2.0 (*) -| | | +--- androidx.arch.core:core-runtime:2.2.0 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-process:2.6.1 -> 2.8.6 -| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) -| | +--- androidx.startup:startup-runtime:1.1.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-service:2.6.1 -> 2.8.6 -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| \--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 -| \--- androidx.lifecycle:lifecycle-viewmodel-android:2.8.6 -| +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -+--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -+--- androidx.compose:compose-bom:2024.09.02 -| +--- androidx.compose.material3:material3-window-size-class:1.3.0 (c) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) -| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) -| +--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) -| +--- androidx.compose.runtime:runtime:1.7.2 (c) -| +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| +--- androidx.compose.foundation:foundation:1.7.2 (c) -| +--- androidx.compose.foundation:foundation-layout:1.7.2 (c) -| +--- androidx.compose.material:material-icons-extended:1.7.2 (c) -| +--- androidx.compose.material3:material3:1.3.0 (c) -| +--- androidx.compose.ui:ui-util:1.7.2 (c) -| +--- androidx.compose.runtime:runtime-saveable:1.7.2 (c) -| +--- androidx.compose.ui:ui:1.7.2 (c) -| +--- androidx.compose.material3.adaptive:adaptive-android:1.0.0 (c) -| +--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 (c) -| +--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 (c) -| +--- androidx.compose.animation:animation:1.7.2 (c) -| +--- androidx.compose.material3:material3-window-size-class-android:1.3.0 (c) -| +--- androidx.compose.runtime:runtime-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-tooling-preview-android:1.7.2 (c) -| +--- androidx.compose.material:material:1.7.2 (c) -| +--- androidx.compose.animation:animation-graphics:1.7.2 (c) -| +--- androidx.compose.foundation:foundation-layout-android:1.7.2 (c) -| +--- androidx.compose.runtime:runtime-saveable-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-android:1.7.2 (c) -| +--- androidx.compose.foundation:foundation-android:1.7.2 (c) -| +--- androidx.compose.material:material-icons-extended-android:1.7.2 (c) -| +--- androidx.compose.material3:material3-android:1.3.0 (c) -| +--- androidx.compose.ui:ui-util-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| +--- androidx.compose.animation:animation-core:1.7.2 (c) -| +--- androidx.compose.animation:animation-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| +--- androidx.compose.material:material-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-geometry-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-unit-android:1.7.2 (c) -| +--- androidx.compose.animation:animation-graphics-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| +--- androidx.compose.ui:ui-text:1.7.2 (c) -| +--- androidx.compose.material:material-icons-core:1.7.2 (c) -| +--- androidx.compose.material:material-ripple:1.7.2 (c) -| +--- androidx.compose.animation:animation-core-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-graphics-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-text-android:1.7.2 (c) -| +--- androidx.compose.material:material-icons-core-android:1.7.2 (c) -| \--- androidx.compose.material:material-ripple-android:1.7.2 (c) -+--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 -| \--- androidx.compose.ui:ui-tooling-preview-android:1.7.2 -| +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| +--- androidx.compose.runtime:runtime:1.7.2 -| | \--- androidx.compose.runtime:runtime-android:1.7.2 -| | +--- androidx.annotation:annotation-experimental:1.4.1 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) -| | +--- androidx.collection:collection:1.4.4 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | \--- androidx.compose.runtime:runtime-saveable:1.7.2 (c) -| +--- androidx.compose.ui:ui:1.7.2 (c) -| +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| +--- androidx.compose.ui:ui-util:1.7.2 (c) -| +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| \--- androidx.compose.ui:ui-text:1.7.2 (c) -+--- com.google.firebase:firebase-bom:33.3.0 -| +--- com.google.firebase:firebase-perf-ktx:21.0.1 (c) -| +--- com.google.firebase:firebase-crashlytics-ktx:19.1.0 (c) -| +--- com.google.firebase:firebase-analytics-ktx:22.1.0 (c) -| +--- com.google.firebase:firebase-messaging-ktx:24.0.1 (c) -| +--- com.google.firebase:firebase-perf:21.0.1 (c) -| +--- com.google.firebase:firebase-common:21.0.0 (c) -| +--- com.google.firebase:firebase-common-ktx:21.0.0 (c) -| +--- com.google.firebase:firebase-crashlytics:19.1.0 (c) -| +--- com.google.firebase:firebase-analytics:22.1.0 (c) -| +--- com.google.firebase:firebase-messaging:24.0.1 (c) -| +--- com.google.firebase:firebase-encoders:17.0.0 (c) -| +--- com.google.firebase:firebase-config:22.0.0 (c) -| \--- com.google.firebase:firebase-installations:18.0.0 (c) -+--- com.google.firebase:firebase-analytics-ktx -> 22.1.0 -| +--- com.google.firebase:firebase-analytics:22.1.0 -| | +--- com.google.android.gms:play-services-measurement:22.1.0 -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | +--- androidx.legacy:legacy-support-core-utils:1.0.0 -| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | +--- androidx.core:core:1.0.0 -> 1.13.1 -| | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) -| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | | | | +--- androidx.interpolator:interpolator:1.0.0 -| | | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 -> 2.8.6 (*) -| | | | | +--- androidx.versionedparcelable:versionedparcelable:1.1.1 -| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | \--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | \--- androidx.core:core-ktx:1.13.1 (c) -| | | | +--- androidx.documentfile:documentfile:1.0.0 -| | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 -| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0 -> 2.8.6 (*) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.8.6 (*) -| | | | | \--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | +--- androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 -| | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | \--- androidx.print:print:1.0.0 -| | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 -| | | | \--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core:1.2.0 -> 1.13.1 (*) -| | | | \--- androidx.fragment:fragment:1.1.0 -> 1.8.2 -| | | | +--- androidx.activity:activity:1.8.1 -> 1.9.2 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | | +--- androidx.core:core:1.13.0 -> 1.13.1 (*) -| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.6 -| | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.core:core:1.13.1 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | \--- androidx.core:core:1.13.1 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) -| | | | | | +--- androidx.savedstate:savedstate:1.2.1 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.8.6 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) -| | | | | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | | | | \--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | +--- androidx.tracing:tracing:1.0.0 -> 1.3.0-alpha02 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- androidx.activity:activity-compose:1.9.2 (c) -| | | | | \--- androidx.activity:activity-ktx:1.9.2 (c) -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) -| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.1 -> 2.8.6 (*) -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.6 (*) -| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 (*) -| | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | +--- androidx.viewpager:viewpager:1.0.0 -| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | | | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) -| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | \--- androidx.fragment:fragment-ktx:1.8.2 (c) -| | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 -| | | | \--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-impl:22.1.0 -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core:1.9.0 -> 1.13.1 (*) -| | | | +--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 -| | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core-ktx:1.8.0 -> 1.13.1 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | | \--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 (c) -| | | | +--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 -| | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | | +--- androidx.concurrent:concurrent-futures:1.1.0 (*) -| | | | | +--- androidx.core:core-ktx:1.8.0 -> 1.13.1 (*) -| | | | | +--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 (*) -| | | | | +--- com.google.guava:guava:31.1-android -| | | | | | +--- com.google.guava:failureaccess:1.0.1 -| | | | | | +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava -| | | | | | +--- com.google.code.findbugs:jsr305:3.0.2 -| | | | | | +--- org.checkerframework:checker-qual:3.12.0 -| | | | | | +--- com.google.errorprone:error_prone_annotations:2.11.0 -> 2.26.0 -| | | | | | \--- com.google.j2objc:j2objc-annotations:1.3 -| | | | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | | \--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 (c) -| | | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 (*) -| | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) -| | | | +--- com.google.android.gms:play-services-stats:17.0.2 -| | | | | +--- androidx.legacy:legacy-support-core-utils:1.0.0 (*) -| | | | | \--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) -| | | | \--- com.google.guava:guava:31.1-android (*) -| | | \--- com.google.android.gms:play-services-stats:17.0.2 (*) -| | +--- com.google.android.gms:play-services-measurement-api:22.1.0 -| | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 (*) -| | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-sdk-api:22.1.0 -| | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | | \--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) -| | | +--- com.google.android.gms:play-services-tasks:18.2.0 -| | | | \--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.firebase:firebase-common:21.0.0 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4 -> 1.9.0 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) -| | | | | +--- com.google.android.gms:play-services-tasks:16.0.1 -> 18.2.0 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- com.google.firebase:firebase-components:18.0.0 -| | | | | +--- com.google.firebase:firebase-annotations:16.2.0 -| | | | | | \--- javax.inject:javax.inject:1 -| | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) -| | | | | \--- com.google.errorprone:error_prone_annotations:2.26.0 -| | | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) -| | | | +--- androidx.concurrent:concurrent-futures:1.1.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) -| | | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 -| | | | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | | | \--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | | +--- com.google.firebase:firebase-installations:17.0.1 -> 18.0.0 -| | | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | | | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | | | +--- com.google.firebase:firebase-installations-interop:17.1.1 -> 17.2.0 -| | | | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | | | | \--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- com.google.firebase:firebase-installations-interop:17.0.0 -> 17.2.0 (*) -| | | +--- com.google.firebase:firebase-measurement-connector:19.0.0 -> 20.0.1 -| | | | +--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) -| | | | \--- com.google.firebase:firebase-annotations:16.0.0 -> 16.2.0 (*) -| | | +--- com.google.guava:guava:31.1-android (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) -| | \--- com.google.android.gms:play-services-measurement-sdk:22.1.0 -| | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) -| | \--- com.google.android.gms:play-services-measurement-impl:22.1.0 (*) -| +--- com.google.firebase:firebase-common:21.0.0 (*) -| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- com.google.firebase:firebase-components:18.0.0 (*) -| \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) -+--- com.google.firebase:firebase-perf-ktx -> 21.0.1 -| +--- com.google.firebase:firebase-perf:21.0.1 -| | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) -| | +--- com.google.firebase:protolite-well-known-types:18.0.0 -| | | \--- com.google.protobuf:protobuf-javalite:3.14.0 -> 4.26.0 -| | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | +--- com.google.firebase:firebase-config:21.5.0 -> 22.0.0 -| | | +--- com.google.firebase:firebase-config-interop:16.0.1 -| | | | +--- com.google.firebase:firebase-encoders-json:18.0.1 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 -> 2.0.0 (*) -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | \--- com.google.firebase:firebase-encoders:17.0.0 -| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | \--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) -| | | +--- com.google.firebase:firebase-abt:21.1.1 -| | | | +--- com.google.firebase:firebase-measurement-connector:18.0.0 -> 20.0.1 (*) -| | | | \--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) -| | | +--- com.google.firebase:firebase-measurement-connector:18.0.0 -> 20.0.1 (*) -| | | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) -| | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) -| | +--- com.google.firebase:firebase-sessions:2.0.0 -> 2.0.4 -| | | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | | +--- com.google.firebase:firebase-installations-interop:17.2.0 (*) -| | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | | +--- com.google.firebase:firebase-encoders-json:18.0.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- com.google.firebase:firebase-installations:18.0.0 (*) -| | | +--- com.google.firebase:firebase-datatransport:19.0.0 -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- com.google.android.datatransport:transport-api:3.1.0 -> 3.2.0 -| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- com.google.android.datatransport:transport-backend-cct:3.2.0 -> 3.3.0 -| | | | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) -| | | | | +--- com.google.android.datatransport:transport-runtime:3.3.0 -| | | | | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) -| | | | | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| | | | | | +--- javax.inject:javax.inject:1 -| | | | | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | | | | | \--- com.google.firebase:firebase-encoders-proto:16.0.0 -| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | \--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | | | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | | | | +--- com.google.firebase:firebase-encoders-json:18.0.0 -> 18.0.1 (*) -| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- com.google.android.datatransport:transport-runtime:3.2.0 -> 3.3.0 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- androidx.datastore:datastore-preferences:1.0.0 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) -| | | | +--- androidx.datastore:datastore:1.0.0 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.9.0 (*) -| | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | | \--- androidx.datastore:datastore-core:1.0.0 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.9.0 (*) -| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | \--- androidx.datastore:datastore-preferences-core:1.0.0 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) -| | | | \--- androidx.datastore:datastore-core:1.0.0 (*) -| | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) -| | | \--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) -| | +--- com.google.firebase:firebase-datatransport:18.1.8 -> 19.0.0 (*) -| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-process:2.3.1 -> 2.8.6 (*) -| | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | +--- com.google.protobuf:protobuf-javalite:3.21.11 -> 4.26.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.appcompat:appcompat:1.2.0 -> 1.7.0 -| | | +--- androidx.activity:activity:1.7.0 -> 1.9.2 (*) -| | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| | | +--- androidx.appcompat:appcompat-resources:1.7.0 -| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core:1.6.0 -> 1.13.1 (*) -| | | | +--- androidx.vectordrawable:vectordrawable:1.1.0 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- androidx.vectordrawable:vectordrawable-animated:1.1.0 -| | | | | +--- androidx.vectordrawable:vectordrawable:1.1.0 (*) -| | | | | +--- androidx.interpolator:interpolator:1.0.0 (*) -| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | \--- androidx.appcompat:appcompat:1.7.0 (c) -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | +--- androidx.core:core:1.13.0 -> 1.13.1 (*) -| | | +--- androidx.core:core-ktx:1.13.0 -> 1.13.1 (*) -| | | +--- androidx.cursoradapter:cursoradapter:1.0.0 -| | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | +--- androidx.drawerlayout:drawerlayout:1.0.0 -| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 (*) -| | | +--- androidx.emoji2:emoji2:1.3.0 -| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) -| | | | +--- androidx.lifecycle:lifecycle-process:2.4.1 -> 2.8.6 (*) -| | | | +--- androidx.startup:startup-runtime:1.0.0 -> 1.1.1 (*) -| | | | \--- androidx.emoji2:emoji2-views-helper:1.3.0 (c) -| | | +--- androidx.emoji2:emoji2-views-helper:1.2.0 -> 1.3.0 -| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) -| | | | +--- androidx.emoji2:emoji2:1.3.0 (*) -| | | | \--- androidx.emoji2:emoji2:1.3.0 (c) -| | | +--- androidx.fragment:fragment:1.5.4 -> 1.8.2 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | +--- androidx.resourceinspection:resourceinspection-annotation:1.0.1 -| | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.appcompat:appcompat-resources:1.7.0 (c) -| | +--- com.google.android.datatransport:transport-api:3.0.0 -> 3.2.0 (*) -| | +--- com.google.dagger:dagger:2.27 -| | | \--- javax.inject:javax.inject:1 -| | \--- com.squareup.okhttp3:okhttp:3.12.1 -> 4.12.0 -| | +--- com.squareup.okio:okio:3.6.0 -> 3.9.0 -| | | \--- com.squareup.okio:okio-jvm:3.9.0 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 2.0.0 (*) -| +--- com.google.firebase:firebase-common:21.0.0 (*) -| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| \--- com.google.firebase:firebase-components:18.0.0 (*) -+--- com.google.firebase:firebase-crashlytics-ktx -> 19.1.0 -| +--- com.google.firebase:firebase-crashlytics:19.1.0 -| | +--- com.google.firebase:firebase-sessions:2.0.4 (*) -| | +--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | +--- com.google.firebase:firebase-config-interop:16.0.1 (*) -| | +--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | +--- com.google.firebase:firebase-encoders-json:18.0.1 (*) -| | +--- com.google.firebase:firebase-installations:18.0.0 (*) -| | +--- com.google.firebase:firebase-installations-interop:17.2.0 (*) -| | +--- com.google.firebase:firebase-measurement-connector:20.0.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | +--- com.google.android.datatransport:transport-api:3.2.0 (*) -| | +--- com.google.android.datatransport:transport-backend-cct:3.3.0 (*) -| | +--- com.google.android.datatransport:transport-runtime:3.3.0 (*) -| | \--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) -| +--- com.google.firebase:firebase-common:21.0.0 (*) -| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| \--- com.google.firebase:firebase-components:18.0.0 (*) -+--- com.google.firebase:firebase-messaging-ktx -> 24.0.1 -| +--- com.google.firebase:firebase-messaging:24.0.1 -| | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | +--- com.google.firebase:firebase-datatransport:18.2.0 -> 19.0.0 (*) -| | +--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | +--- com.google.firebase:firebase-encoders-json:18.0.0 -> 18.0.1 (*) -| | +--- com.google.firebase:firebase-encoders-proto:16.0.0 (*) -| | +--- com.google.firebase:firebase-iid-interop:17.1.0 -| | | +--- com.google.android.gms:play-services-basement:17.0.0 -> 18.4.0 (*) -| | | \--- com.google.android.gms:play-services-tasks:17.0.0 -> 18.2.0 (*) -| | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) -| | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) -| | +--- com.google.firebase:firebase-measurement-connector:19.0.0 -> 20.0.1 (*) -| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | +--- com.google.android.datatransport:transport-api:3.1.0 -> 3.2.0 (*) -| | +--- com.google.android.datatransport:transport-backend-cct:3.1.8 -> 3.3.0 (*) -| | +--- com.google.android.datatransport:transport-runtime:3.1.8 -> 3.3.0 (*) -| | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | +--- androidx.core:core:1.2.0 -> 1.13.1 (*) -| | | +--- androidx.fragment:fragment:1.0.0 -> 1.8.2 (*) -| | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) -| | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | +--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) -| | +--- com.google.android.gms:play-services-cloud-messaging:17.2.0 -| | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) -| | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | +--- com.google.android.gms:play-services-stats:17.0.2 (*) -| | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | +--- com.google.errorprone:error_prone_annotations:2.9.0 -> 2.26.0 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- com.google.firebase:firebase-common:21.0.0 (*) -| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| \--- com.google.firebase:firebase-components:18.0.0 (*) -+--- project :core:data -| +--- androidx.core:core-ktx:1.13.1 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 -| | +--- androidx.tracing:tracing:1.3.0-alpha02 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | \--- androidx.tracing:tracing:1.3.0-alpha02 (c) -| +--- io.insert-koin:koin-android:4.0.0-RC2 -| | +--- io.insert-koin:koin-core:4.0.0-RC2 -| | | \--- io.insert-koin:koin-core-jvm:4.0.0-RC2 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | +--- co.touchlab:stately-concurrency:2.0.7 -| | | | \--- co.touchlab:stately-concurrency-jvm:2.0.7 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | | | \--- co.touchlab:stately-strict:2.0.7 -| | | | \--- co.touchlab:stately-strict-jvm:2.0.7 -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | | \--- co.touchlab:stately-concurrent-collections:2.0.7 -| | | \--- co.touchlab:stately-concurrent-collections-jvm:2.0.7 -| | | +--- co.touchlab:stately-concurrency:2.0.7 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 -| | | \--- io.insert-koin:koin-core-viewmodel-jvm:4.0.0-RC2 -| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.0 -| | | | \--- androidx.lifecycle:lifecycle-viewmodel:2.8.0 -> 2.8.6 (*) -| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 -| | | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 -> 2.8.6 (*) -| | | +--- org.jetbrains.androidx.core:core-bundle:1.0.0 -| | | | \--- org.jetbrains.androidx.core:core-bundle-android:1.0.0 -| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.0 -| | | | \--- androidx.savedstate:savedstate:1.2.1 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- androidx.appcompat:appcompat:1.7.0 (*) -| | +--- androidx.activity:activity-ktx:1.9.1 -> 1.9.2 -| | | +--- androidx.activity:activity:1.9.2 (*) -| | | +--- androidx.core:core-ktx:1.13.0 -> 1.13.1 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.6 -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) -| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.activity:activity:1.9.2 (c) -| | | \--- androidx.activity:activity-compose:1.9.2 (c) -| | +--- androidx.fragment:fragment-ktx:1.8.2 -| | | +--- androidx.activity:activity-ktx:1.8.1 -> 1.9.2 (*) -| | | +--- androidx.collection:collection-ktx:1.1.0 -> 1.4.4 -| | | | +--- androidx.collection:collection:1.4.4 (*) -| | | | \--- androidx.collection:collection:1.4.4 (c) -| | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) -| | | +--- androidx.fragment:fragment:1.8.2 (*) -| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.fragment:fragment:1.8.2 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 -> 2.8.6 (*) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 -> 2.8.6 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- project :core:common -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (*) -| | +--- io.coil-kt.coil3:coil:3.0.0-alpha10 -| | | \--- io.coil-kt.coil3:coil-android:3.0.0-alpha10 -| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 -| | | | \--- io.coil-kt.coil3:coil-core-android:3.0.0-alpha10 -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 -> 2.8.6 (*) -| | | | +--- androidx.annotation:annotation:1.8.1 (*) -| | | | +--- androidx.appcompat:appcompat-resources:1.7.0 (*) -| | | | +--- androidx.core:core-ktx:1.13.1 (*) -| | | | +--- androidx.exifinterface:exifinterface:1.3.7 -| | | | | \--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 -> 1.9.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | | | \--- com.squareup.okio:okio:3.9.0 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) -| | +--- io.coil-kt.coil3:coil-svg:3.0.0-alpha10 -| | | \--- io.coil-kt.coil3:coil-svg-android:3.0.0-alpha10 -| | | +--- androidx.core:core-ktx:1.13.1 (*) -| | | +--- com.caverock:androidsvg-aar:1.4 -| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | +--- io.coil-kt.coil3:coil-network-ktor3:3.0.0-alpha10 -| | | \--- io.coil-kt.coil3:coil-network-ktor3-android:3.0.0-alpha10 -| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) -| | | +--- io.coil-kt.coil3:coil-network-core:3.0.0-alpha10 -| | | | \--- io.coil-kt.coil3:coil-network-core-android:3.0.0-alpha10 -| | | | +--- androidx.core:core-ktx:1.13.1 (*) -| | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | | +--- io.ktor:ktor-client-core:3.0.0-beta-2 -| | | | \--- io.ktor:ktor-client-core-jvm:3.0.0-beta-2 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) -| | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | +--- io.ktor:ktor-http:3.0.0-beta-2 -| | | | | \--- io.ktor:ktor-http-jvm:3.0.0-beta-2 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | +--- io.ktor:ktor-utils:3.0.0-beta-2 -| | | | | | \--- io.ktor:ktor-utils-jvm:3.0.0-beta-2 -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | | +--- io.ktor:ktor-io:3.0.0-beta-2 -| | | | | | | \--- io.ktor:ktor-io-jvm:3.0.0-beta-2 -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-io-core:0.5.1 -| | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.5.1 -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-io-bytestring:0.5.1 -| | | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.5.1 -| | | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- io.ktor:ktor-events:3.0.0-beta-2 -| | | | | \--- io.ktor:ktor-events-jvm:3.0.0-beta-2 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) -| | | | | +--- io.ktor:ktor-utils:3.0.0-beta-2 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- io.ktor:ktor-websocket-serialization:3.0.0-beta-2 -| | | | | \--- io.ktor:ktor-websocket-serialization-jvm:3.0.0-beta-2 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) -| | | | | +--- io.ktor:ktor-serialization:3.0.0-beta-2 -| | | | | | \--- io.ktor:ktor-serialization-jvm:3.0.0-beta-2 -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) -| | | | | | +--- io.ktor:ktor-websockets:3.0.0-beta-2 -| | | | | | | \--- io.ktor:ktor-websockets-jvm:3.0.0-beta-2 -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) -| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- io.ktor:ktor-sse:3.0.0-beta-2 -| | | | | \--- io.ktor:ktor-sse-jvm:3.0.0-beta-2 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.8.0 -> 1.9.0 -| | | | +--- org.slf4j:slf4j-api:1.7.32 -> 2.0.13 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 -| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (c) -| | | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (c) -| | | +--- io.insert-koin:koin-android:4.0.0-RC2 (c) -| | | +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (c) -| | | +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (c) -| | | \--- io.insert-koin:koin-compose:4.0.0-RC2 (c) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 -| | | \--- io.insert-koin:koin-annotations-jvm:1.4.0-RC4 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) -| | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| +--- project :core:datastore -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | +--- com.russhwolf:multiplatform-settings-no-arg:1.2.0 -| | | \--- com.russhwolf:multiplatform-settings-no-arg-android:1.2.0 -| | | +--- androidx.startup:startup-runtime:1.1.1 (*) -| | | +--- com.russhwolf:multiplatform-settings:1.2.0 -| | | | \--- com.russhwolf:multiplatform-settings-android:1.2.0 -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | +--- com.russhwolf:multiplatform-settings-serialization:1.2.0 -| | | \--- com.russhwolf:multiplatform-settings-serialization-android:1.2.0 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | +--- com.russhwolf:multiplatform-settings:1.2.0 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 -| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 (c) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (c) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 (c) -| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (c) -| | +--- com.russhwolf:multiplatform-settings-coroutines:1.2.0 -| | | \--- com.russhwolf:multiplatform-settings-coroutines-android:1.2.0 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | +--- com.russhwolf:multiplatform-settings:1.2.0 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) -| | +--- project :core:model -| | | +--- com.squareup.retrofit2:converter-gson:2.11.0 -| | | | +--- com.squareup.retrofit2:retrofit:2.11.0 -| | | | | \--- com.squareup.okhttp3:okhttp:3.14.9 -> 4.12.0 (*) -| | | | \--- com.google.code.gson:gson:2.10.1 -| | | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 -| | | | \--- org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.0 -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 -| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (c) -| | | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.20 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- project :core:common (*) -| | \--- project :core:datastore-proto -| | +--- com.google.protobuf:protobuf-kotlin-lite:4.26.0 -| | | +--- com.google.protobuf:protobuf-javalite:4.26.0 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.0 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) -| +--- project :core:network -| | +--- io.ktor:ktor-client-android:2.3.4 -| | | \--- io.ktor:ktor-client-android-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 (*) -| | +--- project :core:common (*) -| | +--- project :core:model (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (*) -| | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | +--- io.ktor:ktor-client-json:2.3.4 -| | | \--- io.ktor:ktor-client-json-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | \--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | +--- io.ktor:ktor-client-logging:2.3.4 -| | | \--- io.ktor:ktor-client-logging-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | \--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | +--- io.ktor:ktor-client-serialization:2.3.4 -| | | \--- io.ktor:ktor-client-serialization-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1 -> 1.7.2 (*) -| | | \--- io.ktor:ktor-client-json:2.3.4 (*) -| | +--- io.ktor:ktor-client-content-negotiation:2.3.4 -| | | \--- io.ktor:ktor-client-content-negotiation-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | | \--- io.ktor:ktor-serialization:2.3.4 -> 3.0.0-beta-2 (*) -| | +--- io.ktor:ktor-serialization-kotlinx-json:2.3.4 -| | | \--- io.ktor:ktor-serialization-kotlinx-json-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | +--- io.ktor:ktor-http:2.3.4 -> 3.0.0-beta-2 (*) -| | | +--- io.ktor:ktor-serialization-kotlinx:2.3.4 -| | | | \--- io.ktor:ktor-serialization-kotlinx-jvm:2.3.4 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | +--- io.ktor:ktor-http:2.3.4 -> 3.0.0-beta-2 (*) -| | | | +--- io.ktor:ktor-serialization:2.3.4 -> 3.0.0-beta-2 (*) -| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1 -> 1.7.2 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1 -> 1.7.2 (*) -| | +--- de.jensklingenberg.ktorfit:ktorfit-lib:2.1.0 -| | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-android:2.1.0 -| | | +--- io.ktor:ktor-client-cio-jvm:2.3.12 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | +--- io.ktor:ktor-client-core:2.3.12 -> 3.0.0-beta-2 (*) -| | | | +--- io.ktor:ktor-http-cio:2.3.12 -| | | | | \--- io.ktor:ktor-http-cio-jvm:2.3.12 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | | | +--- io.ktor:ktor-network:2.3.12 -| | | | | | \--- io.ktor:ktor-network-jvm:2.3.12 -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | | | \--- io.ktor:ktor-utils:2.3.12 -> 3.0.0-beta-2 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | | \--- io.ktor:ktor-http:2.3.12 -> 3.0.0-beta-2 (*) -| | | | +--- io.ktor:ktor-websockets:2.3.12 -> 3.0.0-beta-2 (*) -| | | | \--- io.ktor:ktor-network-tls:2.3.12 -| | | | \--- io.ktor:ktor-network-tls-jvm:2.3.12 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | +--- io.ktor:ktor-http:2.3.12 -> 3.0.0-beta-2 (*) -| | | | +--- io.ktor:ktor-network:2.3.12 (*) -| | | | \--- io.ktor:ktor-utils:2.3.12 -> 3.0.0-beta-2 (*) -| | | +--- de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 -| | | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light-android:2.1.0 -| | | | +--- de.jensklingenberg.ktorfit:ktorfit-annotations:2.1.0 -| | | | | \--- de.jensklingenberg.ktorfit:ktorfit-annotations-android:2.1.0 -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- io.ktor:ktor-client-core:2.3.12 -> 3.0.0-beta-2 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | +--- de.jensklingenberg.ktorfit:ktorfit-converters-call:2.1.0 -| | | \--- de.jensklingenberg.ktorfit:ktorfit-converters-call-android:2.1.0 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 (*) -| | \--- de.jensklingenberg.ktorfit:ktorfit-converters-flow:2.1.0 -| | \--- de.jensklingenberg.ktorfit:ktorfit-converters-flow-android:2.1.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 (*) -| +--- project :core:model (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- project :core:analytics -| | +--- com.google.firebase:firebase-bom:33.3.0 (*) -| | +--- com.google.firebase:firebase-analytics-ktx -> 22.1.0 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | \--- org.jetbrains.compose.runtime:runtime:1.6.11 -| | \--- androidx.compose.runtime:runtime:1.6.7 -> 1.7.2 (*) -| \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) -+--- project :core:ui -| +--- androidx.metrics:metrics-performance:1.0.0-beta01 -| | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | +--- androidx.core:core:1.5.0 -> 1.13.1 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- androidx.browser:browser:1.8.0 -| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | +--- androidx.interpolator:interpolator:1.0.0 (*) -| | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| +--- com.google.accompanist:accompanist-pager:0.34.0 -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.9.0 (*) -| | +--- androidx.compose.foundation:foundation:1.6.0 -> 1.7.2 -| | | \--- androidx.compose.foundation:foundation-android:1.7.2 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | +--- androidx.compose.animation:animation:1.7.2 -| | | | \--- androidx.compose.animation:animation-android:1.7.2 -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | +--- androidx.compose.animation:animation-core:1.7.2 -| | | | | \--- androidx.compose.animation:animation-core-android:1.7.2 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui:1.7.2 -| | | | | | \--- androidx.compose.ui:ui-android:1.7.2 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.9.2 (*) -| | | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | | +--- androidx.autofill:autofill:1.0.0 -| | | | | | | \--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 -| | | | | | | \--- androidx.compose.runtime:runtime-saveable-android:1.7.2 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | \--- androidx.compose.runtime:runtime:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 -| | | | | | | \--- androidx.compose.ui:ui-geometry-android:1.7.2 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 -| | | | | | | | \--- androidx.compose.ui:ui-util-android:1.7.2 -| | | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | | | \--- androidx.compose.ui:ui-unit:1.7.2 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 -| | | | | | | \--- androidx.compose.ui:ui-graphics-android:1.7.2 -| | | | | | | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 -| | | | | | | | \--- androidx.compose.ui:ui-unit-android:1.7.2 -| | | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | | | | +--- androidx.collection:collection-ktx:1.2.0 -> 1.4.4 (*) -| | | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) -| | | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) -| | | | | | | +--- androidx.graphics:graphics-path:1.0.1 -| | | | | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) -| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-text:1.7.2 -| | | | | | | \--- androidx.compose.ui:ui-text-android:1.7.2 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 (*) -| | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) -| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) -| | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) -| | | | | | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) -| | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) -| | | | | | +--- androidx.customview:customview-poolingcontainer:1.0.0 -| | | | | | | +--- androidx.core:core-ktx:1.5.0 -> 1.13.1 (*) -| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) -| | | | | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.3 -> 2.8.6 -| | | | | | | \--- androidx.lifecycle:lifecycle-runtime-compose-android:2.8.6 -| | | | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.compose.runtime:runtime:1.7.1 -> 1.7.2 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | | | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (c) -| | | | | | \--- androidx.compose.foundation:foundation:1.7.2 (c) -| | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | | | | +--- androidx.compose.animation:animation:1.7.2 (c) -| | | | | \--- androidx.compose.animation:animation-graphics:1.7.2 (c) -| | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 -| | | | | \--- androidx.compose.foundation:foundation-layout-android:1.7.2 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | +--- androidx.compose.animation:animation-core:1.2.1 -> 1.7.2 (*) -| | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | \--- androidx.compose.foundation:foundation:1.7.2 (c) -| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) -| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) -| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- androidx.compose.animation:animation-core:1.7.2 (c) -| | | | \--- androidx.compose.animation:animation-graphics:1.7.2 (c) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-text:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | +--- androidx.core:core:1.13.1 (*) -| | | +--- androidx.emoji2:emoji2:1.3.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.compose.foundation:foundation-layout:1.7.2 (c) -| | +--- dev.chrisbanes.snapper:snapper:0.2.2 -> 0.3.0 -| | | +--- androidx.compose.foundation:foundation:1.2.1 -> 1.7.2 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21 -> 2.0.0 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) -| +--- project :core:analytics (*) -| +--- project :core:designsystem -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| | +--- androidx.activity:activity-compose:1.9.2 -| | | +--- androidx.activity:activity-ktx:1.9.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.0.1 -> 1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime-saveable:1.0.1 -> 1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.0.1 -> 1.7.2 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.activity:activity:1.9.2 (c) -| | | \--- androidx.activity:activity-ktx:1.9.2 (c) -| | +--- project :core:model (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | +--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 -| | | \--- io.coil-kt.coil3:coil-compose-core-android:3.0.0-alpha10 -| | | +--- com.google.accompanist:accompanist-drawablepainter:0.34.0 -| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.9.0 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) -| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) -| | | +--- org.jetbrains.compose.foundation:foundation:1.6.11 -| | | | \--- androidx.compose.foundation:foundation:1.6.7 -> 1.7.2 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) -| | +--- org.jetbrains.compose.foundation:foundation:1.6.11 (*) -| | +--- org.jetbrains.compose.material:material:1.6.11 -| | | \--- androidx.compose.material:material:1.6.7 -> 1.7.2 -| | | \--- androidx.compose.material:material-android:1.7.2 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.compose.animation:animation:1.7.2 (*) -| | | +--- androidx.compose.animation:animation-core:1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation:1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) -| | | +--- androidx.compose.material:material-ripple:1.7.2 -| | | | \--- androidx.compose.material:material-ripple-android:1.7.2 -| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | +--- androidx.compose.animation:animation:1.7.2 (*) -| | | | +--- androidx.compose.foundation:foundation:1.7.2 (*) -| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-text:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.compose.material3:material3:1.6.11 -| | | \--- androidx.compose.material3:material3:1.2.1 -> 1.3.0 -| | | \--- androidx.compose.material3:material3-android:1.3.0 -| | | +--- androidx.activity:activity-compose:1.8.2 -> 1.9.2 (*) -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | +--- androidx.compose.animation:animation-core:1.6.0 -> 1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation:1.7.0 -> 1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.0 -> 1.7.2 (*) -| | | +--- androidx.compose.material:material-icons-core:1.6.0 -> 1.7.2 -| | | | \--- androidx.compose.material:material-icons-core-android:1.7.2 -| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.compose.material:material-ripple:1.7.0 -> 1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.0 -> 1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) -| | | +--- androidx.compose.ui:ui-text:1.6.0 -> 1.7.2 (*) -| | | +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.2 (*) -| | | +--- androidx.lifecycle:lifecycle-common-java8:2.6.1 -> 2.8.6 (*) -| | | \--- androidx.compose.material3:material3-window-size-class:1.3.0 (c) -| | +--- org.jetbrains.compose.material:material-icons-extended:1.6.11 -| | | \--- androidx.compose.material:material-icons-extended:1.6.7 -> 1.7.2 -| | | \--- androidx.compose.material:material-icons-extended-android:1.7.2 -| | | \--- androidx.compose.material:material-icons-core:1.7.2 (*) -| | +--- org.jetbrains.compose.ui:ui:1.6.11 -| | | \--- androidx.compose.ui:ui:1.6.7 -> 1.7.2 (*) -| | +--- org.jetbrains.compose.ui:ui-util:1.6.11 -| | | \--- androidx.compose.ui:ui-util:1.6.7 -> 1.7.2 (*) -| | +--- org.jetbrains.compose.components:components-resources:1.6.11 -| | | \--- org.jetbrains.compose.components:components-resources-android:1.6.11 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) -| | | +--- org.jetbrains.compose.foundation:foundation:1.6.11 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | \--- org.jetbrains.compose.components:components-ui-tooling-preview:1.6.11 -| | \--- org.jetbrains.compose.components:components-ui-tooling-preview-android:1.6.11 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| +--- project :core:model (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- io.coil-kt.coil3:coil:3.0.0-alpha10 (*) -| +--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) -| +--- org.jetbrains.compose.material3:material3:1.6.11 (*) -| +--- org.jetbrains.compose.components:components-resources:1.6.11 (*) -| \--- org.jetbrains.compose.components:components-ui-tooling-preview:1.6.11 (*) -+--- project :core:designsystem (*) -+--- project :feature:receipt -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | +--- androidx.compose:compose-bom:2024.09.02 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| | +--- androidx.navigation:navigation-compose:2.8.1 -| | | +--- androidx.activity:activity-compose:1.8.0 -> 1.9.2 (*) -| | | +--- androidx.compose.animation:animation:1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2 -> 2.8.6 -| | | | \--- androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.6 -| | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | | | +--- androidx.compose.runtime:runtime:1.6.0 -> 1.7.2 (*) -| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) -| | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 -| | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 -| | | | | +--- androidx.navigation:navigation-common:2.8.1 -| | | | | | +--- androidx.annotation:annotation:1.8.1 (*) -| | | | | | +--- androidx.collection:collection-ktx:1.4.2 -> 1.4.4 (*) -| | | | | | +--- androidx.core:core-ktx:1.1.0 -> 1.13.1 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.2 -> 2.8.6 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.6 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.6 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 -> 2.8.6 (*) -| | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) -| | | | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-common:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-runtime:2.8.1 -| | | | | +--- androidx.activity:activity-ktx:1.7.1 -> 1.9.2 (*) -| | | | | +--- androidx.annotation:annotation-experimental:1.4.1 (*) -| | | | | +--- androidx.collection:collection:1.4.2 -> 1.4.4 (*) -| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.6 (*) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.6 (*) -| | | | | +--- androidx.navigation:navigation-common:2.8.1 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) -| | | | | +--- androidx.navigation:navigation-common:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | | \--- androidx.navigation:navigation-common:2.8.1 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) -| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | \--- androidx.navigation:navigation-common:2.8.1 (c) -| | +--- androidx.compose.material3:material3 -> 1.3.0 (*) -| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| | \--- androidx.compose.ui:ui-util -> 1.7.2 (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 -| | \--- org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.8 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 -| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-compose:4.0.0-RC2 -| | | \--- io.insert-koin:koin-compose-jvm:4.0.0-RC2 -| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.2 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 -> 2.8.6 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 -| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| | +--- androidx.navigation:navigation-fragment-ktx:2.7.7 -> 2.8.1 -| | | +--- androidx.navigation:navigation-fragment:2.8.1 -| | | | +--- androidx.fragment:fragment-ktx:1.6.2 -> 1.8.2 (*) -| | | | +--- androidx.navigation:navigation-runtime:2.8.1 (*) -| | | | +--- androidx.slidingpanelayout:slidingpanelayout:1.2.0 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.customview:customview:1.1.0 (*) -| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | | | +--- androidx.window:window:1.0.0 -> 1.3.0 -| | | | | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| | | | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | | | +--- androidx.core:core:1.8.0 -> 1.13.1 (*) -| | | | | | +--- androidx.window.extensions.core:core:1.0.0 -| | | | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) -| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.20 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | | | | | \--- androidx.window:window-core:1.3.0 (c) -| | | | | \--- androidx.transition:transition:1.4.1 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) -| | | | +--- androidx.navigation:navigation-common:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 (*) -| | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | \--- androidx.navigation:navigation-common:2.8.1 (c) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- com.squareup.okhttp3:okhttp:4.12.0 (*) -+--- project :feature:profile -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- project :libs:country-code-picker -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | +--- androidx.compose:compose-bom:2024.09.02 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| | +--- androidx.compose.foundation:foundation -> 1.7.2 (*) -| | +--- androidx.compose.foundation:foundation-layout -> 1.7.2 (*) -| | +--- androidx.compose.material:material-icons-extended -> 1.7.2 (*) -| | +--- androidx.compose.material3:material3 -> 1.3.0 (*) -| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| | +--- androidx.compose.ui:ui-util -> 1.7.2 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| | \--- io.michaelrocks:libphonenumber-android:8.13.35 -| +--- com.squareup.okhttp3:okhttp:4.12.0 (*) -| \--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) -+--- project :feature:auth -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- project :libs:country-code-picker (*) -| +--- androidx.credentials:credentials:1.2.2 -> 1.3.0-beta01 -| | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | \--- androidx.credentials:credentials-play-services-auth:1.3.0-beta01 (c) -| +--- androidx.credentials:credentials-play-services-auth:1.2.2 -> 1.3.0-beta01 -| | +--- androidx.credentials:credentials:1.3.0-beta01 (*) -| | +--- com.google.android.gms:play-services-auth:21.1.1 -> 21.2.0 -| | | +--- androidx.fragment:fragment:1.5.7 -> 1.8.2 (*) -| | | +--- androidx.loader:loader:1.1.0 (*) -| | | +--- com.google.android.gms:play-services-auth-api-phone:18.0.2 -| | | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) -| | | | +--- com.google.android.gms:play-services-basement:18.0.2 -> 18.4.0 (*) -| | | | \--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | | +--- com.google.android.gms:play-services-auth-base:18.0.10 -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) -| | | | +--- com.google.android.gms:play-services-basement:18.2.0 -> 18.4.0 (*) -| | | | \--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | | +--- com.google.android.gms:play-services-base:18.3.0 (*) -| | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) -| | | +--- com.google.android.gms:play-services-fido:20.0.1 -> 21.0.0 -| | | | +--- com.google.android.gms:play-services-base:18.3.0 (*) -| | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) -| | | | +--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0 -> 2.0.0 (*) -| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | +--- com.google.android.gms:play-services-fido:21.0.0 (*) -| | +--- com.google.android.libraries.identity.googleid:googleid:1.1.0 -> 1.1.1 -| | | +--- androidx.credentials:credentials:1.3.0-beta01 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.0 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.0.0 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | \--- androidx.credentials:credentials:1.3.0-beta01 (c) -| +--- com.google.android.libraries.identity.googleid:googleid:1.1.1 (*) -| \--- com.google.android.gms:play-services-auth:21.2.0 (*) -+--- project :feature:make-transfer -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:faq -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:editpassword -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:notification -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- project :libs:pullrefresh -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- androidx.compose.animation:animation -> 1.7.2 (*) -| +--- androidx.compose.material3:material3 -> 1.3.0 (*) -| +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| \--- androidx.compose.ui:ui-util -> 1.7.2 (*) -+--- project :feature:request-money -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- com.google.zxing:core:3.5.3 -| \--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) -+--- project :feature:upi-setup -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:settings -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:savedcards -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:qr -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- com.google.zxing:core:3.5.3 -| +--- androidx.camera:camera-view:1.3.4 -| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | +--- androidx.annotation:annotation-experimental:1.3.1 -> 1.4.1 (*) -| | +--- androidx.appcompat:appcompat:1.1.0 -> 1.7.0 (*) -| | +--- androidx.camera:camera-core:1.3.4 -| | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.1.0 -> 1.4.1 (*) -| | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | +--- androidx.exifinterface:exifinterface:1.3.2 -> 1.3.7 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.1.0 -> 2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.1.0 -> 2.8.6 (*) -| | | +--- com.google.auto.value:auto-value-annotations:1.6.3 -| | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.camera:camera-lifecycle:1.3.4 (c) -| | | +--- androidx.camera:camera-video:1.3.4 (c) -| | | \--- androidx.camera:camera-view:1.3.4 (c) -| | +--- androidx.camera:camera-lifecycle:1.3.4 -| | | +--- androidx.camera:camera-core:1.3.4 (*) -| | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.1.0 -> 2.8.6 (*) -| | | +--- com.google.auto.value:auto-value-annotations:1.6.3 -| | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| | | +--- androidx.camera:camera-core:1.3.4 (c) -| | | +--- androidx.camera:camera-video:1.3.4 (c) -| | | \--- androidx.camera:camera-view:1.3.4 (c) -| | +--- androidx.camera:camera-video:1.3.4 -| | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | +--- androidx.camera:camera-core:1.3.4 (*) -| | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | +--- com.google.auto.value:auto-value-annotations:1.6.3 -| | | +--- androidx.camera:camera-core:1.3.4 (c) -| | | +--- androidx.camera:camera-lifecycle:1.3.4 (c) -| | | \--- androidx.camera:camera-view:1.3.4 (c) -| | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | +--- androidx.core:core:1.3.2 -> 1.13.1 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.8.6 (*) -| | +--- com.google.auto.value:auto-value-annotations:1.6.3 -| | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| | +--- androidx.camera:camera-core:1.3.4 (c) -| | +--- androidx.camera:camera-lifecycle:1.3.4 (c) -| | \--- androidx.camera:camera-video:1.3.4 (c) -| +--- androidx.camera:camera-lifecycle:1.3.4 (*) -| \--- com.google.guava:guava:27.0.1-android -> 31.1-android (*) -+--- project :feature:invoices -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:merchants -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- project :libs:pullrefresh (*) -+--- project :feature:history -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- project :libs:pullrefresh (*) -+--- project :feature:kyc -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- project :libs:country-code-picker (*) -| +--- project :libs:pullrefresh (*) -| +--- com.maxkeppeler.sheets-compose-dialogs:core:1.3.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.10 -> 2.0.0 (*) -| | +--- androidx.core:core-ktx:1.9.0 -> 1.13.1 (*) -| | +--- androidx.compose:compose-bom:2024.02.00 -> 2024.09.02 (*) -| | +--- androidx.compose.ui:ui -> 1.7.2 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| | +--- androidx.compose.animation:animation -> 1.7.2 (*) -| | +--- androidx.compose.animation:animation-graphics -> 1.7.2 -| | | \--- androidx.compose.animation:animation-graphics-android:1.7.2 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | +--- androidx.compose.animation:animation:1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | +--- androidx.core:core-ktx:1.5.0 -> 1.13.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.compose.animation:animation:1.7.2 (c) -| | | \--- androidx.compose.animation:animation-core:1.7.2 (c) -| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| | \--- androidx.compose.material3:material3 -> 1.3.0 (*) -| +--- com.maxkeppeler.sheets-compose-dialogs:calendar:1.3.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.10 -> 2.0.0 (*) -| | +--- androidx.core:core-ktx:1.9.0 -> 1.13.1 (*) -| | +--- androidx.compose:compose-bom:2024.02.00 -> 2024.09.02 (*) -| | +--- androidx.compose.ui:ui -> 1.7.2 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| | +--- androidx.compose.animation:animation -> 1.7.2 (*) -| | +--- androidx.compose.animation:animation-graphics -> 1.7.2 (*) -| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| | +--- androidx.compose.material3:material3 -> 1.3.0 (*) -| | +--- dev.chrisbanes.snapper:snapper:0.3.0 (*) -| | \--- com.maxkeppeler.sheets-compose-dialogs:core:1.3.0 (*) -| \--- com.squareup.okhttp3:okhttp:4.12.0 (*) -+--- project :feature:home -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:accounts -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- project :libs:pullrefresh (*) -| \--- com.google.android.gms:play-services-auth:21.2.0 (*) -+--- project :feature:finance -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- com.google.accompanist:accompanist-pager:0.34.0 (*) -+--- project :feature:payments -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- com.google.accompanist:accompanist-pager:0.34.0 (*) -+--- project :feature:send-money -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- project :libs:country-code-picker (*) -| \--- com.google.android.gms:play-services-code-scanner:16.1.0 -| +--- androidx.activity:activity:1.3.1 -> 1.9.2 (*) -| +--- com.google.android.datatransport:transport-api:2.2.1 -> 3.2.0 (*) -| +--- com.google.android.datatransport:transport-backend-cct:2.3.3 -> 3.3.0 (*) -| +--- com.google.android.datatransport:transport-runtime:2.2.6 -> 3.3.0 (*) -| +--- com.google.android.gms:play-services-base:18.1.0 -> 18.3.0 (*) -| +--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) -| +--- com.google.android.gms:play-services-tasks:18.0.2 -> 18.2.0 (*) -| +--- com.google.firebase:firebase-components:16.1.0 -> 18.0.0 (*) -| +--- com.google.firebase:firebase-encoders:16.1.0 -> 17.0.0 (*) -| +--- com.google.firebase:firebase-encoders-json:17.1.0 -> 18.0.1 (*) -| +--- com.google.mlkit:barcode-scanning-common:17.0.0 -| | +--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) -| | \--- com.google.mlkit:vision-common:17.0.0 -| | +--- androidx.exifinterface:exifinterface:1.0.0 -> 1.3.7 (*) -| | +--- com.google.android.datatransport:transport-api:2.2.1 -> 3.2.0 (*) -| | +--- com.google.android.datatransport:transport-backend-cct:2.3.3 -> 3.3.0 (*) -| | +--- com.google.android.datatransport:transport-runtime:2.2.6 -> 3.3.0 (*) -| | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) -| | +--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) -| | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | +--- com.google.android.odml:image:1.0.0-beta1 -| | +--- com.google.firebase:firebase-components:16.1.0 -> 18.0.0 (*) -| | +--- com.google.firebase:firebase-encoders:16.1.0 -> 17.0.0 (*) -| | +--- com.google.firebase:firebase-encoders-json:17.1.0 -> 18.0.1 (*) -| | \--- com.google.mlkit:common:18.0.0 -> 18.9.0 -| | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | +--- com.google.android.datatransport:transport-api:2.2.1 -> 3.2.0 (*) -| | +--- com.google.android.datatransport:transport-backend-cct:2.3.3 -> 3.3.0 (*) -| | +--- com.google.android.datatransport:transport-runtime:2.2.6 -> 3.3.0 (*) -| | +--- com.google.android.gms:play-services-base:18.1.0 -> 18.3.0 (*) -| | +--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) -| | +--- com.google.android.gms:play-services-tasks:18.0.2 -> 18.2.0 (*) -| | +--- com.google.firebase:firebase-components:16.1.0 -> 18.0.0 (*) -| | +--- com.google.firebase:firebase-encoders:16.1.0 -> 17.0.0 (*) -| | \--- com.google.firebase:firebase-encoders-json:17.1.0 -> 18.0.1 (*) -| \--- com.google.mlkit:common:18.9.0 (*) -+--- project :feature:standing-instruction -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- com.google.android.gms:play-services-code-scanner:16.1.0 (*) -+--- project :feature:search -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :libs:mifos-passcode -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- androidx.core:core-ktx:1.13.1 (*) -| +--- androidx.compose.foundation:foundation -> 1.7.2 (*) -| +--- androidx.compose.foundation:foundation-layout -> 1.7.2 (*) -| +--- androidx.compose.material:material-icons-extended -> 1.7.2 (*) -| +--- androidx.compose.material3:material3 -> 1.3.0 (*) -| +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-util -> 1.7.2 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| \--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -+--- project :libs:material3-navigation (*) -+--- androidx.core:core-ktx:1.13.1 (*) -+--- androidx.appcompat:appcompat:1.7.0 (*) -+--- androidx.activity:activity-compose:1.9.2 (*) -+--- androidx.activity:activity-ktx:1.9.2 (*) -+--- androidx.core:core-splashscreen:1.0.1 -| +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) -+--- androidx.compose.material3.adaptive:adaptive:1.0.0 -| \--- androidx.compose.material3.adaptive:adaptive-android:1.0.0 -| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.2 (*) -| +--- androidx.window:window:1.3.0 (*) -| +--- androidx.window:window-core:1.3.0 -| | \--- androidx.window:window-core-android:1.3.0 -| | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | \--- androidx.window:window:1.3.0 (c) -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) -| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) -+--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 -| \--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 -| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.animation:animation:1.7.0 -> 1.7.2 (*) -| +--- androidx.compose.animation:animation-core:1.7.0 -> 1.7.2 (*) -| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) -| +--- androidx.compose.foundation:foundation-layout:1.6.5 -> 1.7.2 (*) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (*) -| +--- androidx.compose.ui:ui:1.7.0 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.2 (*) -| +--- androidx.window:window-core:1.3.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) -| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) -+--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 -| \--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 -| +--- androidx.activity:activity-compose:1.8.2 -> 1.9.2 (*) -| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) -| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (*) -| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.2 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) -| \--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) -+--- androidx.compose.material3:material3-window-size-class -> 1.3.0 -| \--- androidx.compose.material3:material3-window-size-class-android:1.3.0 -| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.runtime:runtime:1.7.0 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-unit:1.6.0 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.2 (*) -| +--- androidx.window:window:1.0.0 -> 1.3.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| \--- androidx.compose.material3:material3:1.3.0 (c) -+--- androidx.compose.runtime:runtime-tracing:1.0.0-beta01 -| +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| +--- androidx.compose.runtime:runtime:1.3.3 -> 1.7.2 (*) -| +--- androidx.startup:startup-runtime:1.1.1 (*) -| +--- androidx.tracing:tracing-perfetto:1.0.0 -| | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| | +--- androidx.startup:startup-runtime:1.1.1 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -+--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -+--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (*) -+--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -+--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -+--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (*) -+--- androidx.lifecycle:lifecycle-extensions:2.2.0 -| +--- androidx.lifecycle:lifecycle-runtime:2.2.0 -> 2.8.6 (*) -| +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) -| +--- androidx.arch.core:core-runtime:2.1.0 -> 2.2.0 (*) -| +--- androidx.fragment:fragment:1.2.0 -> 1.8.2 (*) -| +--- androidx.lifecycle:lifecycle-common:2.2.0 -> 2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-livedata:2.2.0 -> 2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-process:2.2.0 -> 2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-service:2.2.0 -> 2.8.6 (*) -| \--- androidx.lifecycle:lifecycle-viewmodel:2.2.0 -> 2.8.6 (*) -+--- androidx.navigation:navigation-compose:2.8.1 (*) -+--- androidx.profileinstaller:profileinstaller:1.4.0 (*) -+--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -+--- io.insert-koin:koin-android:4.0.0-RC2 (*) -+--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -\--- androidx.compose.runtime:runtime -> 1.7.2 (*) diff --git a/mifospay/src/main/java/org/mifospay/MainActivity.kt b/mifospay/src/main/java/org/mifospay/MainActivity.kt deleted file mode 100644 index e17923bd8..000000000 --- a/mifospay/src/main/java/org/mifospay/MainActivity.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay - -import android.os.Bundle -import android.view.Window -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge -import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi -import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import androidx.metrics.performance.JankStats -import androidx.navigation.compose.rememberNavController -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel -import org.koin.core.parameter.parametersOf -import org.mifospay.MainActivityUiState.Loading -import org.mifospay.MainActivityUiState.Success -import org.mifospay.core.analytics.AnalyticsHelper -import org.mifospay.core.analytics.LocalAnalyticsHelper -import org.mifospay.core.data.util.NetworkMonitor -import org.mifospay.core.data.util.TimeZoneMonitor -import org.mifospay.core.designsystem.theme.MifosTheme -import org.mifospay.core.ui.LocalTimeZone -import org.mifospay.navigation.MifosNavGraph.LOGIN_GRAPH -import org.mifospay.navigation.MifosNavGraph.PASSCODE_GRAPH -import org.mifospay.navigation.RootNavGraph -import org.mifospay.ui.rememberMifosAppState - -@OptIn(ExperimentalMaterial3WindowSizeClassApi::class) -class MainActivity : ComponentActivity() { - - /** - * Lazily inject [JankStats], which is used to track jank throughout the app. - */ - - private val networkMonitor: NetworkMonitor by inject() - - private val timeZoneMonitor: TimeZoneMonitor by inject() - - private val analyticsHelper: AnalyticsHelper by inject() - - private val viewModel: MainActivityViewModel by viewModel() - - private val myWindow: Window by inject { parametersOf(this) } - - private val lazyStats: JankStats by inject { parametersOf(myWindow) } - - override fun onCreate(savedInstanceState: Bundle?) { - val splashScreen = installSplashScreen() - super.onCreate(savedInstanceState) - - var uiState: MainActivityUiState by mutableStateOf(Loading) - - // Update the uiState - lifecycleScope.launch { - lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.uiState - .onEach { uiState = it } - .collect() - } - } - - splashScreen.setKeepOnScreenCondition { - when (uiState) { - Loading -> true - is Success -> false - } - } - - enableEdgeToEdge() - - setContent { - val navController = rememberNavController() - - val appState = rememberMifosAppState( - windowSizeClass = calculateWindowSizeClass(this), - networkMonitor = networkMonitor, - timeZoneMonitor = timeZoneMonitor, - ) - - val currentTimeZone by appState.currentTimeZone.collectAsStateWithLifecycle() - - val navDestination = when (uiState) { - is Success -> if ((uiState as Success).userData.isAuthenticated) { - PASSCODE_GRAPH - } else { - LOGIN_GRAPH - } - - else -> LOGIN_GRAPH - } - - CompositionLocalProvider( - LocalAnalyticsHelper provides analyticsHelper, - LocalTimeZone provides currentTimeZone, - ) { - MifosTheme { - RootNavGraph( - appState = appState, - navHostController = navController, - startDestination = navDestination, - onClickLogout = { - viewModel.logOut() - navController.navigate(LOGIN_GRAPH) { - popUpTo(navController.graph.id) { - inclusive = true - } - } - }, - ) - } - } - } - } - - override fun onResume() { - super.onResume() - lazyStats.isTrackingEnabled = true - } - - override fun onPause() { - super.onPause() - lazyStats.isTrackingEnabled = false - } -} diff --git a/mifospay/src/main/java/org/mifospay/MifosPayApp.kt b/mifospay/src/main/java/org/mifospay/MifosPayApp.kt deleted file mode 100644 index e7403cf44..000000000 --- a/mifospay/src/main/java/org/mifospay/MifosPayApp.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay - -import android.app.Application -import org.koin.android.ext.koin.androidContext -import org.koin.core.context.startKoin -import org.koin.core.logger.Level -import org.mifospay.di.KoinModules - -class MifosPayApp : Application() { - override fun onCreate() { - super.onCreate() - val koinModules = KoinModules() - - startKoin { - printLogger(Level.ERROR) - androidContext(this@MifosPayApp) - modules( - listOf( - koinModules.dataModules, - koinModules.mifosPayModule, - koinModules - .coreDataStoreModules, - koinModules.featureModules, - koinModules.networkModules, - koinModules - .analyticsModules, - koinModules.commonModules, - koinModules.libsModule, - ), - ) - } - } -} diff --git a/mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt b/mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt deleted file mode 100644 index aa1210bf6..000000000 --- a/mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.di - -import android.app.Activity -import android.util.Log -import android.view.Window -import androidx.metrics.performance.JankStats -import org.koin.core.module.dsl.viewModel -import org.koin.dsl.module -import org.mifospay.MainActivityViewModel - -val JankStatsModule = module { - - factory { (activity: Activity) -> activity.window } - factory { (window: Window) -> - JankStats.createAndTrack(window) { frameData -> - // Make sure to only log janky frames. - if (frameData.isJank) { - // We're currently logging this but would better report it to a backend. - Log.v("Mifos Jank", frameData.toString()) - } - } - } - - viewModel { - MainActivityViewModel(userDataRepository = get(), passcodeManager = get()) - } -} diff --git a/mifospay/src/main/java/org/mifospay/di/KoinModules.kt b/mifospay/src/main/java/org/mifospay/di/KoinModules.kt deleted file mode 100644 index 72e1d3422..000000000 --- a/mifospay/src/main/java/org/mifospay/di/KoinModules.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.di - -import org.koin.dsl.module -import org.mifos.library.passcode.di.ApplicationModule -import org.mifospay.core.analytics.di.AnalyticsModule -import org.mifospay.core.data.di.DataModule -import org.mifospay.core.data.di.LocalDataModule -import org.mifospay.core.datastore.di.CoreDataStoreModule -import org.mifospay.core.common.di.CoroutineScopesModule -import org.mifospay.core.common.di.DispatchersModule -import org.mifospay.core.network.di.LocalModule -import org.mifospay.core.network.di.NetworkModule -import org.mifospay.feature.auth.di.AuthModule -import org.mifospay.feature.bank.accounts.di.AccountsModule -import org.mifospay.feature.di.HistoryModule -import org.mifospay.feature.editpassword.di.EditPasswordModule -import org.mifospay.feature.faq.di.FaqModule -import org.mifospay.feature.home.di.HomeModule -import org.mifospay.feature.invoices.di.InvoicesModule -import org.mifospay.feature.kyc.di.KYCModule -import org.mifospay.feature.make.transfer.di.MakeTransferModule -import org.mifospay.feature.merchants.di.MerchantsModule -import org.mifospay.feature.notification.di.NotificationModule -import org.mifospay.feature.payments.di.PaymentsModule -import org.mifospay.feature.profile.di.ProfileModule -import org.mifospay.feature.read.qr.di.QrModule -import org.mifospay.feature.receipt.di.ReceiptModule -import org.mifospay.feature.request.money.di.RequestMoneyModule -import org.mifospay.feature.savedcards.di.SavedCardsModule -import org.mifospay.feature.search.di.SearchModule -import org.mifospay.feature.send.money.di.SendMoneyModule -import org.mifospay.feature.settings.di.SettingsModule -import org.mifospay.feature.standing.instruction.di.StandingInstructionModule -import org.mifospay.feature.upiSetup.di.UpiSetupModule - -class KoinModules { - val analyticsModules = module { - includes(AnalyticsModule) - } - val commonModules = module { - includes(CoroutineScopesModule, DispatchersModule) - } - val dataModules = module { - includes(DataModule, LocalDataModule) - } - val coreDataStoreModules = module { - includes(CoreDataStoreModule) - } - val networkModules = module { - includes(LocalModule, NetworkModule) - } - val featureModules = module { - includes( - AuthModule, AccountsModule, EditPasswordModule, FaqModule, HistoryModule, HomeModule, - InvoicesModule, KYCModule, MakeTransferModule, MerchantsModule, NotificationModule, - PaymentsModule, ProfileModule, QrModule, ReceiptModule, RequestMoneyModule, - SavedCardsModule, SearchModule, SendMoneyModule, SettingsModule, - StandingInstructionModule, UpiSetupModule, - ) - } - val mifosPayModule = module { - includes(JankStatsModule) - } - val libsModule = module { - includes(ApplicationModule) - } -} diff --git a/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt b/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt deleted file mode 100644 index dc2a4acc5..000000000 --- a/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.navigation - -import android.content.Context -import android.net.Uri -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.core.content.FileProvider -import androidx.navigation.compose.NavHost -import com.mifos.library.material3.navigation.ModalBottomSheetLayout -import org.mifospay.core.common.Constants -import org.mifospay.core.ui.utility.TabContent -import org.mifospay.feature.bank.accounts.AccountsScreen -import org.mifospay.feature.bank.accounts.navigation.bankAccountDetailScreen -import org.mifospay.feature.bank.accounts.navigation.linkBankAccountScreen -import org.mifospay.feature.bank.accounts.navigation.navigateToBankAccountDetail -import org.mifospay.feature.bank.accounts.navigation.navigateToLinkBankAccount -import org.mifospay.feature.editpassword.navigation.editPasswordScreen -import org.mifospay.feature.editpassword.navigation.navigateToEditPassword -import org.mifospay.feature.faq.navigation.faqScreen -import org.mifospay.feature.finance.FinanceScreenContents -import org.mifospay.feature.finance.navigation.financeScreen -import org.mifospay.feature.history.HistoryScreen -import org.mifospay.feature.home.navigation.HOME_ROUTE -import org.mifospay.feature.home.navigation.homeScreen -import org.mifospay.feature.invoices.InvoiceScreenRoute -import org.mifospay.feature.invoices.navigation.invoiceDetailScreen -import org.mifospay.feature.invoices.navigation.navigateToInvoiceDetail -import org.mifospay.feature.kyc.KYCScreen -import org.mifospay.feature.kyc.navigation.kycLevel1Screen -import org.mifospay.feature.kyc.navigation.kycLevel2Screen -import org.mifospay.feature.kyc.navigation.kycLevel3Screen -import org.mifospay.feature.kyc.navigation.kycScreen -import org.mifospay.feature.kyc.navigation.navigateToKYCLevel1 -import org.mifospay.feature.kyc.navigation.navigateToKYCLevel2 -import org.mifospay.feature.kyc.navigation.navigateToKYCLevel3 -import org.mifospay.feature.make.transfer.navigation.makeTransferScreen -import org.mifospay.feature.make.transfer.navigation.navigateToMakeTransferScreen -import org.mifospay.feature.merchants.navigation.merchantTransferScreen -import org.mifospay.feature.merchants.ui.MerchantScreen -import org.mifospay.feature.notification.notificationScreen -import org.mifospay.feature.payments.PaymentsScreenContents -import org.mifospay.feature.payments.RequestScreen -import org.mifospay.feature.payments.paymentsScreen -import org.mifospay.feature.profile.navigation.editProfileScreen -import org.mifospay.feature.profile.navigation.navigateToEditProfile -import org.mifospay.feature.profile.navigation.profileScreen -import org.mifospay.feature.read.qr.navigation.readQrScreen -import org.mifospay.feature.receipt.navigation.navigateToReceipt -import org.mifospay.feature.receipt.navigation.receiptScreen -import org.mifospay.feature.request.money.navigation.navigateToShowQrScreen -import org.mifospay.feature.request.money.navigation.showQrScreen -import org.mifospay.feature.savedcards.CardsScreen -import org.mifospay.feature.savedcards.navigation.addCardScreen -import org.mifospay.feature.search.searchScreen -import org.mifospay.feature.send.money.SendScreenRoute -import org.mifospay.feature.send.money.navigation.navigateToSendMoneyScreen -import org.mifospay.feature.send.money.navigation.sendMoneyScreen -import org.mifospay.feature.settings.navigation.navigateToSettings -import org.mifospay.feature.settings.navigation.settingsScreen -import org.mifospay.feature.specific.transactions.navigation.navigateToSpecificTransactions -import org.mifospay.feature.specific.transactions.navigation.specificTransactionsScreen -import org.mifospay.feature.standing.instruction.StandingInstructionsScreenRoute -import org.mifospay.feature.standing.instruction.navigateToNewSiScreen -import org.mifospay.feature.standing.instruction.newSiScreen -import org.mifospay.feature.standing.instruction.siDetailsScreen -import org.mifospay.feature.upiSetup.navigation.navigateToSetupUpiPin -import org.mifospay.feature.upiSetup.navigation.setupUpiPinScreen -import org.mifospay.ui.MifosAppState -import java.io.File -import java.util.Objects - -/** - * Top-level navigation graph. Navigation is organized as explained at - * https://d.android.com/jetpack/compose/nav-adaptive - * - * The navigation graph defined in this file defines the different top level routes. Navigation - * within each route is handled using state and Back Handlers. - */ -@Suppress("MaxLineLength", "LongMethod") -@Composable -internal fun MifosNavHost( - appState: MifosAppState, - onClickLogout: () -> Unit, - modifier: Modifier = Modifier, -) { - val navController = appState.navController - - val tabContents = listOf( - TabContent(FinanceScreenContents.ACCOUNTS.name) { - AccountsScreen( - navigateToBankAccountDetailScreen = navController::navigateToBankAccountDetail, - navigateToLinkBankAccountScreen = navController::navigateToLinkBankAccount, - ) - }, - TabContent(FinanceScreenContents.CARDS.name) { - CardsScreen(onEditCard = {}) - }, - TabContent(FinanceScreenContents.MERCHANTS.name) { - MerchantScreen() - }, - TabContent(FinanceScreenContents.KYC.name) { - KYCScreen( - onLevel1Clicked = navController::navigateToKYCLevel1, - onLevel2Clicked = navController::navigateToKYCLevel2, - onLevel3Clicked = navController::navigateToKYCLevel3, - ) - }, - ) - - val paymentsTabContents = listOf( - TabContent(PaymentsScreenContents.SEND.name) { - SendScreenRoute( - onBackClick = {}, - showToolBar = false, - proceedWithMakeTransferFlow = navController::navigateToMakeTransferScreen, - ) - }, - TabContent(PaymentsScreenContents.REQUEST.name) { - RequestScreen(showQr = navController::navigateToShowQrScreen) - }, - TabContent(PaymentsScreenContents.HISTORY.name) { - HistoryScreen( - accountClicked = navController::navigateToSpecificTransactions, - viewReceipt = { - navController - .navigateToReceipt(Uri.parse(Constants.RECEIPT_DOMAIN + it)) - }, - ) - }, - TabContent(PaymentsScreenContents.SI.name) { - StandingInstructionsScreenRoute( - onNewSI = navController::navigateToNewSiScreen, - onBackPress = navController::popBackStack, - ) - }, - TabContent(PaymentsScreenContents.INVOICES.name) { - InvoiceScreenRoute( - navigateToInvoiceDetailScreen = { - navController.navigateToInvoiceDetail(it.toString()) - }, - ) - }, - ) - - ModalBottomSheetLayout( - bottomSheetNavigator = appState.bottomSheetNavigator, - modifier = modifier, - ) { - NavHost( - route = MifosNavGraph.MAIN_GRAPH, - startDestination = HOME_ROUTE, - navController = navController, - ) { - homeScreen( - onRequest = navController::navigateToShowQrScreen, - onPay = navController::navigateToSendMoneyScreen, - ) - paymentsScreen( - tabContents = paymentsTabContents, - ) - financeScreen( - tabContents = tabContents, - ) - addCardScreen( - onDismiss = navController::popBackStack, - onAddCard = { - // Handle adding the cards - navController.popBackStack() - }, - ) - profileScreen( - onEditProfile = navController::navigateToEditProfile, - onSettings = navController::navigateToSettings, - ) - sendMoneyScreen( - onBackClick = navController::popBackStack, - proceedWithMakeTransferFlow = navController::navigateToMakeTransferScreen, - ) - makeTransferScreen( - onDismiss = navController::popBackStack, - ) - showQrScreen( - onBackClick = navController::popBackStack, - ) - merchantTransferScreen( - proceedWithMakeTransferFlow = navController::navigateToMakeTransferScreen, - onBackPressed = navController::popBackStack, - ) - settingsScreen( - onBackPress = navController::popBackStack, - navigateToEditPasswordScreen = navController::navigateToEditPassword, - onLogout = onClickLogout, - onChangePasscode = { - // TODO:: Implement change passcode screen - }, - ) - - kycScreen( - onLevel1Clicked = navController::navigateToKYCLevel1, - onLevel2Clicked = navController::navigateToKYCLevel2, - onLevel3Clicked = navController::navigateToKYCLevel3, - ) - kycLevel1Screen( - navigateToKycLevel2 = navController::navigateToKYCLevel2, - ) - kycLevel2Screen( - onSuccessKyc2 = navController::navigateToKYCLevel3, - ) - - kycLevel3Screen() - - newSiScreen(onBackClick = navController::popBackStack) - - siDetailsScreen( - onClickCreateNew = navController::navigateToNewSiScreen, - onBackPress = navController::popBackStack, - ) - - editProfileScreen( - onBackPress = navController::popBackStack, - getUri = ::getUri, - ) - - faqScreen( - navigateBack = navController::popBackStack, - ) - readQrScreen( - onBackClick = navController::popBackStack, - ) - - specificTransactionsScreen( - onBackClick = navController::popBackStack, - onTransactionItemClicked = { transactionId -> - navController.navigateToReceipt(Uri.parse(Constants.RECEIPT_DOMAIN + transactionId)) - }, - ) - invoiceDetailScreen( - onBackPress = navController::popBackStack, - navigateToReceiptScreen = { uri -> - navController.navigateToReceipt(Uri.parse(Constants.RECEIPT_DOMAIN + uri)) - }, - ) - receiptScreen( - openPassCodeActivity = { - // TODO: Implement Passcode Screen for Receipt - }, - onBackClick = navController::popBackStack, - ) - setupUpiPinScreen( - onBackPress = navController::popBackStack, - ) - - bankAccountDetailScreen( - onSetupUpiPin = { bankAccountDetails, index -> - navController.navigateToSetupUpiPin(bankAccountDetails, index, Constants.SETUP) - }, - onChangeUpiPin = { bankAccountDetails, index -> - navController.navigateToSetupUpiPin(bankAccountDetails, index, Constants.CHANGE) - }, - onForgotUpiPin = { bankAccountDetails, index -> - navController.navigateToSetupUpiPin(bankAccountDetails, index, Constants.FORGOT) - }, - onBackClick = { bankAccountDetails, index -> - navController.previousBackStackEntry?.savedStateHandle?.set( - Constants.UPDATED_BANK_ACCOUNT, - bankAccountDetails, - ) - navController.previousBackStackEntry?.savedStateHandle?.set( - Constants.INDEX, - index, - ) - navController.popBackStack() - }, - ) - linkBankAccountScreen( - onBackClick = navController::popBackStack, - ) - editPasswordScreen( - onBackPress = navController::popBackStack, - onCancelChanges = navController::popBackStack, - ) - - notificationScreen() - - searchScreen(onBackClick = navController::popBackStack) - } - } -} - -fun getUri(context: Context, file: File): Uri { - val uri = FileProvider.getUriForFile( - Objects.requireNonNull(context), - org.mifospay.BuildConfig.APPLICATION_ID + ".provider", - file, - ) - return uri -} diff --git a/mifospay/src/main/java/org/mifospay/navigation/PasscodeNavGraph.kt b/mifospay/src/main/java/org/mifospay/navigation/PasscodeNavGraph.kt deleted file mode 100644 index a672817e2..000000000 --- a/mifospay/src/main/java/org/mifospay/navigation/PasscodeNavGraph.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.navigation - -import androidx.navigation.NavController -import androidx.navigation.NavGraphBuilder -import androidx.navigation.navigation -import org.mifos.library.passcode.PASSCODE_SCREEN -import org.mifos.library.passcode.passcodeRoute - -internal fun NavGraphBuilder.passcodeNavGraph(navController: NavController) { - navigation( - route = MifosNavGraph.PASSCODE_GRAPH, - startDestination = PASSCODE_SCREEN, - ) { - passcodeRoute( - onForgotButton = { - navController.popBackStack() - navController.navigate(MifosNavGraph.MAIN_GRAPH) - }, - onSkipButton = { - navController.popBackStack() - navController.navigate(MifosNavGraph.MAIN_GRAPH) - }, - onPasscodeConfirm = { - navController.popBackStack() - navController.navigate(MifosNavGraph.MAIN_GRAPH) - }, - onPasscodeRejected = { - navController.popBackStack() - navController.navigate(MifosNavGraph.MAIN_GRAPH) - }, - ) - } -} diff --git a/scripts/pre-commit.sh b/scripts/pre-commit.sh index c49bfe109..2f87f220e 100644 --- a/scripts/pre-commit.sh +++ b/scripts/pre-commit.sh @@ -74,26 +74,6 @@ run_detekt_checks() { fi } -# Function to run Version Catalog checks -run_version_catalog_checks() { - echo "\n🚀 Version catalog linter is now analyzing your catalog for potential issues!" - ./gradlew formatVersionCatalog > /tmp/catalog-result - DETEKT_EXIT_CODE=$? - - if [ ${DETEKT_EXIT_CODE} -ne 0 ]; then - cat /tmp/catalog-result - rm /tmp/catalog-result - echo "\n*********************************************************************************" - echo " 💥 Oh no! Version Catalog found issues in the code! Time to fix those issues! 💥" - echo " 💡 Tip: Review the Version Catalog logs to resolve these issues. 🛠️" - echo "*********************************************************************************" - exit ${DETEKT_EXIT_CODE} - else - rm /tmp/catalog-result - echo "🎉 Fantastic work! Your Version catalog has been formatted successfully 🚀🌟" - fi -} - # Function to print success message print_success_message() { GIT_USERNAME=$(git config user.name) @@ -109,7 +89,6 @@ check_current_branch run_spotless_checks run_detekt_checks run_dependency_guard -run_version_catalog_checks print_success_message exit 0 diff --git a/scripts/pre-push.sh b/scripts/pre-push.sh index cad5ba9a1..d628bc07b 100644 --- a/scripts/pre-push.sh +++ b/scripts/pre-push.sh @@ -80,29 +80,6 @@ run_dependency_guard() { fi } -# Function to run Version Catalog checks -run_version_catalog_checks() { - echo "\n🚀 Version catalog linter is now analyzing your catalog for potential issues!" - ./gradlew checkVersionCatalog > /tmp/catalog-result - DETEKT_EXIT_CODE=$? - - if [ ${DETEKT_EXIT_CODE} -ne 0 ]; then - cat /tmp/catalog-result - rm /tmp/catalog-result - echo "\n*********************************************************************************" - echo " 💥 Oh no! Version Catalog found issues in the code! Time to fix those issues! 💥" - echo " 💡 Tip: Review the Version Catalog logs to resolve these issues. 🛠️" - echo "*********************************************************************************" - echo "🚀 Attempting to format the Version Catalog again..." - ./gradlew formatVersionCatalog > /tmp/catalog-result - rm /tmp/catalog-result - echo "🎉 Fantastic work! Your Version catalog has been formatted successfully 🚀🌟" - else - rm /tmp/catalog-result - echo "🎉 Fantastic work! Your Version catalog has been formatted properly 🚀🌟" - fi -} - # Function to print success message print_success_message() { GIT_USERNAME=$(git config user.name) @@ -118,7 +95,6 @@ check_current_branch run_spotless_checks run_detekt_checks run_dependency_guard -run_version_catalog_checks print_success_message exit 0 diff --git a/settings.gradle.kts b/settings.gradle.kts index f43a17c79..1ccad1d2f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -34,9 +34,14 @@ extensions.configure { rootProject.name = "mobile-wallet" enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -include(":mifospay") + +include(":mifospay-shared") +include(":mifospay-android") +include(":mifospay-desktop") +include(":mifospay-web") include(":core:data") +include(":core:domain") include(":core:datastore") include(":core:designsystem") include(":core:ui") @@ -47,8 +52,6 @@ include(":core:model") include(":core:datastore-proto") include(":core:analytics") -include(":lint") - include(":feature:home") include(":feature:history") include(":feature:receipt") @@ -74,10 +77,9 @@ include(":feature:upi-setup") include(":feature:qr") include(":feature:search") +include(":lint") + include(":libs:country-code-picker") include(":libs:pullrefresh") include(":libs:material3-navigation") include(":libs:mifos-passcode") - -include(":shared") -include(":desktop") diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts deleted file mode 100644 index fec478782..000000000 --- a/shared/build.gradle.kts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.android.library) - alias(libs.plugins.compose.compiler) - alias(libs.plugins.jetbrainsCompose) - alias(libs.plugins.wire) - id("kotlin-parcelize") -} - -kotlin { - androidTarget { - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_11) - } - } - - jvm("desktop") - - listOf( - iosX64(), - iosArm64(), - iosSimulatorArm64() - ).forEach { - it.binaries.framework { - baseName = "shared" - isStatic = true - } - } - - sourceSets { - androidMain.dependencies { - implementation(compose.preview) - implementation(libs.androidx.activity.compose) - - implementation(libs.koin.android) - implementation(libs.koin.androidx.compose) - } - - commonMain.dependencies { - //put your multiplatform dependencies here - implementation(compose.runtime) - implementation(compose.material3) - implementation(compose.ui) - implementation(compose.components.resources) - implementation(compose.components.uiToolingPreview) - - implementation(libs.kotlinx.datetime) - implementation(libs.kotlinx.serialization.json) - - api(libs.koin.core) - implementation(libs.koin.compose) - - implementation(libs.datastore) - } - - val desktopMain by getting { - dependencies { - // Desktop specific dependencies - implementation(compose.desktop.currentOs) - implementation(compose.desktop.common) - } - } - } - - task("testClasses") -} - -wire { - kotlin {} - sourcePath { - srcDir("src/commonMain/proto") - } -} - -android { - namespace = "org.mifospay.shared" - compileSdk = 34 - - defaultConfig { - minSdk = 24 - } - - packaging { - resources { - excludes += "/META-INF/{AL2.0,LGPL2.1}" - } - } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } - - dependencies { - debugImplementation(compose.uiTooling) - } -} diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/MainActivity.kt b/shared/src/androidMain/kotlin/org/mifospay/shared/MainActivity.kt deleted file mode 100644 index e65339b5a..000000000 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/MainActivity.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Preview - -class MainActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setContent { - App() - } - } -} - -@Preview -@Composable -fun AppAndroidPreview() { - App() -} diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/Platform.android.kt b/shared/src/androidMain/kotlin/org/mifospay/shared/Platform.android.kt deleted file mode 100644 index 909044b97..000000000 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/Platform.android.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -class AndroidPlatform : Platform { - override val name: String = "Android ${android.os.Build.VERSION.SDK_INT}" -} - -actual fun getPlatform(): Platform = AndroidPlatform() - -actual typealias CommonParcelize = Parcelize -actual typealias CommonParcelable = Parcelable diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/di/AndroidPlatformContextProvider.kt b/shared/src/androidMain/kotlin/org/mifospay/shared/di/AndroidPlatformContextProvider.kt deleted file mode 100644 index 9c6908224..000000000 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/di/AndroidPlatformContextProvider.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.di - -import android.content.Context - -object AndroidPlatformContextProvider { - private var appContext: Context? = null - - val context: Context? - get() = appContext - - fun setContext(context: Context) { - appContext = context - } -} diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.android.kt b/shared/src/androidMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.android.kt deleted file mode 100644 index 7976d9c2b..000000000 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.android.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.DataStore -import okio.FileSystem -import okio.Path.Companion.toPath -import org.mifospay.shared.commonMain.proto.UserPreferences -import org.mifospay.shared.di.AndroidPlatformContextProvider - -actual fun getDataStore(): DataStore { - val content = requireNotNull(AndroidPlatformContextProvider.context) - val producePath = { content.filesDir.resolve(DATA_STORE_FILE_NAME).absolutePath.toPath() } - - return createDataStore(fileSystem = FileSystem.SYSTEM, producePath = producePath) -} diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/App.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/App.kt deleted file mode 100644 index 8e9fb5365..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/App.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -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.text.font.FontWeight -import org.koin.compose.KoinContext - -@Composable -fun App() { - KoinContext { - Box( - modifier = Modifier - .fillMaxSize(), - contentAlignment = Alignment.Center, - ) { - Text( - text = "MifosWallet", - style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold), - color = MaterialTheme.colorScheme.onSurface, - ) - } - } -} diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/Platform.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/Platform.kt deleted file mode 100644 index 00ed0030d..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/Platform.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -interface Platform { - val name: String -} - -expect fun getPlatform(): Platform - -// For Android @Parcelize -@OptIn(ExperimentalMultiplatform::class) -@OptionalExpectation -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.BINARY) -expect annotation class CommonParcelize() - -// For Android Parcelable -expect interface CommonParcelable diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Client.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Client.kt deleted file mode 100644 index 60f1e2d05..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Client.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.modal.domain - -data class Client( - var name: String? = null, - var image: String, - var externalId: String? = null, - var clientId: Long = 0L, - var displayName: String, - var mobileNo: String, -) diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/User.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/User.kt deleted file mode 100644 index dad50bcc7..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/User.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.modal.domain - -data class User( - val username: String, - val userId: Long = 0, - val base64EncodedAuthenticationKey: String, - val authenticated: Boolean = false, - val officeId: Int, - val officeName: String, - val roles: List, - val permissions: List, - val clients: List, - val shouldRenewPassword: Boolean, - val isTwoFactorAuthenticationRequired: Boolean, -) diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/UserData.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/UserData.kt deleted file mode 100644 index 4191ecd67..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/UserData.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.modal.domain - -data class UserData( - val authToken: String, - val user: String, - val userEmail: String, - val client: String, -) diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.kt deleted file mode 100644 index 2c7fbe6f2..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.DataStore -import androidx.datastore.core.DataStoreFactory -import androidx.datastore.core.okio.OkioStorage -import okio.FileSystem -import okio.Path -import org.mifospay.shared.commonMain.proto.UserPreferences -internal const val DATA_STORE_FILE_NAME = "user.preferences_pb" - -expect fun getDataStore(): DataStore - -fun createDataStore( - fileSystem: FileSystem, - producePath: () -> Path, -): DataStore = - DataStoreFactory.create( - storage = OkioStorage( - fileSystem = fileSystem, - producePath = producePath, - serializer = UserPreferenceSerializer, - ), - ) diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceRepository.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceRepository.kt deleted file mode 100644 index 294905f01..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceRepository.kt +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.DataStore -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import org.mifospay.shared.commonMain.proto.Client -import org.mifospay.shared.commonMain.proto.User -import org.mifospay.shared.commonMain.proto.UserPreferences - -interface UserPreferenceRepository { - suspend fun saveToken(token: String) - fun getToken(): Flow - suspend fun saveFullName(name: String) - fun getFullName(): Flow - suspend fun saveUsername(name: String) - fun getUsername(): Flow - suspend fun saveEmail(email: String) - fun getEmail(): Flow - suspend fun saveMobile(mobile: String) - fun getMobile(): Flow - fun getUserId(): Flow - suspend fun setUserId(id: Int) - fun getClientId(): Flow - suspend fun setClientId(clientId: Int) - fun getClientVpa(): Flow - suspend fun setClientVpa(vpa: String) - fun getAccountId(): Flow - suspend fun setAccountId(accountId: Int) - fun getFirebaseRegId(): Flow - suspend fun setFirebaseRegId(firebaseRegId: String) - fun getUser(): Flow - suspend fun setUser(user: User) - fun getClient(): Flow - suspend fun setClient(client: Client) -} - -class UserPreferenceRepositoryImpl( - private val dataStore: DataStore = getDataStore(), -) : UserPreferenceRepository { - - override suspend fun saveToken(token: String) { - dataStore.updateData { preferences -> - preferences.copy(token = token) - } - } - - override fun getToken(): Flow { - return dataStore.data.map { it.token } - } - - override suspend fun saveFullName(name: String) { - dataStore.updateData { preferences -> - preferences.copy(name = name) - } - } - - override fun getFullName(): Flow { - return dataStore.data.map { it.name } - } - - override suspend fun saveUsername(name: String) { - dataStore.updateData { preferences -> - preferences.copy(username = name) - } - } - - override fun getUsername(): Flow { - return dataStore.data.map { it.username } - } - - override suspend fun saveEmail(email: String) { - dataStore.updateData { preferences -> - preferences.copy(email = email) - } - } - - override fun getEmail(): Flow { - return dataStore.data.map { it.email } - } - - override suspend fun saveMobile(mobile: String) { - dataStore.updateData { preferences -> - preferences.copy(mobile_no = mobile) - } - } - - override fun getMobile(): Flow { - return dataStore.data.map { it.mobile_no } - } - - override fun getUserId(): Flow { - return dataStore.data.map { it.user_id } - } - - override suspend fun setUserId(id: Int) { - dataStore.updateData { preferences -> - preferences.copy(user_id = id) - } - } - - override fun getClientId(): Flow { - return dataStore.data.map { it.client_id } - } - - override suspend fun setClientId(clientId: Int) { - dataStore.updateData { preferences -> - preferences.copy(client_id = clientId) - } - } - - override fun getClientVpa(): Flow { - return dataStore.data.map { it.client_vpa } - } - - override suspend fun setClientVpa(vpa: String) { - dataStore.updateData { preferences -> - preferences.copy(client_vpa = vpa) - } - } - - override fun getAccountId(): Flow { - return dataStore.data.map { it.account_id } - } - - override suspend fun setAccountId(accountId: Int) { - dataStore.updateData { preferences -> - preferences.copy(account_id = accountId) - } - } - - override fun getFirebaseRegId(): Flow { - return dataStore.data.map { it.firebase_reg_id } - } - - override suspend fun setFirebaseRegId(firebaseRegId: String) { - dataStore.updateData { preferences -> - preferences.copy(firebase_reg_id = firebaseRegId) - } - } - - override fun getUser(): Flow { - return dataStore.data.map { it.user!! } - } - - override suspend fun setUser(user: User) { - dataStore.updateData { preferences -> - preferences.copy(user = user) - } - } - - override fun getClient(): Flow { - return dataStore.data.map { it.client!! } - } - - override suspend fun setClient(client: Client) { - dataStore.updateData { preferences -> - preferences.copy(client = client) - } - } -} diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceSerializer.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceSerializer.kt deleted file mode 100644 index 803b106af..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceSerializer.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.okio.OkioSerializer -import okio.BufferedSink -import okio.BufferedSource -import okio.IOException -import org.mifospay.shared.commonMain.proto.UserPreferences - -object UserPreferenceSerializer : OkioSerializer { - override val defaultValue: UserPreferences - get() = UserPreferences() - - override suspend fun readFrom(source: BufferedSource): UserPreferences { - try { - return UserPreferences.ADAPTER.decode(source) - } catch (exception: IOException) { - throw Exception(exception.message ?: "Serialization Exception") - } - } - - override suspend fun writeTo(t: UserPreferences, sink: BufferedSink) { - sink.write(t.encode()) - } -} diff --git a/shared/src/commonMain/proto/user_preferences.proto b/shared/src/commonMain/proto/user_preferences.proto deleted file mode 100644 index 1a7a43dc5..000000000 --- a/shared/src/commonMain/proto/user_preferences.proto +++ /dev/null @@ -1,49 +0,0 @@ -syntax = "proto3"; - -option java_package = "org.mifospay.shared.commonMain.proto"; -option java_multiple_files = true; - -message UserPreferences { - string token = 1; - string name = 2; - string username = 3; - string email = 4; - string mobile_no = 5; - int32 user_id = 6; - int32 client_id = 7; - string client_vpa = 8; - int32 account_id = 9; - string firebase_reg_id = 10; - Client client = 11; - User user = 12; -} - -message Client { - string name = 1; - string image = 2; - string external_id = 3; - int64 clientId = 4; - string display_name = 5; - string mobileNo = 6; -} - -message User { - string username = 1; - int64 userId = 2; - string base64EncodedAuthenticationKey = 3; - bool authenticated = 4; - int32 officeId = 5; - string officeName = 6; - repeated Role roles = 7; - repeated string permissions = 8; - repeated int64 clients = 9; - bool shouldRenewPassword = 10; - bool isTwoFactorAuthenticationRequired = 11; -} - -message Role { - string id = 1; - string name = 2; - string description = 3; - bool disabled = 4; -} \ No newline at end of file diff --git a/shared/src/desktopMain/kotlin/org/mifospay/shared/Platform.desktop.kt b/shared/src/desktopMain/kotlin/org/mifospay/shared/Platform.desktop.kt deleted file mode 100644 index fcc74d588..000000000 --- a/shared/src/desktopMain/kotlin/org/mifospay/shared/Platform.desktop.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import androidx.compose.runtime.Composable - -@Composable -fun MainView() = App() - -class JVMPlatform : Platform { - override val name: String = "Windows" -} - -actual fun getPlatform(): Platform = JVMPlatform() - -actual interface CommonParcelable diff --git a/shared/src/desktopMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.desktop.kt b/shared/src/desktopMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.desktop.kt deleted file mode 100644 index 64fe263b0..000000000 --- a/shared/src/desktopMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.desktop.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.DataStore -import okio.FileSystem -import okio.Path.Companion.toPath -import org.mifospay.shared.commonMain.proto.UserPreferences -import java.io.File - -actual fun getDataStore(): DataStore { - val dbFile = File(System.getProperty("java.io.tmpdir"), DATA_STORE_FILE_NAME) - - return createDataStore( - fileSystem = FileSystem.SYSTEM, - producePath = { dbFile.absolutePath.toPath() }, - ) -} diff --git a/shared/src/iosMain/kotlin/org/mifospay/shared/MainViewController.kt b/shared/src/iosMain/kotlin/org/mifospay/shared/MainViewController.kt deleted file mode 100644 index 1f5f6765a..000000000 --- a/shared/src/iosMain/kotlin/org/mifospay/shared/MainViewController.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import androidx.compose.ui.window.ComposeUIViewController -import org.mifospay.shared.di.initKoin - -fun mainViewController() = ComposeUIViewController( - configure = { - initKoin() - }, -) { - App() -} diff --git a/shared/src/iosMain/kotlin/org/mifospay/shared/Platform.ios.kt b/shared/src/iosMain/kotlin/org/mifospay/shared/Platform.ios.kt deleted file mode 100644 index 22fb77da7..000000000 --- a/shared/src/iosMain/kotlin/org/mifospay/shared/Platform.ios.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import platform.UIKit.UIDevice - -class IOSPlatform : Platform { - override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion -} - -actual fun getPlatform(): Platform = IOSPlatform() - -actual interface CommonParcelable diff --git a/shared/src/iosMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.ios.kt b/shared/src/iosMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.ios.kt deleted file mode 100644 index 6e7e19d38..000000000 --- a/shared/src/iosMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.ios.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.DataStore -import okio.FileSystem -import okio.Path.Companion.toPath -import org.mifospay.shared.commonMain.proto.UserPreferences - -actual fun getDataStore(): DataStore { - return createDataStore( - fileSystem = FileSystem.SYSTEM, - producePath = { "${documentDirectory()}/$DATA_STORE_FILE_NAME".toPath() }, - ) -} - -private fun documentDirectory(): String { - val documentDirectory = NSFileManager.defaultManager.URLForDirectory( - directory = NSDocumentDirectory, - inDomain = NSUserDomainMask, - appropriateForURL = null, - create = false, - error = null, - ) - return requireNotNull(documentDirectory?.path) -} From a1ca686adca9002f80ca5e301b8e5d252094a008 Mon Sep 17 00:00:00 2001 From: Sk Niyaj Ali Date: Tue, 8 Oct 2024 06:58:52 +0530 Subject: [PATCH 09/31] Feat: Migrated Passcode Module to KMP (#1783) --- libs/mifos-passcode/build.gradle.kts | 68 ++++-- .../{main => androidMain}/AndroidManifest.xml | 0 .../lib_mifos_passcode_mifos_logo.jpg | Bin .../font/lib_mifos_passcode_lato_black.ttf | Bin .../font/lib_mifos_passcode_lato_bold.ttf | Bin .../font/lib_mifos_passcode_lato_regular.ttf | Bin .../composeResources}/values/strings.xml | 0 .../mifos/library/passcode/PassCodeScreen.kt | 84 ++++---- .../library/passcode/PasscodeNavigation.kt | 0 .../library/passcode/component/MifosIcon.kt | 7 +- .../passcode/component/PasscodeButton.kt | 13 +- .../passcode/component/PasscodeHeader.kt | 15 +- .../passcode/component/PasscodeKeys.kt | 7 +- .../component/PasscodeMismatchedDialog.kt | 10 +- .../component/PasscodeStepIndicator.kt | 0 .../passcode/component/PasscodeToolbar.kt | 13 +- .../library/passcode/di/PasscodeModule.kt | 21 ++ .../org/mifos/library/passcode/theme/Color.kt | 0 .../org/mifos/library/passcode/theme/Font.kt | 47 +++++ .../org/mifos/library/passcode/theme/Theme.kt | 2 +- .../org/mifos/library/passcode/theme/Type.kt | 12 -- .../library/passcode/utility/Constants.kt | 0 .../passcode/utility/ShakeAnimation.kt | 0 .../mifos/library/passcode/utility/Step.kt | 2 +- .../passcode/viewmodels/PasscodeViewModel.kt | 199 ++++++++++++++++++ .../library/passcode/data/PasscodeManager.kt | 48 +++++ .../data/PasscodePreferencesDataSource.kt | 66 ++++++ .../library/passcode/di/PreferenceModule.kt | 23 ++ .../model/PasscodePreferencesProto.kt} | 16 +- .../passcode/passcode_preferences.proto | 8 + .../library/passcode/data/PasscodeManager.kt | 29 --- .../passcode/data/PasscodeRepositoryImpl.kt | 28 --- .../library/passcode/di/ApplicationModule.kt | 35 --- .../org/mifos/library/passcode/theme/Font.kt | 34 --- .../passcode/utility/PreferenceManager.kt | 39 ---- .../passcode/utility/VibrationFeedback.kt | 48 ----- .../passcode/viewmodels/PasscodeViewModel.kt | 148 ------------- .../lib_mifos_passcode_delete_forever.xml | 15 -- .../drawable/lib_mifos_passcode_ic_delete.xml | 20 -- mifospay-shared/build.gradle.kts | 1 + .../kotlin/org/mifospay/shared/MifosPayApp.kt | 4 +- .../org/mifospay/shared/MifosPayViewModel.kt | 4 +- .../org/mifospay/shared/di/KoinModules.kt | 5 + .../shared/navigation/LoginNavGraph.kt | 4 +- .../shared/navigation/PasscodeNavGraph.kt | 42 ++++ .../shared/navigation/RootNavGraph.kt | 2 +- 46 files changed, 609 insertions(+), 510 deletions(-) rename libs/mifos-passcode/src/{main => androidMain}/AndroidManifest.xml (100%) rename libs/mifos-passcode/src/{main/res => commonMain/composeResources}/drawable/lib_mifos_passcode_mifos_logo.jpg (100%) rename libs/mifos-passcode/src/{main/res => commonMain/composeResources}/font/lib_mifos_passcode_lato_black.ttf (100%) rename libs/mifos-passcode/src/{main/res => commonMain/composeResources}/font/lib_mifos_passcode_lato_bold.ttf (100%) rename libs/mifos-passcode/src/{main/res => commonMain/composeResources}/font/lib_mifos_passcode_lato_regular.ttf (100%) rename libs/mifos-passcode/src/{main/res => commonMain/composeResources}/values/strings.xml (100%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/PassCodeScreen.kt (76%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/PasscodeNavigation.kt (100%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/component/MifosIcon.kt (75%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/component/PasscodeButton.kt (77%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/component/PasscodeHeader.kt (84%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/component/PasscodeKeys.kt (96%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/component/PasscodeMismatchedDialog.kt (71%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/component/PasscodeStepIndicator.kt (100%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/component/PasscodeToolbar.kt (79%) create mode 100644 libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/di/PasscodeModule.kt rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/theme/Color.kt (100%) create mode 100644 libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Font.kt rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/theme/Theme.kt (97%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/theme/Type.kt (71%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/utility/Constants.kt (100%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/utility/ShakeAnimation.kt (100%) rename libs/mifos-passcode/src/{main => commonMain}/kotlin/org/mifos/library/passcode/utility/Step.kt (90%) create mode 100644 libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt create mode 100644 libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/data/PasscodeManager.kt create mode 100644 libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/data/PasscodePreferencesDataSource.kt create mode 100644 libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/di/PreferenceModule.kt rename libs/mifos-passcode/src/{main/kotlin/org/mifos/library/passcode/data/PasscodeRepository.kt => commonMain/kotlin/proto/org/mifos/library/passcode/model/PasscodePreferencesProto.kt} (51%) create mode 100644 libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/passcode_preferences.proto delete mode 100644 libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeManager.kt delete mode 100644 libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepositoryImpl.kt delete mode 100644 libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/di/ApplicationModule.kt delete mode 100644 libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Font.kt delete mode 100644 libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/PreferenceManager.kt delete mode 100644 libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/VibrationFeedback.kt delete mode 100644 libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt delete mode 100644 libs/mifos-passcode/src/main/res/drawable/lib_mifos_passcode_delete_forever.xml delete mode 100644 libs/mifos-passcode/src/main/res/drawable/lib_mifos_passcode_ic_delete.xml create mode 100644 mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/PasscodeNavGraph.kt diff --git a/libs/mifos-passcode/build.gradle.kts b/libs/mifos-passcode/build.gradle.kts index 93d85ab8f..64cb920fc 100644 --- a/libs/mifos-passcode/build.gradle.kts +++ b/libs/mifos-passcode/build.gradle.kts @@ -8,39 +8,61 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.library) - alias(libs.plugins.mifospay.android.library.compose) - id("com.google.devtools.ksp") + alias(libs.plugins.mifospay.cmp.feature) + alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.protobuf) } android { namespace = "com.mifos.library.passcode" } -dependencies { - implementation(libs.androidx.core.ktx) +kotlin { + sourceSets { + commonMain.dependencies { + implementation(compose.ui) + implementation(compose.foundation) + implementation(compose.material3) + implementation(compose.materialIconsExtended) + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) - implementation(libs.androidx.compose.foundation) - implementation(libs.androidx.compose.foundation.layout) - implementation(libs.androidx.compose.material.iconsExtended) - implementation(libs.androidx.compose.material3) - implementation(libs.androidx.compose.runtime) - implementation(libs.androidx.compose.ui.util) + implementation(libs.koin.compose.viewmodel) + implementation(libs.koin.compose) - implementation(libs.androidx.lifecycle.runtimeCompose) - implementation(libs.androidx.lifecycle.viewModelCompose) - implementation(libs.androidx.navigation.compose) + implementation(libs.jb.kotlin.stdlib) + implementation(libs.kotlin.reflect) - implementation(platform(libs.koin.bom)) - implementation(libs.koin.core) - implementation(libs.koin.android) - implementation(libs.koin.androidx.navigation) - implementation(libs.koin.androidx.compose) - implementation(libs.koin.core.viewmodel) + api(libs.protobuf.kotlin.lite) + implementation(libs.kotlinx.serialization.core) + implementation(libs.multiplatform.settings) + implementation(libs.multiplatform.settings.serialization) + implementation(libs.multiplatform.settings.coroutines) - testImplementation(libs.koin.test) - testImplementation(libs.koin.test.junit4) - testImplementation(libs.koin.test.junit5) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.serialization.core) + } + desktopMain.dependencies { + implementation(libs.kotlinx.coroutines.swing) + } + } } + +// Setup protobuf configuration, generating lite Java and Kotlin classes +protobuf { + protoc { + artifact = libs.protobuf.protoc.get().toString() + } + generateProtoTasks { + all().forEach { task -> + task.builtins { + register("kotlin") { + option("lite") + } + } + } + } +} \ No newline at end of file diff --git a/libs/mifos-passcode/src/main/AndroidManifest.xml b/libs/mifos-passcode/src/androidMain/AndroidManifest.xml similarity index 100% rename from libs/mifos-passcode/src/main/AndroidManifest.xml rename to libs/mifos-passcode/src/androidMain/AndroidManifest.xml diff --git a/libs/mifos-passcode/src/main/res/drawable/lib_mifos_passcode_mifos_logo.jpg b/libs/mifos-passcode/src/commonMain/composeResources/drawable/lib_mifos_passcode_mifos_logo.jpg similarity index 100% rename from libs/mifos-passcode/src/main/res/drawable/lib_mifos_passcode_mifos_logo.jpg rename to libs/mifos-passcode/src/commonMain/composeResources/drawable/lib_mifos_passcode_mifos_logo.jpg diff --git a/libs/mifos-passcode/src/main/res/font/lib_mifos_passcode_lato_black.ttf b/libs/mifos-passcode/src/commonMain/composeResources/font/lib_mifos_passcode_lato_black.ttf similarity index 100% rename from libs/mifos-passcode/src/main/res/font/lib_mifos_passcode_lato_black.ttf rename to libs/mifos-passcode/src/commonMain/composeResources/font/lib_mifos_passcode_lato_black.ttf diff --git a/libs/mifos-passcode/src/main/res/font/lib_mifos_passcode_lato_bold.ttf b/libs/mifos-passcode/src/commonMain/composeResources/font/lib_mifos_passcode_lato_bold.ttf similarity index 100% rename from libs/mifos-passcode/src/main/res/font/lib_mifos_passcode_lato_bold.ttf rename to libs/mifos-passcode/src/commonMain/composeResources/font/lib_mifos_passcode_lato_bold.ttf diff --git a/libs/mifos-passcode/src/main/res/font/lib_mifos_passcode_lato_regular.ttf b/libs/mifos-passcode/src/commonMain/composeResources/font/lib_mifos_passcode_lato_regular.ttf similarity index 100% rename from libs/mifos-passcode/src/main/res/font/lib_mifos_passcode_lato_regular.ttf rename to libs/mifos-passcode/src/commonMain/composeResources/font/lib_mifos_passcode_lato_regular.ttf diff --git a/libs/mifos-passcode/src/main/res/values/strings.xml b/libs/mifos-passcode/src/commonMain/composeResources/values/strings.xml similarity index 100% rename from libs/mifos-passcode/src/main/res/values/strings.xml rename to libs/mifos-passcode/src/commonMain/composeResources/values/strings.xml diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/PassCodeScreen.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/PassCodeScreen.kt similarity index 76% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/PassCodeScreen.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/PassCodeScreen.kt index e7225a959..ba9cf7bc1 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/PassCodeScreen.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/PassCodeScreen.kt @@ -32,20 +32,20 @@ import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold 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.remember +import androidx.compose.runtime.rememberCoroutineScope 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.tooling.preview.Preview import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle -import org.koin.androidx.compose.koinViewModel +import kotlinx.coroutines.launch +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.koin.compose.viewmodel.koinViewModel import org.mifos.library.passcode.component.MifosIcon import org.mifos.library.passcode.component.PasscodeForgotButton import org.mifos.library.passcode.component.PasscodeHeader @@ -55,10 +55,11 @@ import org.mifos.library.passcode.component.PasscodeSkipButton import org.mifos.library.passcode.component.PasscodeToolbar import org.mifos.library.passcode.theme.blueTint import org.mifos.library.passcode.utility.Constants.PASSCODE_LENGTH -import org.mifos.library.passcode.utility.PreferenceManager import org.mifos.library.passcode.utility.ShakeAnimation.performShakeAnimation -import org.mifos.library.passcode.utility.VibrationFeedback.vibrateFeedback +import org.mifos.library.passcode.viewmodels.PasscodeAction +import org.mifos.library.passcode.viewmodels.PasscodeEvent import org.mifos.library.passcode.viewmodels.PasscodeViewModel +import org.mifospay.core.ui.utils.EventsEffect @Composable internal fun PasscodeScreen( @@ -69,29 +70,25 @@ internal fun PasscodeScreen( modifier: Modifier = Modifier, viewModel: PasscodeViewModel = koinViewModel(), ) { - val context = LocalContext.current - val preferenceManager = remember { PreferenceManager(context) } - - val activeStep by viewModel.activeStep.collectAsStateWithLifecycle() - val filledDots by viewModel.filledDots.collectAsStateWithLifecycle() - val passcodeVisible by viewModel.passcodeVisible.collectAsStateWithLifecycle() - val currentPasscode by viewModel.currentPasscodeInput.collectAsStateWithLifecycle() + val scope = rememberCoroutineScope() + val state by viewModel.stateFlow.collectAsStateWithLifecycle() val xShake = remember { Animatable(initialValue = 0.0F) } var passcodeRejectedDialogVisible by remember { mutableStateOf(false) } - LaunchedEffect(key1 = viewModel.onPasscodeConfirmed) { - viewModel.onPasscodeConfirmed.collect { - onPasscodeConfirm(it) - } - } + EventsEffect(viewModel) { event -> + when (event) { + is PasscodeEvent.PasscodeConfirmed -> { + onPasscodeConfirm(event.passcode) + } - LaunchedEffect(key1 = viewModel.onPasscodeRejected) { - viewModel.onPasscodeRejected.collect { - passcodeRejectedDialogVisible = true - vibrateFeedback(context) - performShakeAnimation(xShake) - onPasscodeRejected() + is PasscodeEvent.PasscodeRejected -> { + passcodeRejectedDialogVisible = true + scope.launch { + performShakeAnimation(xShake) + } + onPasscodeRejected() + } } } @@ -106,10 +103,10 @@ internal fun PasscodeScreen( .padding(paddingValues), horizontalAlignment = Alignment.CenterHorizontally, ) { - PasscodeToolbar(activeStep = activeStep, preferenceManager.hasPasscode) + PasscodeToolbar(activeStep = state.activeStep, state.hasPasscode) PasscodeSkipButton( - hasPassCode = preferenceManager.hasPasscode, + hasPassCode = state.hasPasscode, onSkipButton = onSkipButton, ) @@ -122,15 +119,19 @@ internal fun PasscodeScreen( horizontalAlignment = Alignment.CenterHorizontally, ) { PasscodeHeader( - activeStep = activeStep, - isPasscodeAlreadySet = preferenceManager.hasPasscode, + activeStep = state.activeStep, + isPasscodeAlreadySet = state.hasPasscode, ) PasscodeView( - restart = { viewModel.restart() }, - togglePasscodeVisibility = { viewModel.togglePasscodeVisibility() }, - filledDots = filledDots, - passcodeVisible = passcodeVisible, - currentPasscode = currentPasscode, + restart = remember(viewModel) { + { viewModel.trySendAction(PasscodeAction.Restart) } + }, + togglePasscodeVisibility = remember(viewModel) { + { viewModel.trySendAction(PasscodeAction.TogglePasscodeVisibility) } + }, + filledDots = state.filledDots, + passcodeVisible = state.passcodeVisible, + currentPasscode = state.currentPasscodeInput, passcodeRejectedDialogVisible = passcodeRejectedDialogVisible, onDismissDialog = { passcodeRejectedDialogVisible = false }, xShake = xShake, @@ -140,16 +141,21 @@ internal fun PasscodeScreen( Spacer(modifier = Modifier.height(6.dp)) PasscodeKeys( - enterKey = viewModel::enterKey, - deleteKey = viewModel::deleteKey, - deleteAllKeys = viewModel::deleteAllKeys, - modifier = Modifier.padding(horizontal = 12.dp), + enterKey = remember(viewModel) { + { viewModel.trySendAction(PasscodeAction.EnterKey(it)) } + }, + deleteKey = remember(viewModel) { + { viewModel.trySendAction(PasscodeAction.DeleteKey) } + }, + deleteAllKeys = remember(viewModel) { + { viewModel.trySendAction(PasscodeAction.DeleteAllKeys) } + }, ) Spacer(modifier = Modifier.height(8.dp)) PasscodeForgotButton( - hasPassCode = preferenceManager.hasPasscode, + hasPassCode = state.hasPasscode, onForgotButton = onForgotButton, ) } @@ -230,7 +236,7 @@ private fun PasscodeView( } } -@Preview(showBackground = true) +@Preview @Composable private fun PasscodeScreenPreview() { PasscodeScreen( diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/PasscodeNavigation.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/PasscodeNavigation.kt similarity index 100% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/PasscodeNavigation.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/PasscodeNavigation.kt diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/MifosIcon.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/MifosIcon.kt similarity index 75% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/MifosIcon.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/MifosIcon.kt index 5b5e8b778..986fa2e7d 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/MifosIcon.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/MifosIcon.kt @@ -15,9 +15,10 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.painterResource import androidx.compose.ui.unit.dp -import com.mifos.library.passcode.R +import mobile_wallet.libs.mifos_passcode.generated.resources.Res +import mobile_wallet.libs.mifos_passcode.generated.resources.lib_mifos_passcode_mifos_logo +import org.jetbrains.compose.resources.painterResource @Composable internal fun MifosIcon(modifier: Modifier = Modifier) { @@ -27,7 +28,7 @@ internal fun MifosIcon(modifier: Modifier = Modifier) { ) { Image( modifier = Modifier.size(180.dp), - painter = painterResource(id = R.drawable.lib_mifos_passcode_mifos_logo), + painter = painterResource(resource = Res.drawable.lib_mifos_passcode_mifos_logo), contentDescription = null, ) } diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeButton.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeButton.kt similarity index 77% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeButton.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeButton.kt index f1b4d31ac..bb7ecfd80 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeButton.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeButton.kt @@ -17,9 +17,11 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import com.mifos.library.passcode.R +import mobile_wallet.libs.mifos_passcode.generated.resources.Res +import mobile_wallet.libs.mifos_passcode.generated.resources.library_mifos_passcode_login_manually +import mobile_wallet.libs.mifos_passcode.generated.resources.library_mifos_passcode_skip +import org.jetbrains.compose.resources.stringResource import org.mifos.library.passcode.theme.forgotButtonStyle import org.mifos.library.passcode.theme.skipButtonStyle @@ -39,7 +41,10 @@ internal fun PasscodeSkipButton( TextButton( onClick = { onSkipButton.invoke() }, ) { - Text(text = stringResource(R.string.library_mifos_passcode_skip), style = skipButtonStyle) + Text( + text = stringResource(Res.string.library_mifos_passcode_skip), + style = skipButtonStyle, + ) } } } @@ -62,7 +67,7 @@ internal fun PasscodeForgotButton( onClick = { onForgotButton.invoke() }, ) { Text( - text = stringResource(R.string.library_mifos_passcode_login_manually), + text = stringResource(Res.string.library_mifos_passcode_login_manually), style = forgotButtonStyle, ) } diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeHeader.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeHeader.kt similarity index 84% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeHeader.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeHeader.kt index 1a08a37a9..81eaa1980 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeHeader.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeHeader.kt @@ -26,12 +26,15 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha import androidx.compose.ui.draw.scale import androidx.compose.ui.geometry.Offset -import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.mifos.library.passcode.R +import mobile_wallet.libs.mifos_passcode.generated.resources.Res +import mobile_wallet.libs.mifos_passcode.generated.resources.library_mifos_passcode_confirm_passcode +import mobile_wallet.libs.mifos_passcode.generated.resources.library_mifos_passcode_create_passcode +import mobile_wallet.libs.mifos_passcode.generated.resources.library_mifos_passcode_enter_your_passcode +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.Preview import org.mifos.library.passcode.utility.Step @Composable @@ -86,7 +89,7 @@ internal fun PasscodeHeader( .offset(x = xTransitionHeader1.x.dp) .alpha(alpha = alphaHeader1) .scale(scale = scaleHeader1), - text = stringResource(id = R.string.library_mifos_passcode_enter_your_passcode), + text = stringResource(Res.string.library_mifos_passcode_enter_your_passcode), style = TextStyle(fontSize = 20.sp), ) } else { @@ -96,7 +99,7 @@ internal fun PasscodeHeader( .offset(x = xTransitionHeader1.x.dp) .alpha(alpha = alphaHeader1) .scale(scale = scaleHeader1), - text = stringResource(id = R.string.library_mifos_passcode_create_passcode), + text = stringResource(Res.string.library_mifos_passcode_create_passcode), style = TextStyle(fontSize = 20.sp), ) } else if (activeStep == Step.Confirm) { @@ -105,7 +108,7 @@ internal fun PasscodeHeader( .offset(x = xTransitionHeader2.x.dp) .alpha(alpha = alphaHeader2) .scale(scale = scaleHeader2), - text = stringResource(id = R.string.library_mifos_passcode_confirm_passcode), + text = stringResource(Res.string.library_mifos_passcode_confirm_passcode), style = TextStyle(fontSize = 20.sp), ) } diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeKeys.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeKeys.kt similarity index 96% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeKeys.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeKeys.kt index abaf8c3e3..521b95845 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeKeys.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeKeys.kt @@ -19,6 +19,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Backspace +import androidx.compose.material.icons.filled.Delete import androidx.compose.material3.Icon import androidx.compose.material3.LocalContentColor import androidx.compose.material3.Text @@ -27,12 +28,10 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.res.vectorResource import androidx.compose.ui.semantics.Role -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import com.mifos.library.passcode.R +import org.jetbrains.compose.ui.tooling.preview.Preview import org.mifos.library.passcode.theme.PasscodeKeyButtonStyle import org.mifos.library.passcode.theme.blueTint @@ -111,7 +110,7 @@ internal fun PasscodeKeys( ) PasscodeKey( modifier = Modifier.weight(weight = 1.0F), - keyIcon = ImageVector.vectorResource(id = R.drawable.lib_mifos_passcode_ic_delete), + keyIcon = Icons.Default.Delete, keyIconContentDescription = "Delete Passcode Key Button", onClick = { deleteKey() diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeMismatchedDialog.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeMismatchedDialog.kt similarity index 71% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeMismatchedDialog.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeMismatchedDialog.kt index 228221117..6cfe56bbf 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeMismatchedDialog.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeMismatchedDialog.kt @@ -15,8 +15,10 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource -import com.mifos.library.passcode.R +import mobile_wallet.libs.mifos_passcode.generated.resources.Res +import mobile_wallet.libs.mifos_passcode.generated.resources.library_mifos_passcode_do_not_match +import mobile_wallet.libs.mifos_passcode.generated.resources.library_mifos_passcode_try_again +import org.jetbrains.compose.resources.stringResource @Composable internal fun PasscodeMismatchedDialog( @@ -29,14 +31,14 @@ internal fun PasscodeMismatchedDialog( containerColor = Color.White, title = { Text( - text = stringResource(R.string.library_mifos_passcode_do_not_match), + text = stringResource(Res.string.library_mifos_passcode_do_not_match), color = Color.Black, ) }, confirmButton = { TextButton(onClick = onDismiss) { Text( - text = stringResource(R.string.library_mifos_passcode_try_again), + text = stringResource(Res.string.library_mifos_passcode_try_again), color = Color.Black, ) } diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeStepIndicator.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeStepIndicator.kt similarity index 100% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeStepIndicator.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeStepIndicator.kt diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeToolbar.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeToolbar.kt similarity index 79% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeToolbar.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeToolbar.kt index fc5bda091..eebeb1b2d 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/component/PasscodeToolbar.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/component/PasscodeToolbar.kt @@ -25,9 +25,12 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import com.mifos.library.passcode.R +import mobile_wallet.libs.mifos_passcode.generated.resources.Res +import mobile_wallet.libs.mifos_passcode.generated.resources.lib_mifos_passcode_cancel +import mobile_wallet.libs.mifos_passcode.generated.resources.library_mifos_passcode_exit +import mobile_wallet.libs.mifos_passcode.generated.resources.library_mifos_passcode_exit_message +import org.jetbrains.compose.resources.stringResource import org.mifos.library.passcode.utility.Step @Composable @@ -74,18 +77,18 @@ private fun ExitWarningDialog( containerColor = Color.White, title = { Text( - text = stringResource(R.string.library_mifos_passcode_exit_message), + text = stringResource(Res.string.library_mifos_passcode_exit_message), color = Color.Black, ) }, confirmButton = { TextButton(onClick = onConfirm) { - Text(text = stringResource(R.string.library_mifos_passcode_exit)) + Text(text = stringResource(Res.string.library_mifos_passcode_exit)) } }, dismissButton = { TextButton(onClick = onDismiss) { - Text(text = stringResource(R.string.lib_mifos_passcode_cancel)) + Text(text = stringResource(Res.string.lib_mifos_passcode_cancel)) } }, onDismissRequest = onDismiss, diff --git a/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/di/PasscodeModule.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/di/PasscodeModule.kt new file mode 100644 index 000000000..92ca27c9a --- /dev/null +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/di/PasscodeModule.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifos.library.passcode.di + +import org.koin.core.module.dsl.viewModelOf +import org.koin.dsl.module +import org.mifos.library.passcode.viewmodels.PasscodeViewModel +import proto.org.mifos.library.passcode.di.PasscodePreferenceModule + +val PasscodeModule = module { + includes(PasscodePreferenceModule) + + viewModelOf(::PasscodeViewModel) +} diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Color.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Color.kt similarity index 100% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Color.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Color.kt diff --git a/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Font.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Font.kt new file mode 100644 index 000000000..bc97b8ffc --- /dev/null +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Font.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifos.library.passcode.theme + +import androidx.compose.material3.Typography +import androidx.compose.runtime.Composable +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp +import mobile_wallet.libs.mifos_passcode.generated.resources.Res +import mobile_wallet.libs.mifos_passcode.generated.resources.lib_mifos_passcode_lato_black +import mobile_wallet.libs.mifos_passcode.generated.resources.lib_mifos_passcode_lato_bold +import mobile_wallet.libs.mifos_passcode.generated.resources.lib_mifos_passcode_lato_regular +import org.jetbrains.compose.resources.Font + +@Composable +fun getFontFamily() = FontFamily( + Font(Res.font.lib_mifos_passcode_lato_regular, FontWeight.Normal, FontStyle.Normal), + Font(Res.font.lib_mifos_passcode_lato_bold, FontWeight.Bold, FontStyle.Normal), + Font(Res.font.lib_mifos_passcode_lato_black, FontWeight.Black, FontStyle.Normal), +) + +@Composable +fun getTypography(): Typography { + val fontFamily = FontFamily( + Font(Res.font.lib_mifos_passcode_lato_regular, FontWeight.Normal, FontStyle.Normal), + Font(Res.font.lib_mifos_passcode_lato_bold, FontWeight.Bold, FontStyle.Normal), + Font(Res.font.lib_mifos_passcode_lato_black, FontWeight.Black, FontStyle.Normal), + ) + + return Typography( + displayLarge = TextStyle( + fontFamily = getFontFamily(), + fontWeight = FontWeight.Black, + fontSize = 34.sp, + ), + ) +} diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Theme.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Theme.kt similarity index 97% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Theme.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Theme.kt index 121bfcbd3..39b181fa1 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Theme.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Theme.kt @@ -43,7 +43,7 @@ internal fun MifosPasscodeTheme( MaterialTheme( colorScheme = colors, - typography = Typography, + typography = getTypography(), content = content, ) } diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Type.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Type.kt similarity index 71% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Type.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Type.kt index b1bdb5ecb..1325f6019 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Type.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/theme/Type.kt @@ -9,21 +9,11 @@ */ package org.mifos.library.passcode.theme -import androidx.compose.material3.Typography import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp -internal val Typography = Typography( - displayLarge = TextStyle( - fontFamily = LatoFonts, - fontWeight = FontWeight.Black, - fontSize = 34.sp, - ), -) - internal val PasscodeKeyButtonStyle = TextStyle( - fontFamily = LatoFonts, fontWeight = FontWeight.Bold, fontSize = 24.sp, ) @@ -31,11 +21,9 @@ internal val PasscodeKeyButtonStyle = TextStyle( internal val skipButtonStyle = TextStyle( color = blueTint, fontSize = 20.sp, - fontFamily = LatoFonts, ) internal val forgotButtonStyle = TextStyle( color = blueTint, fontSize = 14.sp, - fontFamily = LatoFonts, ) diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/Constants.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/utility/Constants.kt similarity index 100% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/Constants.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/utility/Constants.kt diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/ShakeAnimation.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/utility/ShakeAnimation.kt similarity index 100% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/ShakeAnimation.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/utility/ShakeAnimation.kt diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/Step.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/utility/Step.kt similarity index 90% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/Step.kt rename to libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/utility/Step.kt index e5782451a..6c664574b 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/Step.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/utility/Step.kt @@ -9,7 +9,7 @@ */ package org.mifos.library.passcode.utility -internal enum class Step(var index: Int) { +enum class Step(var index: Int) { Create(0), Confirm(1), } diff --git a/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt new file mode 100644 index 000000000..b6c5cddea --- /dev/null +++ b/libs/mifos-passcode/src/commonMain/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt @@ -0,0 +1,199 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifos.library.passcode.viewmodels + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.mifos.library.passcode.utility.Step +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize +import org.mifospay.core.ui.utils.BaseViewModel +import proto.org.mifos.library.passcode.data.PasscodeManager + +private const val KEY_STATE = "passcode_state" +private const val PASSCODE_LENGTH = 4 + +class PasscodeViewModel( + private val passcodeRepository: PasscodeManager, + savedStateHandle: SavedStateHandle, +) : BaseViewModel( + initialState = savedStateHandle[KEY_STATE] ?: PasscodeState(), +) { + private var createPasscode: StringBuilder = StringBuilder() + private var confirmPasscode: StringBuilder = StringBuilder() + + init { + observePasscodeRepository() + } + + private fun observePasscodeRepository() { + viewModelScope.launch { + passcodeRepository.hasPasscode.collect { hasPasscode -> + mutableStateFlow.update { + it.copy( + hasPasscode = hasPasscode, + isPasscodeAlreadySet = hasPasscode, + ) + } + } + } + } + + override fun handleAction(action: PasscodeAction) { + when (action) { + is PasscodeAction.EnterKey -> enterKey(action.key) + is PasscodeAction.DeleteKey -> deleteKey() + is PasscodeAction.DeleteAllKeys -> deleteAllKeys() + is PasscodeAction.TogglePasscodeVisibility -> togglePasscodeVisibility() + is PasscodeAction.Restart -> restart() + is PasscodeAction.Internal.ProcessCompletedPasscode -> processCompletedPasscode() + } + } + + private fun enterKey(key: String) { + if (state.filledDots >= PASSCODE_LENGTH) return + + val currentPasscode = + if (state.activeStep == Step.Create) createPasscode else confirmPasscode + currentPasscode.append(key) + + mutableStateFlow.update { + it.copy( + currentPasscodeInput = currentPasscode.toString(), + filledDots = currentPasscode.length, + ) + } + + if (state.filledDots == PASSCODE_LENGTH) { + viewModelScope.launch { + sendAction(PasscodeAction.Internal.ProcessCompletedPasscode) + } + } + } + + private fun deleteKey() { + val currentPasscode = + if (state.activeStep == Step.Create) createPasscode else confirmPasscode + if (currentPasscode.isNotEmpty()) { + currentPasscode.deleteAt(currentPasscode.length - 1) + mutableStateFlow.update { + it.copy( + currentPasscodeInput = currentPasscode.toString(), + filledDots = currentPasscode.length, + ) + } + } + } + + private fun deleteAllKeys() { + if (state.activeStep == Step.Create) { + createPasscode.clear() + } else { + confirmPasscode.clear() + } + mutableStateFlow.update { + it.copy( + currentPasscodeInput = "", + filledDots = 0, + ) + } + } + + private fun togglePasscodeVisibility() { + mutableStateFlow.update { it.copy(passcodeVisible = !it.passcodeVisible) } + } + + private fun restart() { + resetState() + } + + private fun processCompletedPasscode() { + viewModelScope.launch { + when { + state.isPasscodeAlreadySet -> validateExistingPasscode() + state.activeStep == Step.Create -> moveToConfirmStep() + else -> validateNewPasscode() + } + } + } + + private suspend fun validateExistingPasscode() { + val savedPasscode = passcodeRepository.getPasscode.first() + if (savedPasscode == createPasscode.toString()) { + sendEvent(PasscodeEvent.PasscodeConfirmed(createPasscode.toString())) + createPasscode.clear() + } else { + sendEvent(PasscodeEvent.PasscodeRejected) + } + mutableStateFlow.update { it.copy(currentPasscodeInput = "") } + } + + private fun moveToConfirmStep() { + mutableStateFlow.update { + it.copy( + activeStep = Step.Confirm, + filledDots = 0, + currentPasscodeInput = "", + ) + } + } + + private suspend fun validateNewPasscode() { + if (createPasscode.toString() == confirmPasscode.toString()) { + passcodeRepository.savePasscode(confirmPasscode.toString()) + sendEvent(PasscodeEvent.PasscodeConfirmed(confirmPasscode.toString())) + resetState() + } else { + sendEvent(PasscodeEvent.PasscodeRejected) + resetState() + } + } + + private fun resetState() { + mutableStateFlow.update { + PasscodeState( + hasPasscode = it.hasPasscode, + isPasscodeAlreadySet = it.isPasscodeAlreadySet, + ) + } + createPasscode.clear() + confirmPasscode.clear() + } +} + +@Parcelize +data class PasscodeState( + val hasPasscode: Boolean = false, + val activeStep: Step = Step.Create, + val filledDots: Int = 0, + val passcodeVisible: Boolean = false, + val currentPasscodeInput: String = "", + val isPasscodeAlreadySet: Boolean = false, +) : Parcelable + +sealed class PasscodeEvent { + data class PasscodeConfirmed(val passcode: String) : PasscodeEvent() + data object PasscodeRejected : PasscodeEvent() +} + +sealed class PasscodeAction { + data class EnterKey(val key: String) : PasscodeAction() + data object DeleteKey : PasscodeAction() + data object DeleteAllKeys : PasscodeAction() + data object TogglePasscodeVisibility : PasscodeAction() + data object Restart : PasscodeAction() + + sealed class Internal : PasscodeAction() { + data object ProcessCompletedPasscode : Internal() + } +} diff --git a/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/data/PasscodeManager.kt b/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/data/PasscodeManager.kt new file mode 100644 index 000000000..2d6a3dca5 --- /dev/null +++ b/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/data/PasscodeManager.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package proto.org.mifos.library.passcode.data + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.stateIn +import proto.org.mifos.library.passcode.model.PasscodePreferencesProto + +class PasscodeManager( + private val source: PasscodePreferencesDataSource, + dispatcher: CoroutineDispatcher, +) { + private val coroutineScope = CoroutineScope(dispatcher) + + val getPasscode = source.passcode.stateIn( + scope = coroutineScope, + started = SharingStarted.Eagerly, + initialValue = "", + ) + + val hasPasscode = source.hasPasscode.stateIn( + scope = coroutineScope, + started = SharingStarted.Eagerly, + initialValue = false, + ) + + suspend fun savePasscode(passcode: String) { + source.updatePasscodeSettings( + PasscodePreferencesProto( + passcode = passcode, + hasPasscode = passcode.isNotEmpty(), + ), + ) + } + + suspend fun clearPasscode() { + source.clearInfo() + } +} diff --git a/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/data/PasscodePreferencesDataSource.kt b/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/data/PasscodePreferencesDataSource.kt new file mode 100644 index 000000000..9bf273fe0 --- /dev/null +++ b/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/data/PasscodePreferencesDataSource.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +@file:OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) + +package proto.org.mifos.library.passcode.data + +import com.russhwolf.settings.ExperimentalSettingsApi +import com.russhwolf.settings.Settings +import com.russhwolf.settings.serialization.decodeValue +import com.russhwolf.settings.serialization.decodeValueOrNull +import com.russhwolf.settings.serialization.encodeValue +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext +import kotlinx.serialization.ExperimentalSerializationApi +import proto.org.mifos.library.passcode.model.PasscodePreferencesProto + +private const val PASSCODE_INFO_KEY = "passcodeInfo" + +class PasscodePreferencesDataSource( + private val settings: Settings, + private val dispatcher: CoroutineDispatcher, +) { + private val passcodeSettings = MutableStateFlow( + settings.decodeValue( + key = PASSCODE_INFO_KEY, + serializer = PasscodePreferencesProto.serializer(), + defaultValue = settings.decodeValueOrNull( + key = PASSCODE_INFO_KEY, + serializer = PasscodePreferencesProto.serializer(), + ) ?: PasscodePreferencesProto.DEFAULT, + ), + ) + + val passcode = passcodeSettings.map { it.passcode } + val hasPasscode = passcodeSettings.map { it.hasPasscode } + + suspend fun updatePasscodeSettings(passcodePreferences: PasscodePreferencesProto) { + withContext(dispatcher) { + settings.putPasscodePreference(passcodePreferences) + passcodeSettings.value = passcodePreferences + } + } + + suspend fun clearInfo() { + withContext(dispatcher) { + settings.remove(PASSCODE_INFO_KEY) + } + } +} + +private fun Settings.putPasscodePreference(preference: PasscodePreferencesProto) { + encodeValue( + key = PASSCODE_INFO_KEY, + serializer = PasscodePreferencesProto.serializer(), + value = preference, + ) +} diff --git a/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/di/PreferenceModule.kt b/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/di/PreferenceModule.kt new file mode 100644 index 000000000..575121f6b --- /dev/null +++ b/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/di/PreferenceModule.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package proto.org.mifos.library.passcode.di + +import com.russhwolf.settings.Settings +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifospay.core.common.MifosDispatchers +import proto.org.mifos.library.passcode.data.PasscodeManager +import proto.org.mifos.library.passcode.data.PasscodePreferencesDataSource + +val PasscodePreferenceModule = module { + factory { Settings() } + factory { PasscodePreferencesDataSource(get(), get(named(MifosDispatchers.IO.name))) } + factory { PasscodeManager(get(), get(named(MifosDispatchers.Unconfined.name))) } +} diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepository.kt b/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/model/PasscodePreferencesProto.kt similarity index 51% rename from libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepository.kt rename to libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/model/PasscodePreferencesProto.kt index 4311e6ade..0f7b38b79 100644 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepository.kt +++ b/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/model/PasscodePreferencesProto.kt @@ -7,12 +7,16 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifos.library.passcode.data +package proto.org.mifos.library.passcode.model -interface PasscodeRepository { - val hasPasscode: Boolean +import kotlinx.serialization.Serializable - fun getSavedPasscode(): String - - fun savePasscode(passcode: String) +@Serializable +data class PasscodePreferencesProto( + val passcode: String, + val hasPasscode: Boolean, +) { + companion object { + val DEFAULT = PasscodePreferencesProto(passcode = "", hasPasscode = false) + } } diff --git a/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/passcode_preferences.proto b/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/passcode_preferences.proto new file mode 100644 index 000000000..7ff555c9b --- /dev/null +++ b/libs/mifos-passcode/src/commonMain/kotlin/proto/org/mifos/library/passcode/passcode_preferences.proto @@ -0,0 +1,8 @@ +syntax = "proto3"; + +option java_package = "org.mifos.library.passcode.proto"; +option java_multiple_files = true; + +message PasscodePreferences { + string passcode = 1; +} \ No newline at end of file diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeManager.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeManager.kt deleted file mode 100644 index 15899edd1..000000000 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeManager.kt +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifos.library.passcode.data - -import org.mifos.library.passcode.utility.PreferenceManager - -class PasscodeManager( - private val passcodePreferencesHelper: PreferenceManager, -) { - - val getPasscode = passcodePreferencesHelper.getSavedPasscode() - - val hasPasscode = passcodePreferencesHelper.hasPasscode - - fun savePasscode(passcode: String) { - passcodePreferencesHelper.savePasscode(passcode) - } - - fun clearPasscode() { - passcodePreferencesHelper.clearPasscode() - } -} diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepositoryImpl.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepositoryImpl.kt deleted file mode 100644 index 3346a2670..000000000 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/data/PasscodeRepositoryImpl.kt +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifos.library.passcode.data - -import org.mifos.library.passcode.utility.PreferenceManager - -class PasscodeRepositoryImpl( - private val preferenceManager: PreferenceManager, -) : PasscodeRepository { - - override val hasPasscode: Boolean - get() = preferenceManager.hasPasscode - - override fun getSavedPasscode(): String { - return preferenceManager.getSavedPasscode() - } - - override fun savePasscode(passcode: String) { - preferenceManager.savePasscode(passcode) - } -} diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/di/ApplicationModule.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/di/ApplicationModule.kt deleted file mode 100644 index ad1c93c66..000000000 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/di/ApplicationModule.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifos.library.passcode.di - -import org.koin.android.ext.koin.androidContext -import org.koin.core.module.dsl.viewModel -import org.koin.dsl.module -import org.mifos.library.passcode.data.PasscodeManager -import org.mifos.library.passcode.data.PasscodeRepository -import org.mifos.library.passcode.data.PasscodeRepositoryImpl -import org.mifos.library.passcode.utility.PreferenceManager -import org.mifos.library.passcode.viewmodels.PasscodeViewModel - -val ApplicationModule = module { - - factory { - PreferenceManager(context = androidContext()) - } - - single { PasscodeRepositoryImpl(preferenceManager = get()) } - - viewModel { - PasscodeViewModel(passcodeRepository = get()) - } - factory { - PasscodeManager(passcodePreferencesHelper = get()) - } -} diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Font.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Font.kt deleted file mode 100644 index e948eca0a..000000000 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/theme/Font.kt +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifos.library.passcode.theme - -import androidx.compose.ui.text.font.Font -import androidx.compose.ui.text.font.FontFamily -import androidx.compose.ui.text.font.FontStyle -import androidx.compose.ui.text.font.FontWeight -import com.mifos.library.passcode.R - -internal val LatoFonts = FontFamily( - Font( - resId = R.font.lib_mifos_passcode_lato_regular, - weight = FontWeight.Normal, - style = FontStyle.Normal, - ), - Font( - resId = R.font.lib_mifos_passcode_lato_bold, - weight = FontWeight.Bold, - style = FontStyle.Normal, - ), - Font( - resId = R.font.lib_mifos_passcode_lato_black, - weight = FontWeight.Black, - style = FontStyle.Normal, - ), -) diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/PreferenceManager.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/PreferenceManager.kt deleted file mode 100644 index 89d729d92..000000000 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/PreferenceManager.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifos.library.passcode.utility - -import android.content.Context -import com.mifos.library.passcode.R - -class PreferenceManager(context: Context) { - private val sharedPreference = context.getSharedPreferences( - R.string.lib_mifos_passcode_pref_name.toString(), - Context.MODE_PRIVATE, - ) - - var hasPasscode: Boolean - get() = sharedPreference.getBoolean(R.string.lib_mifos_passcode_has_passcode.toString(), false) - set(value) = sharedPreference.edit().putBoolean(R.string.lib_mifos_passcode_has_passcode.toString(), value) - .apply() - - fun savePasscode(passcode: String) { - sharedPreference.edit().putString(R.string.lib_mifos_passcode.toString(), passcode).apply() - hasPasscode = true - } - - fun getSavedPasscode(): String { - return sharedPreference.getString(R.string.lib_mifos_passcode.toString(), "").toString() - } - - fun clearPasscode() { - sharedPreference.edit().clear().apply() - hasPasscode = false - } -} diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/VibrationFeedback.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/VibrationFeedback.kt deleted file mode 100644 index 62ca18df1..000000000 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/utility/VibrationFeedback.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifos.library.passcode.utility - -import android.content.Context -import android.os.Build -import android.os.CombinedVibration -import android.os.VibrationEffect -import android.os.Vibrator -import android.os.VibratorManager -import org.mifos.library.passcode.utility.Constants.VIBRATE_FEEDBACK_DURATION - -internal object VibrationFeedback { - - @Suppress("DEPRECATION") - internal fun vibrateFeedback(context: Context) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - (context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager).vibrate( - CombinedVibration.createParallel( - VibrationEffect.createOneShot( - VIBRATE_FEEDBACK_DURATION, - VibrationEffect.DEFAULT_AMPLITUDE, - ), - ), - ) - } else { - (context.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator).let { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - it.vibrate( - VibrationEffect.createOneShot( - VIBRATE_FEEDBACK_DURATION, - VibrationEffect.DEFAULT_AMPLITUDE, - ), - ) - } else { - it.vibrate(VIBRATE_FEEDBACK_DURATION) - } - } - } - } -} diff --git a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt b/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt deleted file mode 100644 index c0d2631a6..000000000 --- a/libs/mifos-passcode/src/main/kotlin/org/mifos/library/passcode/viewmodels/PasscodeViewModel.kt +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifos.library.passcode.viewmodels - -import androidx.compose.runtime.mutableStateOf -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.flow.MutableSharedFlow -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.asSharedFlow -import kotlinx.coroutines.flow.asStateFlow -import kotlinx.coroutines.launch -import org.mifos.library.passcode.data.PasscodeRepository -import org.mifos.library.passcode.utility.Constants.PASSCODE_LENGTH -import org.mifos.library.passcode.utility.Step - -internal class PasscodeViewModel( - private val passcodeRepository: PasscodeRepository, -) : ViewModel() { - - private val mOnPasscodeConfirmed = MutableSharedFlow() - val onPasscodeConfirmed = mOnPasscodeConfirmed.asSharedFlow() - - private val mOnPasscodeRejected = MutableSharedFlow() - val onPasscodeRejected = mOnPasscodeRejected.asSharedFlow() - - private val mActiveStep = MutableStateFlow(Step.Create) - val activeStep = mActiveStep.asStateFlow() - - private val mFilledDots = MutableStateFlow(0) - val filledDots = mFilledDots.asStateFlow() - - private var createPasscode: StringBuilder = StringBuilder() - private var confirmPasscode: StringBuilder = StringBuilder() - - private val mPasscodeVisible = MutableStateFlow(false) - val passcodeVisible = mPasscodeVisible.asStateFlow() - - private val mCurrentPasscodeInput = MutableStateFlow("") - val currentPasscodeInput = mCurrentPasscodeInput.asStateFlow() - - private var mIsPasscodeAlreadySet = mutableStateOf(passcodeRepository.hasPasscode) - - init { - resetData() - } - - private fun emitActiveStep(activeStep: Step) = viewModelScope.launch { - mActiveStep.emit(activeStep) - } - - private fun emitFilledDots(filledDots: Int) = viewModelScope.launch { - mFilledDots.emit(filledDots) - } - - private fun emitOnPasscodeConfirmed(confirmPassword: String) = viewModelScope.launch { - mOnPasscodeConfirmed.emit(confirmPassword) - } - - private fun emitOnPasscodeRejected() = viewModelScope.launch { - mOnPasscodeRejected.emit(Unit) - } - - fun togglePasscodeVisibility() { - mPasscodeVisible.value = !mPasscodeVisible.value - } - - private fun resetData() { - emitActiveStep(Step.Create) - emitFilledDots(0) - - createPasscode.clear() - confirmPasscode.clear() - } - - fun enterKey(key: String) { - if (mFilledDots.value >= PASSCODE_LENGTH) { - return - } - - val currentPasscode = - if (mActiveStep.value == Step.Create) createPasscode else confirmPasscode - currentPasscode.append(key) - mCurrentPasscodeInput.value = currentPasscode.toString() - emitFilledDots(currentPasscode.length) - - if (mFilledDots.value == PASSCODE_LENGTH) { - if (mIsPasscodeAlreadySet.value) { - if (passcodeRepository.getSavedPasscode() == createPasscode.toString()) { - emitOnPasscodeConfirmed(createPasscode.toString()) - createPasscode.clear() - } else { - emitOnPasscodeRejected() - // logic for retires can be written here - } - mCurrentPasscodeInput.value = "" - } else if (mActiveStep.value == Step.Create) { - emitActiveStep(Step.Confirm) - emitFilledDots(0) - mCurrentPasscodeInput.value = "" - } else { - if (createPasscode.toString() == confirmPasscode.toString()) { - emitOnPasscodeConfirmed(confirmPasscode.toString()) - passcodeRepository.savePasscode(confirmPasscode.toString()) - mIsPasscodeAlreadySet.value = true - resetData() - } else { - emitOnPasscodeRejected() - resetData() - } - mCurrentPasscodeInput.value = "" - } - } - } - - fun deleteKey() { - val currentPasscode = - if (mActiveStep.value == Step.Create) createPasscode else confirmPasscode - - if (currentPasscode.isNotEmpty()) { - currentPasscode.deleteAt(currentPasscode.length - 1) - mCurrentPasscodeInput.value = currentPasscode.toString() - emitFilledDots(currentPasscode.length) - } - } - - fun deleteAllKeys() { - if (mActiveStep.value == Step.Create) { - createPasscode.clear() - } else { - confirmPasscode.clear() - } - mCurrentPasscodeInput.value = "" - emitFilledDots(0) - } - - fun restart() { - resetData() - mPasscodeVisible.value = false - } -} diff --git a/libs/mifos-passcode/src/main/res/drawable/lib_mifos_passcode_delete_forever.xml b/libs/mifos-passcode/src/main/res/drawable/lib_mifos_passcode_delete_forever.xml deleted file mode 100644 index cc0810db2..000000000 --- a/libs/mifos-passcode/src/main/res/drawable/lib_mifos_passcode_delete_forever.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - diff --git a/libs/mifos-passcode/src/main/res/drawable/lib_mifos_passcode_ic_delete.xml b/libs/mifos-passcode/src/main/res/drawable/lib_mifos_passcode_ic_delete.xml deleted file mode 100644 index a10936ea0..000000000 --- a/libs/mifos-passcode/src/main/res/drawable/lib_mifos_passcode_ic_delete.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - diff --git a/mifospay-shared/build.gradle.kts b/mifospay-shared/build.gradle.kts index 241131218..420f537c1 100644 --- a/mifospay-shared/build.gradle.kts +++ b/mifospay-shared/build.gradle.kts @@ -34,6 +34,7 @@ kotlin { api(libs.koin.compose.viewmodel) api(projects.feature.auth) + api(projects.libs.mifosPasscode) } desktopMain.dependencies { diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt index 20ae14177..d799b6664 100644 --- a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt @@ -25,7 +25,7 @@ import org.mifospay.core.designsystem.theme.MifosTheme import org.mifospay.core.ui.LocalTimeZone import org.mifospay.shared.MainUiState.Success import org.mifospay.shared.navigation.MifosNavGraph.LOGIN_GRAPH -import org.mifospay.shared.navigation.MifosNavGraph.MAIN_GRAPH +import org.mifospay.shared.navigation.MifosNavGraph.PASSCODE_GRAPH import org.mifospay.shared.navigation.RootNavGraph import org.mifospay.shared.ui.rememberMifosAppState @@ -60,7 +60,7 @@ private fun MifosPayApp( val navDestination = when (uiState) { is MainUiState.Loading -> LOGIN_GRAPH is Success -> if ((uiState as Success).userData.authenticated) { - MAIN_GRAPH + PASSCODE_GRAPH } else { LOGIN_GRAPH } diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt index 634d6eb60..b76b77d14 100644 --- a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt @@ -18,9 +18,11 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch import org.mifospay.core.datastore.UserPreferencesRepository import org.mifospay.core.model.UserInfo +import proto.org.mifos.library.passcode.data.PasscodeManager class MifosPayViewModel( private val userDataRepository: UserPreferencesRepository, + private val passcodeManager: PasscodeManager, ) : ViewModel() { val uiState: StateFlow = userDataRepository.userInfo.map { MainUiState.Success(it) @@ -33,7 +35,7 @@ class MifosPayViewModel( fun logOut() { viewModelScope.launch { userDataRepository.logOut() -// passcodeManager.clearPasscode() + passcodeManager.clearPasscode() } } } diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt index 042388040..2aed9d942 100644 --- a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt @@ -14,6 +14,7 @@ import org.koin.core.module.dsl.viewModelOf import org.koin.dsl.KoinAppDeclaration import org.koin.dsl.koinApplication import org.koin.dsl.module +import org.mifos.library.passcode.di.PasscodeModule import org.mifospay.core.common.di.DispatchersModule import org.mifospay.core.data.di.RepositoryModule import org.mifospay.core.datastore.di.PreferencesModule @@ -47,6 +48,9 @@ object KoinModules { AuthModule, ) } + private val LibraryModule = module { + includes(PasscodeModule) + } val allModules = listOf( commonModules, @@ -56,6 +60,7 @@ object KoinModules { networkModules, featureModules, sharedModule, + LibraryModule, ) } diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/LoginNavGraph.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/LoginNavGraph.kt index fdf8ac1de..89ae956a4 100644 --- a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/LoginNavGraph.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/LoginNavGraph.kt @@ -12,6 +12,7 @@ package org.mifospay.shared.navigation import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.navigation +import org.mifos.library.passcode.navigateToPasscodeScreen import org.mifospay.feature.auth.navigation.LOGIN_ROUTE import org.mifospay.feature.auth.navigation.loginScreen import org.mifospay.feature.auth.navigation.mobileVerificationScreen @@ -28,8 +29,7 @@ internal fun NavGraphBuilder.loginNavGraph(navController: NavController) { ) { loginScreen( onNavigateBack = navController::popBackStack, - // TODO:: we should navigate to passcode graph - onNavigateToPasscodeScreen = navController::navigateToMainGraph, + onNavigateToPasscodeScreen = navController::navigateToPasscodeScreen, onNavigateToSignupScreen = navController::navigateToSignupMethod, ) diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/PasscodeNavGraph.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/PasscodeNavGraph.kt new file mode 100644 index 000000000..37222ca7f --- /dev/null +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/PasscodeNavGraph.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.shared.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.navigation +import org.mifos.library.passcode.PASSCODE_SCREEN +import org.mifos.library.passcode.passcodeRoute + +internal fun NavGraphBuilder.passcodeNavGraph(navController: NavController) { + navigation( + route = MifosNavGraph.PASSCODE_GRAPH, + startDestination = PASSCODE_SCREEN, + ) { + passcodeRoute( + onForgotButton = { + navController.popBackStack() + navController.navigate(MifosNavGraph.MAIN_GRAPH) + }, + onSkipButton = { + navController.popBackStack() + navController.navigate(MifosNavGraph.MAIN_GRAPH) + }, + onPasscodeConfirm = { + navController.popBackStack() + navController.navigate(MifosNavGraph.MAIN_GRAPH) + }, + onPasscodeRejected = { + navController.popBackStack() + navController.navigate(MifosNavGraph.MAIN_GRAPH) + }, + ) + } +} diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/RootNavGraph.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/RootNavGraph.kt index be68108c2..599f353be 100644 --- a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/RootNavGraph.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/RootNavGraph.kt @@ -33,7 +33,7 @@ internal fun RootNavGraph( ) { loginNavGraph(navHostController) -// passcodeNavGraph(navHostController) + passcodeNavGraph(navHostController) composable(MifosNavGraph.MAIN_GRAPH) { MifosApp( From d295cabba81ac9dbba7a6c8b72ba8f594d6f9aa5 Mon Sep 17 00:00:00 2001 From: Sk Niyaj Ali Date: Thu, 10 Oct 2024 19:01:06 +0530 Subject: [PATCH 10/31] Feat: Migrated Home Module to KMP (#1784) --- core/common/build.gradle.kts | 1 + .../org/mifospay/core/common}/DateHelper.kt | 2 +- core/data/build.gradle.kts | 3 +- .../core/data/mapper/AccountMapper.kt | 6 +- .../core/data/mapper/ClientDetailsMapper.kt | 34 +- .../core/data/mapper/CurrencyMapper.kt | 6 +- .../data/mapper/SearchedEntitiesMapper.kt | 17 +- .../core/data/mapper/TrannsferDetailMapper.kt | 76 +++ .../core/data/mapper/TransactionMapper.kt | 13 +- .../mifospay/core/data/mapper/UserMapper.kt | 59 ++ .../core/data/repository/AccountRepository.kt | 2 +- .../repository/AuthenticationRepository.kt | 4 +- .../data/repository/BeneficiaryRepository.kt | 8 +- .../core/data/repository/ClientRepository.kt | 18 +- .../data/repository/DocumentRepository.kt | 2 +- .../core/data/repository/InvoiceRepository.kt | 2 +- .../data/repository/KycLevelRepository.kt | 2 +- .../data/repository/NotificationRepository.kt | 2 +- .../data/repository/RegistrationRepository.kt | 4 +- .../data/repository/RunReportRepository.kt | 2 +- .../data/repository/SavedCardRepository.kt | 2 +- .../repository/SavingsAccountRepository.kt | 15 +- .../core/data/repository/SearchRepository.kt | 4 +- .../data/repository/SelfServiceRepository.kt | 27 +- .../StandingInstructionRepository.kt | 8 +- .../ThirdPartyTransferRepository.kt | 6 +- .../repository/TwoFactorAuthRepository.kt | 4 +- .../core/data/repository/UserRepository.kt | 6 +- .../repositoryImp/AccountRepositoryImpl.kt | 5 +- .../AuthenticationRepositoryImpl.kt | 9 +- .../BeneficiaryRepositoryImpl.kt | 8 +- .../repositoryImp/ClientRepositoryImpl.kt | 42 +- .../repositoryImp/DocumentRepositoryImpl.kt | 2 +- .../repositoryImp/InvoiceRepositoryImpl.kt | 7 +- .../repositoryImp/KycLevelRepositoryImpl.kt | 6 +- .../NotificationRepositoryImpl.kt | 2 +- .../RegistrationRepositoryImpl.kt | 4 +- .../repositoryImp/RunReportRepositoryImpl.kt | 2 +- .../repositoryImp/SavedCardRepositoryImpl.kt | 2 +- .../SavingsAccountRepositoryImpl.kt | 29 +- .../repositoryImp/SearchRepositoryImpl.kt | 7 +- .../SelfServiceRepositoryImpl.kt | 78 ++- .../StandingInstructionRepositoryImpl.kt | 8 +- .../ThirdPartyTransferRepositoryImpl.kt | 6 +- .../TwoFactorAuthRepositoryImpl.kt | 4 +- .../data/repositoryImp/UserRepositoryImpl.kt | 15 +- .../core/datastore/PreferencesMapper.kt | 12 +- .../datastore/UserPreferencesDataSource.kt | 34 +- .../datastore/UserPreferencesRepository.kt | 14 +- .../UserPreferencesRepositoryImpl.kt | 36 +- .../core/datastore/utils/UserMapper.kt | 47 -- core/designsystem/build.gradle.kts | 5 +- .../composeResources/font/outfit_black.ttf | Bin 0 -> 55376 bytes .../composeResources/font/outfit_bold.ttf | Bin 0 -> 55396 bytes .../font/outfit_extra_bold.ttf | Bin 0 -> 55312 bytes .../font/outfit_extra_light.ttf | Bin 0 -> 54940 bytes .../composeResources/font/outfit_light.ttf | Bin 0 -> 54860 bytes .../composeResources/font/outfit_medium.ttf | Bin 0 -> 54824 bytes .../composeResources/font/outfit_regular.ttf | Bin 0 -> 54916 bytes .../font/outfit_semi_bold.ttf | Bin 0 -> 55496 bytes .../composeResources/font/outfit_thin.ttf | Bin 0 -> 54584 bytes .../core/designsystem/component/Background.kt | 36 +- .../core/designsystem/component/Button.kt | 7 +- .../core/designsystem/component/IconBox.kt | 59 ++ .../designsystem/component/LoadingWheel.kt | 5 +- .../core/designsystem/component/Navigation.kt | 12 +- .../core/designsystem/component/TextField.kt | 5 +- .../core/designsystem/component/TopAppBar.kt | 3 +- .../component/scrollbar/AppScrollbars.kt | 246 ++++++++ .../scrollbar/LazyScrollbarUtilities.kt | 81 +++ .../component/scrollbar/Scrollbar.kt | 412 ++++++++++++ .../component/scrollbar/ScrollbarExt.kt | 227 +++++++ .../component/scrollbar/ThumbExt.kt | 82 +++ .../core/designsystem/icon/MifosIcons.kt | 12 +- .../mifospay/core/designsystem/theme/Color.kt | 26 +- .../mifospay/core/designsystem/theme/Theme.kt | 13 +- .../mifospay/core/designsystem/theme/Type.kt | 69 +- .../org/mifospay/core/domain/LoginUseCase.kt | 59 +- core/model/build.gradle.kts | 2 +- .../core/model/{domain => account}/Account.kt | 10 +- .../model/{domain => account}/NewAccount.kt | 2 +- .../core/model/{domain => bank}/Bank.kt | 8 +- .../core/model/bank/BankAccountDetails.kt | 24 + .../model/client/AccountWithTransactions.kt | 21 + .../model/{ClientInfo.kt => client/Client.kt} | 10 +- .../core/model/client/ClientAccount.kt | 16 + .../core/model/client/ClientAddress.kt | 23 + .../mifospay/core/model/client/NewClient.kt | 23 + .../core/model/domain/BankAccountDetails.kt | 33 - .../mifospay/core/model/domain/Transaction.kt | 40 -- .../core/model/domain/user/NewUser.kt | 57 -- .../entity/accounts/savings/SavingAccount.kt | 54 -- .../entity/accounts/savings/TransferDetail.kt | 30 - .../{domain => savingsaccount}/Currency.kt | 15 +- .../core/model/savingsaccount/DepositType.kt | 20 + .../model/savingsaccount/SavingAccount.kt | 33 + .../core/model/savingsaccount/Status.kt | 30 + .../core/model/savingsaccount/Transaction.kt | 27 + .../TransactionType.kt | 2 +- .../model/savingsaccount/TransferDetail.kt | 23 + .../model/{domain => search}/SearchResult.kt | 24 +- .../mifospay/core/model/signup/SignupData.kt | 31 - .../org/mifospay/core/model/user/NewUser.kt | 22 + .../core/model/{ => user}/RoleInfo.kt | 8 +- .../core/model/{ => user}/UserData.kt | 6 +- .../core/model/{ => user}/UserInfo.kt | 8 +- core/network/build.gradle.kts | 12 - .../core/network/FineractApiManager.kt | 65 +- .../core/network/SelfServiceApiManager.kt | 30 +- .../mifospay/core/network/di/NetworkModule.kt | 6 +- .../localAssets/LocalAssetDataSource.kt | 6 +- .../localAssets/MifosLocalAssetDataSource.kt | 6 +- ...entResponse.kt => ClientResponseEntity.kt} | 2 +- .../network/model}/NotificationPayload.kt | 2 +- .../core/network}/model/entity/Invoice.kt | 2 +- .../core/network}/model/entity/Page.kt | 2 +- .../core/network}/model/entity/Role.kt | 2 +- .../network}/model/entity/SearchedEntity.kt | 2 +- .../core/network}/model/entity/TPTResponse.kt | 2 +- .../core/network}/model/entity/Timeline.kt | 2 +- .../core/network}/model/entity/UserEntity.kt | 2 +- .../network}/model/entity/UserWithRole.kt | 2 +- .../accounts/SavingAccountsListResponse.kt | 5 +- .../accounts/savings/CurrencyEntity.kt} | 4 +- .../accounts/savings/PaymentDetailData.kt | 4 +- .../entity/accounts/savings/PaymentType.kt | 2 +- .../accounts/savings/SavingAccountEntity.kt | 106 ++++ .../savings/SavingsWithAssociationsEntity.kt | 30 +- .../entity/accounts/savings/StatusEntity.kt} | 4 +- .../model/entity/accounts/savings/Summary.kt | 4 +- .../model/entity/accounts/savings/TimeLine.kt | 2 +- .../accounts/savings/TransactionType.kt | 2 +- .../accounts/savings/TransactionsEntity.kt | 4 +- .../model/entity/accounts/savings/Transfer.kt | 2 +- .../accounts/savings/TransferDetailEntity.kt | 30 + .../authentication/AuthenticationPayload.kt | 2 +- .../model/entity/beneficary/Beneficiary.kt | 6 +- .../entity/beneficary/BeneficiaryPayload.kt | 2 +- .../beneficary/BeneficiaryUpdatePayload.kt | 2 +- .../entity/client/ClientAccountsEntity.kt} | 20 +- .../model/entity/client/ClientEntity.kt | 5 +- .../network}/model/entity/client/Currency.kt | 2 +- .../model/entity/client/DepositTypeEntity.kt} | 14 +- .../model/entity/client/NewClientEntity.kt} | 6 +- .../network}/model/entity/client/Status.kt | 2 +- .../core/network}/model/entity/client/Type.kt | 2 +- .../client/UpdateClientEntityMobile.kt | 2 +- .../model/entity/kyc/KYCLevel1Details.kt | 2 +- .../network}/model/entity/noncore/Document.kt | 2 +- .../model/entity/payload/ClientPayload.kt | 4 +- .../model/entity/payload/DataTablePayload.kt | 2 +- .../model/entity/payload/PayPayload.kt | 2 +- .../model/entity/payload/PayResponse.kt | 4 +- .../payload/StandingInstructionPayload.kt | 2 +- .../model/entity/payload/TransferPayload.kt | 2 +- .../model/entity/payload/UpdateVpaPayload.kt | 2 +- .../model/entity/register/RegisterPayload.kt | 2 +- .../model/entity/register/UserVerify.kt | 2 +- .../network}/model/entity/savedcards/Card.kt | 2 +- .../core/network/model/entity/signup}/City.kt | 2 +- .../network/model/entity/signup}/Country.kt | 2 +- .../network/model/entity/signup}/State.kt | 2 +- .../entity/standinginstruction/SDIResponse.kt | 2 +- .../StandingInstruction.kt | 15 +- .../entity/templates/account/AccountOption.kt | 4 +- .../account/AccountOptionsTemplate.kt | 6 +- .../entity/templates/account/AccountType.kt | 2 +- .../beneficiary/AccountTypeOption.kt | 2 +- .../beneficiary/BeneficiaryTemplate.kt | 4 +- .../model/entity/user/NewUserEntity.kt} | 20 +- .../entity}/user/UpdateUserEntityClients.kt | 2 +- .../entity}/user/UpdateUserEntityEmail.kt | 2 +- .../entity}/user/UpdateUserEntityPassword.kt | 2 +- .../core/network/model/entity}/user/User.kt | 4 +- .../network/model}/twofactor/AccessToken.kt | 2 +- .../model}/twofactor/DeliveryMethod.kt | 2 +- .../services/AccountTransfersService.kt | 4 +- .../network/services/AuthenticationService.kt | 4 +- .../network/services/BeneficiaryService.kt | 8 +- .../core/network/services/ClientService.kt | 18 +- .../core/network/services/DocumentService.kt | 2 +- .../core/network/services/InvoiceService.kt | 2 +- .../core/network/services/KYCLevel1Service.kt | 2 +- .../network/services/NotificationService.kt | 2 +- .../network/services/RegistrationService.kt | 4 +- .../core/network/services/RunReportService.kt | 2 +- .../core/network/services/SavedCardService.kt | 2 +- .../services/SavingsAccountsService.kt | 12 +- .../core/network/services/SearchService.kt | 2 +- .../services/StandingInstructionService.kt | 8 +- .../services/ThirdPartyTransferService.kt | 6 +- .../network/services/TwoFactorAuthService.kt | 4 +- .../core/network/services/UserService.kt | 8 +- .../core/network/utils/KtorInterceptor.kt | 56 +- .../org/mifospay/core/ui/FaqItemScreen.kt | 2 +- .../mifospay/core/ui/TransactionItemScreen.kt | 11 +- .../feature/auth/login/LoginScreen.kt | 4 +- .../feature/auth/login/LoginViewModel.kt | 4 +- .../mobileVerify/MobileVerificationScreen.kt | 4 +- .../feature/auth/signup/SignupScreen.kt | 4 +- .../feature/auth/signup/SignupViewModel.kt | 12 +- feature/home/build.gradle.kts | 18 +- .../{main => androidMain}/AndroidManifest.xml | 0 .../drawable/arrow_backward.xml} | 12 +- .../drawable/arrow_outward.xml} | 8 +- .../composeResources/drawable/coin_image.png | Bin 0 -> 345967 bytes .../composeResources}/values/strings.xml | 2 + .../org/mifospay/feature/home/HomeScreen.kt | 595 ++++++++++++++++++ .../mifospay/feature/home/HomeViewModel.kt | 209 ++++++ .../mifospay/feature/home/di/HomeModule.kt | 12 +- .../feature/home/navigation/HomeNavigation.kt | 2 + .../org/mifospay/feature/home/HomeScreen.kt | 332 ---------- .../mifospay/feature/home/HomeViewModel.kt | 86 --- .../feature/kyc/KYCDescriptionScreen.kt | 12 +- .../feature/kyc/KYCDescriptionViewModel.kt | 2 +- .../feature/kyc/KYCLevel1ViewModel.kt | 6 +- .../profile/edit/EditProfileViewModel.kt | 2 +- .../org/mifos/library/passcode/theme/Font.kt | 6 - .../prodReleaseRuntimeClasspath.tree.txt | 140 +++-- .../prodReleaseRuntimeClasspath.txt | 5 +- mifospay-shared/build.gradle.kts | 2 + .../kotlin/org/mifospay/shared/MifosPayApp.kt | 47 +- .../org/mifospay/shared/MifosPayViewModel.kt | 2 +- .../org/mifospay/shared/di/KoinModules.kt | 2 + .../shared/navigation/MifosNavHost.kt | 64 +- .../shared/navigation/PasscodeNavGraph.kt | 28 +- .../shared/navigation/RootNavGraph.kt | 9 +- .../kotlin/org/mifospay/shared/ui/MifosApp.kt | 60 +- .../org/mifospay/shared/ui/MifosAppState.kt | 5 +- 229 files changed, 3508 insertions(+), 1534 deletions(-) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/utils => common/src/commonMain/kotlin/org/mifospay/core/common}/DateHelper.kt (99%) create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TrannsferDetailMapper.kt create mode 100644 core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/UserMapper.kt delete mode 100644 core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/utils/UserMapper.kt create mode 100644 core/designsystem/src/commonMain/composeResources/font/outfit_black.ttf create mode 100644 core/designsystem/src/commonMain/composeResources/font/outfit_bold.ttf create mode 100644 core/designsystem/src/commonMain/composeResources/font/outfit_extra_bold.ttf create mode 100644 core/designsystem/src/commonMain/composeResources/font/outfit_extra_light.ttf create mode 100644 core/designsystem/src/commonMain/composeResources/font/outfit_light.ttf create mode 100644 core/designsystem/src/commonMain/composeResources/font/outfit_medium.ttf create mode 100644 core/designsystem/src/commonMain/composeResources/font/outfit_regular.ttf create mode 100644 core/designsystem/src/commonMain/composeResources/font/outfit_semi_bold.ttf create mode 100644 core/designsystem/src/commonMain/composeResources/font/outfit_thin.ttf create mode 100644 core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/IconBox.kt create mode 100644 core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/AppScrollbars.kt create mode 100644 core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/LazyScrollbarUtilities.kt create mode 100644 core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/Scrollbar.kt create mode 100644 core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/ScrollbarExt.kt create mode 100644 core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/ThumbExt.kt rename core/model/src/commonMain/kotlin/org/mifospay/core/model/{domain => account}/Account.kt (71%) rename core/model/src/commonMain/kotlin/org/mifospay/core/model/{domain => account}/NewAccount.kt (93%) rename core/model/src/commonMain/kotlin/org/mifospay/core/model/{domain => bank}/Bank.kt (76%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/bank/BankAccountDetails.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/client/AccountWithTransactions.kt rename core/model/src/commonMain/kotlin/org/mifospay/core/model/{ClientInfo.kt => client/Client.kt} (73%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/client/ClientAccount.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/client/ClientAddress.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/client/NewClient.kt delete mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/BankAccountDetails.kt delete mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Transaction.kt delete mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt delete mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingAccount.kt delete mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransferDetail.kt rename core/model/src/commonMain/kotlin/org/mifospay/core/model/{domain => savingsaccount}/Currency.kt (67%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/DepositType.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/SavingAccount.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Status.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Transaction.kt rename core/model/src/commonMain/kotlin/org/mifospay/core/model/{domain => savingsaccount}/TransactionType.kt (89%) create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/TransferDetail.kt rename core/model/src/commonMain/kotlin/org/mifospay/core/model/{domain => search}/SearchResult.kt (52%) delete mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/SignupData.kt create mode 100644 core/model/src/commonMain/kotlin/org/mifospay/core/model/user/NewUser.kt rename core/model/src/commonMain/kotlin/org/mifospay/core/model/{ => user}/RoleInfo.kt (74%) rename core/model/src/commonMain/kotlin/org/mifospay/core/model/{ => user}/UserData.kt (85%) rename core/model/src/commonMain/kotlin/org/mifospay/core/model/{ => user}/UserInfo.kt (82%) rename core/network/src/commonMain/kotlin/org/mifospay/core/network/model/{ClientResponse.kt => ClientResponseEntity.kt} (93%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/domain => network/src/commonMain/kotlin/org/mifospay/core/network/model}/NotificationPayload.kt (92%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/Invoice.kt (95%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/Page.kt (91%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/Role.kt (91%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/SearchedEntity.kt (92%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/TPTResponse.kt (91%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/Timeline.kt (96%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/UserEntity.kt (94%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/UserWithRole.kt (92%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/accounts/SavingAccountsListResponse.kt (70%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/CurrencyEntity.kt} (89%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/accounts/savings/PaymentDetailData.kt (83%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/accounts/savings/PaymentType.kt (88%) create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/SavingAccountEntity.kt rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/accounts/savings/SavingsWithAssociationsEntity.kt (57%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Status.kt => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/StatusEntity.kt} (93%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/accounts/savings/Summary.kt (82%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/accounts/savings/TimeLine.kt (95%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/accounts/savings/TransactionType.kt (94%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/accounts/savings/TransactionsEntity.kt (90%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/accounts/savings/Transfer.kt (87%) create mode 100644 core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TransferDetailEntity.kt rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/authentication/AuthenticationPayload.kt (88%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/beneficary/Beneficiary.kt (72%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/beneficary/BeneficiaryPayload.kt (93%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/beneficary/BeneficiaryUpdatePayload.kt (89%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientAccounts.kt => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/ClientAccountsEntity.kt} (53%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/client/ClientEntity.kt (89%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/client/Currency.kt (93%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/DepositTypeEntity.kt} (83%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/NewClientEntity.kt} (92%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/client/Status.kt (91%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/client/Type.kt (89%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/domain => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity}/client/UpdateClientEntityMobile.kt (87%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/kyc/KYCLevel1Details.kt (92%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/noncore/Document.kt (92%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/payload/ClientPayload.kt (86%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/payload/DataTablePayload.kt (93%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/payload/PayPayload.kt (91%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/payload/PayResponse.kt (81%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/payload/StandingInstructionPayload.kt (95%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/payload/TransferPayload.kt (95%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/payload/UpdateVpaPayload.kt (89%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/register/RegisterPayload.kt (92%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/register/UserVerify.kt (89%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/savedcards/Card.kt (90%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup}/City.kt (90%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup}/Country.kt (89%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup}/State.kt (90%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/standinginstruction/SDIResponse.kt (87%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/standinginstruction/StandingInstruction.kt (55%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/templates/account/AccountOption.kt (78%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/templates/account/AccountOptionsTemplate.kt (58%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/templates/account/AccountType.kt (88%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/templates/beneficiary/AccountTypeOption.kt (87%) rename core/{model/src/commonMain/kotlin/org/mifospay/core => network/src/commonMain/kotlin/org/mifospay/core/network}/model/entity/templates/beneficiary/BeneficiaryTemplate.kt (68%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/NewUserEntity.kt} (51%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/domain => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity}/user/UpdateUserEntityClients.kt (89%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/domain => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity}/user/UpdateUserEntityEmail.kt (89%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/domain => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity}/user/UpdateUserEntityPassword.kt (90%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/domain => network/src/commonMain/kotlin/org/mifospay/core/network/model/entity}/user/User.kt (88%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/domain => network/src/commonMain/kotlin/org/mifospay/core/network/model}/twofactor/AccessToken.kt (90%) rename core/{model/src/commonMain/kotlin/org/mifospay/core/model/domain => network/src/commonMain/kotlin/org/mifospay/core/network/model}/twofactor/DeliveryMethod.kt (90%) rename feature/home/src/{main => androidMain}/AndroidManifest.xml (100%) rename feature/home/src/{main/res/drawable/feature_home_ic_arrow_back_black_24dp.xml => commonMain/composeResources/drawable/arrow_backward.xml} (60%) rename feature/home/src/{main/res/values/colors.xml => commonMain/composeResources/drawable/arrow_outward.xml} (52%) create mode 100644 feature/home/src/commonMain/composeResources/drawable/coin_image.png rename feature/home/src/{main/res => commonMain/composeResources}/values/strings.xml (66%) create mode 100644 feature/home/src/commonMain/kotlin/org/mifospay/feature/home/HomeScreen.kt create mode 100644 feature/home/src/commonMain/kotlin/org/mifospay/feature/home/HomeViewModel.kt rename feature/home/src/{main => commonMain}/kotlin/org/mifospay/feature/home/di/HomeModule.kt (61%) rename feature/home/src/{main => commonMain}/kotlin/org/mifospay/feature/home/navigation/HomeNavigation.kt (92%) delete mode 100644 feature/home/src/main/kotlin/org/mifospay/feature/home/HomeScreen.kt delete mode 100644 feature/home/src/main/kotlin/org/mifospay/feature/home/HomeViewModel.kt diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index 58ae08079..35745924c 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -39,6 +39,7 @@ kotlin { api(libs.kermit.logging) api(libs.squareup.okio) api(libs.jb.kotlin.stdlib) + api(libs.kotlinx.datetime) } androidMain.dependencies { diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt b/core/common/src/commonMain/kotlin/org/mifospay/core/common/DateHelper.kt similarity index 99% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt rename to core/common/src/commonMain/kotlin/org/mifospay/core/common/DateHelper.kt index 819cdd41d..6c0c4919c 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt +++ b/core/common/src/commonMain/kotlin/org/mifospay/core/common/DateHelper.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.utils +package org.mifospay.core.common import kotlinx.datetime.Clock import kotlinx.datetime.DateTimeUnit diff --git a/core/data/build.gradle.kts b/core/data/build.gradle.kts index 36ec8ba1f..80c987522 100644 --- a/core/data/build.gradle.kts +++ b/core/data/build.gradle.kts @@ -28,9 +28,8 @@ kotlin { commonMain.dependencies { api(projects.core.common) api(projects.core.datastore) - api(projects.core.network) api(projects.core.model) - + implementation(projects.core.network) implementation(projects.core.analytics) } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/AccountMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/AccountMapper.kt index e4aca8873..3e5045e89 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/AccountMapper.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/AccountMapper.kt @@ -9,10 +9,10 @@ */ package org.mifospay.core.data.mapper -import org.mifospay.core.model.domain.Account -import org.mifospay.core.model.entity.client.ClientAccounts +import org.mifospay.core.model.account.Account +import org.mifospay.core.network.model.entity.client.ClientAccountsEntity -fun ClientAccounts.toAccount(): List { +fun ClientAccountsEntity.toAccount(): List { return this.savingsAccounts.map { Account( name = it.productName, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/ClientDetailsMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/ClientDetailsMapper.kt index 727d28a4f..ed597cbbb 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/ClientDetailsMapper.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/ClientDetailsMapper.kt @@ -9,13 +9,17 @@ */ package org.mifospay.core.data.mapper -import org.mifospay.core.model.domain.client.Client -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.client.ClientEntity +import org.mifospay.core.model.client.Client +import org.mifospay.core.model.client.ClientAddress +import org.mifospay.core.model.client.NewClient +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.client.Address +import org.mifospay.core.network.model.entity.client.ClientEntity +import org.mifospay.core.network.model.entity.client.NewClientEntity fun ClientEntity.toModel(): Client { return Client( - name = this.displayName, + name = this.displayName ?: "", clientId = this.id.toLong(), externalId = this.externalId, mobileNo = this.mobileNo, @@ -32,3 +36,25 @@ fun Page.toModel(): Page { pageItems = this.pageItems.map { it.toModel() }.toMutableList(), ) } + +fun NewClient.toEntity(): NewClientEntity { + return NewClientEntity( + firstname = firstname, + lastname = lastname, + externalId = externalId, + mobileNo = mobileNo, + address = address.toEntity(), + savingsProductId = savingsProductId, + ) +} + +fun ClientAddress.toEntity(): Address { + return Address( + addressLine1 = addressLine1, + addressLine2 = addressLine2, + postalCode = postalCode, + stateProvinceId = stateProvinceId, + countryId = countryId, + addressTypeId = addressTypeId, + ) +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/CurrencyMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/CurrencyMapper.kt index c70c2c882..0517a7bc2 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/CurrencyMapper.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/CurrencyMapper.kt @@ -9,10 +9,10 @@ */ package org.mifospay.core.data.mapper -import org.mifospay.core.model.entity.accounts.savings.Currency -import org.mifospay.core.model.domain.Currency as DomainCurrency +import org.mifospay.core.network.model.entity.accounts.savings.CurrencyEntity +import org.mifospay.core.model.savingsaccount.Currency as DomainCurrency -fun Currency.toModel(): DomainCurrency { +fun CurrencyEntity.toModel(): DomainCurrency { return DomainCurrency( code = this.code, displayLabel = this.displayLabel, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/SearchedEntitiesMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/SearchedEntitiesMapper.kt index 4208aed4a..7ee5d1ec9 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/SearchedEntitiesMapper.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/SearchedEntitiesMapper.kt @@ -9,15 +9,18 @@ */ package org.mifospay.core.data.mapper -import org.mifospay.core.model.domain.SearchResult -import org.mifospay.core.model.entity.SearchedEntity +import org.mifospay.core.model.search.SearchResult +import org.mifospay.core.network.model.entity.SearchedEntity -fun SearchedEntity.toSearchResult(): SearchResult { +fun SearchedEntity.toModel(): SearchResult { return SearchResult( - resultId = this.entityId, - resultName = this.entityName, - resultType = this.entityType, + entityId = entityId, + entityAccountNo = entityAccountNo, + entityName = entityName, + entityType = entityType, + parentId = parentId, + parentName = parentName, ) } -fun List.toSearchResult(): List = map { it.toSearchResult() } +fun List.toSearchResult(): List = map { it.toModel() } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TrannsferDetailMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TrannsferDetailMapper.kt new file mode 100644 index 000000000..0dc0a86d5 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TrannsferDetailMapper.kt @@ -0,0 +1,76 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.mapper + +import org.mifospay.core.model.savingsaccount.DepositType +import org.mifospay.core.model.savingsaccount.SavingAccount +import org.mifospay.core.model.savingsaccount.Status +import org.mifospay.core.model.savingsaccount.TransferDetail +import org.mifospay.core.network.model.entity.accounts.savings.SavingAccountEntity +import org.mifospay.core.network.model.entity.accounts.savings.StatusEntity +import org.mifospay.core.network.model.entity.accounts.savings.TransferDetailEntity +import org.mifospay.core.network.model.entity.client.DepositTypeEntity + +fun TransferDetailEntity.toModel(): TransferDetail { + return TransferDetail( + id = id, + fromClient = fromClient.toModel(), + fromAccount = fromAccount.toModel(), + toClient = toClient.toModel(), + toAccount = toAccount.toModel(), + ) +} + +fun SavingAccountEntity.toModel(): SavingAccount { + return SavingAccount( + id = id, + accountNo = accountNo, + productName = productName, + productId = productId, + overdraftLimit = overdraftLimit, + minRequiredBalance = minRequiredBalance, + accountBalance = accountBalance, + totalDeposits = totalDeposits, + savingsProductName = savingsProductName, + clientName = clientName, + savingsProductId = savingsProductId, + nominalAnnualInterestRate = nominalAnnualInterestRate, + status = status?.toModel(), + currency = currency.toModel(), + depositType = depositType?.toModel(), + isRecurring = this.isRecurring(), + ) +} + +fun StatusEntity.toModel(): Status { + return Status( + id = id, + code = code, + value = value, + submittedAndPendingApproval = submittedAndPendingApproval, + approved = approved, + rejected = rejected, + withdrawnByApplicant = withdrawnByApplicant, + active = active, + closed = closed, + prematureClosed = prematureClosed, + transferInProgress = transferInProgress, + transferOnHold = transferOnHold, + matured = matured, + ) +} + +fun DepositTypeEntity.toModel(): DepositType { + return DepositType( + id = id, + code = code, + value = value, + ) +} diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TransactionMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TransactionMapper.kt index 41c4820b3..e73ff2b4b 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TransactionMapper.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/TransactionMapper.kt @@ -9,11 +9,11 @@ */ package org.mifospay.core.data.mapper -import org.mifospay.core.model.domain.Transaction -import org.mifospay.core.model.domain.TransactionType -import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity -import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity -import org.mifospay.core.model.utils.DateHelper +import org.mifospay.core.common.DateHelper +import org.mifospay.core.model.savingsaccount.Transaction +import org.mifospay.core.model.savingsaccount.TransactionType +import org.mifospay.core.network.model.entity.accounts.savings.SavingsWithAssociationsEntity +import org.mifospay.core.network.model.entity.accounts.savings.TransactionsEntity fun SavingsWithAssociationsEntity.toTransactionList(): List { return this.transactions.map { it.toModel() } @@ -32,5 +32,8 @@ fun TransactionsEntity.toModel(): Transaction { else -> TransactionType.OTHER }, transferId = this.originalTransactionId ?: 0, + clientId = 0, + accountId = this.accountId?.toLong() ?: 0L, + transferDetail = null, ) } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/UserMapper.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/UserMapper.kt new file mode 100644 index 000000000..bedfc89d6 --- /dev/null +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/mapper/UserMapper.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.data.mapper + +import org.mifospay.core.model.user.NewUser +import org.mifospay.core.model.user.RoleInfo +import org.mifospay.core.model.user.UserInfo +import org.mifospay.core.network.model.entity.Role +import org.mifospay.core.network.model.entity.user.NewUserEntity +import org.mifospay.core.network.model.entity.user.User + +private const val OFFICE_ID = 1 +private const val MOBILE_WALLET_ROLE_ID = 2 +private const val SUPER_USER_ROLE_ID = 1 + +val NEW_USER_ROLE_IDS: ArrayList = arrayListOf(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID) + +fun NewUser.toEntity(): NewUserEntity { + return NewUserEntity( + username = username, + firstname = firstname, + lastname = lastname, + email = email, + password = password, + officeId = OFFICE_ID, + roles = NEW_USER_ROLE_IDS, + sendPasswordToEmail = false, + isSelfServiceUser = true, + repeatPassword = password, + ) +} + +fun User.toUserInfo() = UserInfo( + username = username, + userId = userId, + base64EncodedAuthenticationKey = base64EncodedAuthenticationKey, + authenticated = authenticated, + officeId = officeId, + officeName = officeName, + roles = roles.map { it.toRoleInfo() }, + permissions = permissions, + clients = clients, + shouldRenewPassword = shouldRenewPassword, + isTwoFactorAuthenticationRequired = isTwoFactorAuthenticationRequired, +) + +fun Role.toRoleInfo() = RoleInfo( + id = id ?: "", + name = name ?: "", + description = description ?: "", + disabled = disabled, +) diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AccountRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AccountRepository.kt index 246d77517..7dc93bc56 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AccountRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AccountRepository.kt @@ -11,7 +11,7 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.entity.accounts.savings.TransferDetail +import org.mifospay.core.model.savingsaccount.TransferDetail interface AccountRepository { suspend fun getAccountTransfer(transferId: Long): Flow> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt index a2c53f0fe..a68c02fe8 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/AuthenticationRepository.kt @@ -10,8 +10,8 @@ package org.mifospay.core.data.repository import org.mifospay.core.common.Result -import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.user.UserInfo interface AuthenticationRepository { - suspend fun authenticate(username: String, password: String): Result + suspend fun authenticate(username: String, password: String): Result } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt index de31cc9ec..8cd329f11 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/BeneficiaryRepository.kt @@ -11,11 +11,11 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.entity.beneficary.Beneficiary -import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload -import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload -import org.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate import org.mifospay.core.network.model.CommonResponse +import org.mifospay.core.network.model.entity.beneficary.Beneficiary +import org.mifospay.core.network.model.entity.beneficary.BeneficiaryPayload +import org.mifospay.core.network.model.entity.beneficary.BeneficiaryUpdatePayload +import org.mifospay.core.network.model.entity.templates.beneficiary.BeneficiaryTemplate interface BeneficiaryRepository { suspend fun getBeneficiaryList(): Flow>> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt index b5481f0bd..13112b3f4 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ClientRepository.kt @@ -11,11 +11,11 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.domain.client.Client -import org.mifospay.core.model.domain.client.NewClient -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.client.ClientAccounts -import org.mifospay.core.network.model.ClientResponse +import org.mifospay.core.model.account.Account +import org.mifospay.core.model.client.Client +import org.mifospay.core.model.client.NewClient +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.client.ClientAccountsEntity interface ClientRepository { @@ -29,11 +29,11 @@ interface ClientRepository { suspend fun updateClientImage(clientId: Long, image: String): Flow> - suspend fun getClientAccounts(clientId: Long): Flow> + suspend fun getClientAccounts(clientId: Long): Flow> - suspend fun getAccounts(clientId: Long, accountType: String): Flow> + suspend fun getAccounts(clientId: Long, accountType: String): Result> - suspend fun createClient(newClient: NewClient): Result + suspend fun createClient(newClient: NewClient): Result - suspend fun deleteClient(clientId: Int): Result + suspend fun deleteClient(clientId: Int): Result } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt index e524862d2..3efeec010 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/DocumentRepository.kt @@ -12,7 +12,7 @@ package org.mifospay.core.data.repository import io.ktor.http.content.PartData import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.entity.noncore.Document +import org.mifospay.core.network.model.entity.noncore.Document interface DocumentRepository { suspend fun getDocuments(entityType: String, entityId: Int): Flow>> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/InvoiceRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/InvoiceRepository.kt index 63d5affb5..4bc53f800 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/InvoiceRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/InvoiceRepository.kt @@ -11,8 +11,8 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.entity.Invoice import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.Invoice interface InvoiceRepository { suspend fun getInvoice(clientId: Int, invoiceId: Int): Flow> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/KycLevelRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/KycLevelRepository.kt index 0326045ff..a5954daa4 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/KycLevelRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/KycLevelRepository.kt @@ -11,8 +11,8 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.kyc.KYCLevel1Details interface KycLevelRepository { suspend fun fetchKYCLevel1Details(clientId: Int): Flow>> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/NotificationRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/NotificationRepository.kt index 30d10ddad..22ae67eb3 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/NotificationRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/NotificationRepository.kt @@ -11,7 +11,7 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.domain.NotificationPayload +import org.mifospay.core.network.model.NotificationPayload interface NotificationRepository { suspend fun fetchNotifications(clientId: Long): Flow>> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RegistrationRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RegistrationRepository.kt index 9cc290d42..288eb7543 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RegistrationRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RegistrationRepository.kt @@ -10,8 +10,8 @@ package org.mifospay.core.data.repository import org.mifospay.core.common.Result -import org.mifospay.core.model.entity.register.RegisterPayload -import org.mifospay.core.model.entity.register.UserVerify +import org.mifospay.core.network.model.entity.register.RegisterPayload +import org.mifospay.core.network.model.entity.register.UserVerify interface RegistrationRepository { suspend fun registerUser(registerPayload: RegisterPayload): Result diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RunReportRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RunReportRepository.kt index e2eb96968..eda8c5ecc 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RunReportRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/RunReportRepository.kt @@ -11,7 +11,7 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.domain.Transaction +import org.mifospay.core.model.savingsaccount.Transaction interface RunReportRepository { suspend fun getTransactionReceipt( diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavedCardRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavedCardRepository.kt index e2feb9514..819759e87 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavedCardRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavedCardRepository.kt @@ -11,8 +11,8 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.entity.savedcards.Card import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.savedcards.Card interface SavedCardRepository { suspend fun getSavedCards(clientId: Int): Flow>> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavingsAccountRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavingsAccountRepository.kt index f3a3b70ba..608e10ce3 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavingsAccountRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SavingsAccountRepository.kt @@ -11,11 +11,11 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.domain.Transaction -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.accounts.savings.SavingAccount -import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity +import org.mifospay.core.model.savingsaccount.Transaction import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.accounts.savings.SavingAccountEntity +import org.mifospay.core.network.model.entity.accounts.savings.SavingsWithAssociationsEntity interface SavingsAccountRepository { suspend fun getSavingsAccounts(limit: Int): Flow>> @@ -25,9 +25,12 @@ interface SavingsAccountRepository { associationType: String, ): Flow> - suspend fun createSavingsAccount(savingAccount: SavingAccount): Flow> + suspend fun createSavingsAccount(savingAccount: SavingAccountEntity): Flow> - suspend fun blockUnblockAccount(accountId: Long, command: String?): Flow> + suspend fun blockUnblockAccount( + accountId: Long, + command: String?, + ): Flow> suspend fun getSavingAccountTransaction( accountId: Long, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt index 1dfec0479..c3649a378 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SearchRepository.kt @@ -10,12 +10,12 @@ package org.mifospay.core.data.repository import org.mifospay.core.common.Result -import org.mifospay.core.model.entity.SearchedEntity +import org.mifospay.core.model.search.SearchResult interface SearchRepository { suspend fun searchResources( query: String, resources: String, exactMatch: Boolean, - ): Result> + ): Result> } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt index dc0c437ff..7d248413c 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/SelfServiceRepository.kt @@ -11,17 +11,16 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.domain.client.Client -import org.mifospay.core.model.domain.user.User -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity -import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity -import org.mifospay.core.model.entity.authentication.AuthenticationPayload -import org.mifospay.core.model.entity.beneficary.Beneficiary -import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload -import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload -import org.mifospay.core.model.entity.client.ClientAccounts +import org.mifospay.core.model.account.Account +import org.mifospay.core.model.client.Client +import org.mifospay.core.model.savingsaccount.Transaction import org.mifospay.core.network.model.CommonResponse +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.authentication.AuthenticationPayload +import org.mifospay.core.network.model.entity.beneficary.Beneficiary +import org.mifospay.core.network.model.entity.beneficary.BeneficiaryPayload +import org.mifospay.core.network.model.entity.beneficary.BeneficiaryUpdatePayload +import org.mifospay.core.network.model.entity.user.User interface SelfServiceRepository { suspend fun loginSelf(payload: AuthenticationPayload): Result @@ -30,16 +29,16 @@ interface SelfServiceRepository { suspend fun getSelfClientDetails(): Flow>> - suspend fun getSelfAccountTransactions( + fun getSelfAccountTransactions( accountId: Long, - ): Flow> + ): Flow> suspend fun getSelfAccountTransactionFromId( accountId: Long, transactionId: Long, - ): Flow> + ): Result> - suspend fun getSelfAccounts(clientId: Long): Flow> + suspend fun getSelfAccounts(clientId: Long): Result> suspend fun getBeneficiaryList(): Flow>> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/StandingInstructionRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/StandingInstructionRepository.kt index 747e46a88..cf927559c 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/StandingInstructionRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/StandingInstructionRepository.kt @@ -11,11 +11,11 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.payload.StandingInstructionPayload -import org.mifospay.core.model.entity.standinginstruction.SDIResponse -import org.mifospay.core.model.entity.standinginstruction.StandingInstruction import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.payload.StandingInstructionPayload +import org.mifospay.core.network.model.entity.standinginstruction.SDIResponse +import org.mifospay.core.network.model.entity.standinginstruction.StandingInstruction interface StandingInstructionRepository { suspend fun getAllStandingInstructions( diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ThirdPartyTransferRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ThirdPartyTransferRepository.kt index c7cadf08b..13b6a7493 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ThirdPartyTransferRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/ThirdPartyTransferRepository.kt @@ -11,9 +11,9 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.entity.TPTResponse -import org.mifospay.core.model.entity.payload.TransferPayload -import org.mifospay.core.model.entity.templates.account.AccountOptionsTemplate +import org.mifospay.core.network.model.entity.TPTResponse +import org.mifospay.core.network.model.entity.payload.TransferPayload +import org.mifospay.core.network.model.entity.templates.account.AccountOptionsTemplate interface ThirdPartyTransferRepository { suspend fun getTransferTemplate(): Flow> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/TwoFactorAuthRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/TwoFactorAuthRepository.kt index 267560b3e..37bc17ddb 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/TwoFactorAuthRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/TwoFactorAuthRepository.kt @@ -11,8 +11,8 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.domain.twofactor.AccessToken -import org.mifospay.core.model.domain.twofactor.DeliveryMethod +import org.mifospay.core.network.model.twofactor.AccessToken +import org.mifospay.core.network.model.twofactor.DeliveryMethod interface TwoFactorAuthRepository { suspend fun deliveryMethods(): Flow>> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt index 8cabf58e1..915761d86 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repository/UserRepository.kt @@ -11,17 +11,17 @@ package org.mifospay.core.data.repository import kotlinx.coroutines.flow.Flow import org.mifospay.core.common.Result -import org.mifospay.core.model.domain.user.NewUser -import org.mifospay.core.model.entity.UserWithRole +import org.mifospay.core.model.user.NewUser import org.mifospay.core.network.model.CommonResponse import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.UserWithRole interface UserRepository { suspend fun getUsers(): Flow>> suspend fun getUser(): Flow> - suspend fun createUser(newUser: NewUser): Result + suspend fun createUser(newUser: NewUser): Result suspend fun updateUser(userId: Int, updatedUser: NewUser): Flow> diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AccountRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AccountRepositoryImpl.kt index 13230bb62..3a6c84a01 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AccountRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AccountRepositoryImpl.kt @@ -12,10 +12,12 @@ package org.mifospay.core.data.repositoryImp import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map import org.mifospay.core.common.Result import org.mifospay.core.common.asResult +import org.mifospay.core.data.mapper.toModel import org.mifospay.core.data.repository.AccountRepository -import org.mifospay.core.model.entity.accounts.savings.TransferDetail +import org.mifospay.core.model.savingsaccount.TransferDetail import org.mifospay.core.network.FineractApiManager class AccountRepositoryImpl( @@ -26,6 +28,7 @@ class AccountRepositoryImpl( return apiManager .accountTransfersApi .getAccountTransfer(transferId) + .map { it.toModel() } .asResult() .flowOn(ioDispatcher) } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt index 0a9ed9fa6..18fd2d1fb 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/AuthenticationRepositoryImpl.kt @@ -12,16 +12,17 @@ package org.mifospay.core.data.repositoryImp import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext import org.mifospay.core.common.Result +import org.mifospay.core.data.mapper.toUserInfo import org.mifospay.core.data.repository.AuthenticationRepository -import org.mifospay.core.model.domain.user.User -import org.mifospay.core.model.entity.authentication.AuthenticationPayload +import org.mifospay.core.model.user.UserInfo import org.mifospay.core.network.SelfServiceApiManager +import org.mifospay.core.network.model.entity.authentication.AuthenticationPayload class AuthenticationRepositoryImpl( private val apiManager: SelfServiceApiManager, private val ioDispatcher: CoroutineDispatcher, ) : AuthenticationRepository { - override suspend fun authenticate(username: String, password: String): Result { + override suspend fun authenticate(username: String, password: String): Result { return try { val payload = AuthenticationPayload(username, password) @@ -29,7 +30,7 @@ class AuthenticationRepositoryImpl( apiManager.authenticationApi.authenticate(payload) } - Result.Success(result) + Result.Success(result.toUserInfo()) } catch (e: Exception) { Result.Error(e) } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt index 49e3e1a2c..e9abdcf8b 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/BeneficiaryRepositoryImpl.kt @@ -15,12 +15,12 @@ import kotlinx.coroutines.flow.flowOn import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.BeneficiaryRepository -import org.mifospay.core.model.entity.beneficary.Beneficiary -import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload -import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload -import org.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate import org.mifospay.core.network.SelfServiceApiManager import org.mifospay.core.network.model.CommonResponse +import org.mifospay.core.network.model.entity.beneficary.Beneficiary +import org.mifospay.core.network.model.entity.beneficary.BeneficiaryPayload +import org.mifospay.core.network.model.entity.beneficary.BeneficiaryUpdatePayload +import org.mifospay.core.network.model.entity.templates.beneficiary.BeneficiaryTemplate class BeneficiaryRepositoryImpl( private val apiManager: SelfServiceApiManager, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt index 62d0b01b4..1b935e27d 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ClientRepositoryImpl.kt @@ -16,15 +16,17 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.withContext import org.mifospay.core.common.Result import org.mifospay.core.common.asResult +import org.mifospay.core.data.mapper.toAccount +import org.mifospay.core.data.mapper.toEntity import org.mifospay.core.data.mapper.toModel import org.mifospay.core.data.repository.ClientRepository -import org.mifospay.core.model.domain.client.Client -import org.mifospay.core.model.domain.client.NewClient -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.client.ClientAccounts +import org.mifospay.core.model.account.Account +import org.mifospay.core.model.client.Client +import org.mifospay.core.model.client.NewClient import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.SelfServiceApiManager -import org.mifospay.core.network.model.ClientResponse +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.client.ClientAccountsEntity class ClientRepositoryImpl( private val apiManager: SelfServiceApiManager, @@ -37,8 +39,8 @@ class ClientRepositoryImpl( override suspend fun getClient(clientId: Long): Result { return try { - val result = apiManager.clientsApi.getClientForId(clientId).toModel() - Result.Success(result) + val result = apiManager.clientsApi.getClientForId(clientId) + Result.Success(result.toModel()) } catch (e: Exception) { Result.Error(e) } @@ -60,7 +62,7 @@ class ClientRepositoryImpl( .asResult().flowOn(ioDispatcher) } - override suspend fun getClientAccounts(clientId: Long): Flow> { + override suspend fun getClientAccounts(clientId: Long): Flow> { return apiManager.clientsApi .getClientAccounts(clientId) .asResult().flowOn(ioDispatcher) @@ -69,31 +71,37 @@ class ClientRepositoryImpl( override suspend fun getAccounts( clientId: Long, accountType: String, - ): Flow> { - return apiManager.clientsApi - .getAccounts(clientId, accountType) - .asResult().flowOn(ioDispatcher) + ): Result> { + return try { + val result = withContext(ioDispatcher) { + apiManager.clientsApi.getAccounts(clientId, accountType) + } + + Result.Success(result.toAccount()) + } catch (e: Exception) { + Result.Error(e) + } } - override suspend fun createClient(newClient: NewClient): Result { + override suspend fun createClient(newClient: NewClient): Result { return try { val result = withContext(ioDispatcher) { - fineractApiManager.clientsApi.createClient(newClient) + fineractApiManager.clientsApi.createClient(newClient.toEntity()) } - Result.Success(result) + Result.Success(result.clientId) } catch (e: Exception) { Result.Error(e) } } - override suspend fun deleteClient(clientId: Int): Result { + override suspend fun deleteClient(clientId: Int): Result { return try { val result = withContext(ioDispatcher) { fineractApiManager.clientsApi.deleteClient(clientId) } - Result.Success(result) + Result.Success(result.clientId) } catch (e: Exception) { Result.Error(e) } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt index ec4108358..e9bfe21cf 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/DocumentRepositoryImpl.kt @@ -16,8 +16,8 @@ import kotlinx.coroutines.flow.flowOn import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.DocumentRepository -import org.mifospay.core.model.entity.noncore.Document import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.entity.noncore.Document class DocumentRepositoryImpl( private val apiManager: FineractApiManager, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/InvoiceRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/InvoiceRepositoryImpl.kt index c41461773..6c1487125 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/InvoiceRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/InvoiceRepositoryImpl.kt @@ -15,9 +15,9 @@ import kotlinx.coroutines.flow.flowOn import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.InvoiceRepository -import org.mifospay.core.model.entity.Invoice import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.Invoice class InvoiceRepositoryImpl( private val apiManager: FineractApiManager, @@ -49,7 +49,10 @@ class InvoiceRepositoryImpl( .flowOn(ioDispatcher) } - override suspend fun deleteInvoice(clientId: Int, invoiceId: Int): Flow> { + override suspend fun deleteInvoice( + clientId: Int, + invoiceId: Int, + ): Flow> { return apiManager.invoiceApi .deleteInvoice(clientId, invoiceId).asResult() .flowOn(ioDispatcher) diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/KycLevelRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/KycLevelRepositoryImpl.kt index 32d5ca277..af256b987 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/KycLevelRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/KycLevelRepositoryImpl.kt @@ -15,15 +15,17 @@ import kotlinx.coroutines.flow.flowOn import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.KycLevelRepository -import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.kyc.KYCLevel1Details class KycLevelRepositoryImpl( private val apiManager: FineractApiManager, private val ioDispatcher: CoroutineDispatcher, ) : KycLevelRepository { - override suspend fun fetchKYCLevel1Details(clientId: Int): Flow>> { + override suspend fun fetchKYCLevel1Details( + clientId: Int, + ): Flow>> { return apiManager.kycLevel1Api .fetchKYCLevel1Details(clientId) .asResult().flowOn(ioDispatcher) diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/NotificationRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/NotificationRepositoryImpl.kt index 209a3008a..d6eff667c 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/NotificationRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/NotificationRepositoryImpl.kt @@ -15,8 +15,8 @@ import kotlinx.coroutines.flow.flowOn import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.NotificationRepository -import org.mifospay.core.model.domain.NotificationPayload import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.NotificationPayload class NotificationRepositoryImpl( private val apiManager: FineractApiManager, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RegistrationRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RegistrationRepositoryImpl.kt index 34c4d11ee..bcb2e5d93 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RegistrationRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RegistrationRepositoryImpl.kt @@ -13,9 +13,9 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext import org.mifospay.core.common.Result import org.mifospay.core.data.repository.RegistrationRepository -import org.mifospay.core.model.entity.register.RegisterPayload -import org.mifospay.core.model.entity.register.UserVerify import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.entity.register.RegisterPayload +import org.mifospay.core.network.model.entity.register.UserVerify class RegistrationRepositoryImpl( private val apiManager: FineractApiManager, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RunReportRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RunReportRepositoryImpl.kt index f24187988..7c989c45b 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RunReportRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/RunReportRepositoryImpl.kt @@ -17,7 +17,7 @@ import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.mapper.toModel import org.mifospay.core.data.repository.RunReportRepository -import org.mifospay.core.model.domain.Transaction +import org.mifospay.core.model.savingsaccount.Transaction import org.mifospay.core.network.FineractApiManager class RunReportRepositoryImpl( diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavedCardRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavedCardRepositoryImpl.kt index 3bf8bd19b..6aebd3457 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavedCardRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavedCardRepositoryImpl.kt @@ -15,9 +15,9 @@ import kotlinx.coroutines.flow.flowOn import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.SavedCardRepository -import org.mifospay.core.model.entity.savedcards.Card import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.savedcards.Card class SavedCardRepositoryImpl( private val apiManager: FineractApiManager, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavingsAccountRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavingsAccountRepositoryImpl.kt index 0e450c251..9bb4b36ad 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavingsAccountRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SavingsAccountRepositoryImpl.kt @@ -11,19 +11,21 @@ package org.mifospay.core.data.repositoryImp import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.mapper.toModel import org.mifospay.core.data.repository.SavingsAccountRepository -import org.mifospay.core.model.domain.Transaction -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.accounts.savings.SavingAccount -import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity -import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity +import org.mifospay.core.model.savingsaccount.Transaction import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.accounts.savings.SavingAccountEntity +import org.mifospay.core.network.model.entity.accounts.savings.SavingsWithAssociationsEntity +import org.mifospay.core.network.model.entity.accounts.savings.TransactionsEntity class SavingsAccountRepositoryImpl( private val apiManager: FineractApiManager, @@ -41,13 +43,22 @@ class SavingsAccountRepositoryImpl( accountId: Long, associationType: String, ): Flow> { - return apiManager.savingsAccountsApi - .getSavingsWithAssociations(accountId, associationType) - .asResult().flowOn(ioDispatcher) + return flow { + try { + val result = withContext(ioDispatcher) { + apiManager.savingsAccountsApi + .getSavingsWithAssociations(accountId, associationType) + } + + emit(Result.Success(result)) + } catch (e: Exception) { + emit(Result.Error(e)) + } + } } override suspend fun createSavingsAccount( - savingAccount: SavingAccount, + savingAccount: SavingAccountEntity, ): Flow> { return apiManager.savingsAccountsApi .createSavingsAccount(savingAccount) diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt index 93f5bd9c6..8f7c7f098 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SearchRepositoryImpl.kt @@ -12,8 +12,9 @@ package org.mifospay.core.data.repositoryImp import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext import org.mifospay.core.common.Result +import org.mifospay.core.data.mapper.toSearchResult import org.mifospay.core.data.repository.SearchRepository -import org.mifospay.core.model.entity.SearchedEntity +import org.mifospay.core.model.search.SearchResult import org.mifospay.core.network.FineractApiManager class SearchRepositoryImpl( @@ -24,13 +25,13 @@ class SearchRepositoryImpl( query: String, resources: String, exactMatch: Boolean, - ): Result> { + ): Result> { return try { val result = withContext(ioDispatcher) { apiManager.searchApi.searchResources(query, resources, exactMatch) } - Result.Success(result) + Result.Success(result.toSearchResult()) } catch (e: Exception) { Result.Error(e) } diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt index 66b287fd2..52ca37a20 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/SelfServiceRepositoryImpl.kt @@ -11,25 +11,28 @@ package org.mifospay.core.data.repositoryImp import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext import org.mifospay.core.common.Result import org.mifospay.core.common.asResult +import org.mifospay.core.data.mapper.toAccount import org.mifospay.core.data.mapper.toModel +import org.mifospay.core.data.mapper.toTransactionList import org.mifospay.core.data.repository.SelfServiceRepository import org.mifospay.core.data.util.Constants -import org.mifospay.core.model.domain.client.Client -import org.mifospay.core.model.domain.user.User -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity -import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity -import org.mifospay.core.model.entity.authentication.AuthenticationPayload -import org.mifospay.core.model.entity.beneficary.Beneficiary -import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload -import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload -import org.mifospay.core.model.entity.client.ClientAccounts +import org.mifospay.core.model.account.Account +import org.mifospay.core.model.client.Client +import org.mifospay.core.model.savingsaccount.Transaction import org.mifospay.core.network.SelfServiceApiManager import org.mifospay.core.network.model.CommonResponse +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.authentication.AuthenticationPayload +import org.mifospay.core.network.model.entity.beneficary.Beneficiary +import org.mifospay.core.network.model.entity.beneficary.BeneficiaryPayload +import org.mifospay.core.network.model.entity.beneficary.BeneficiaryUpdatePayload +import org.mifospay.core.network.model.entity.user.User class SelfServiceRepositoryImpl( private val apiManager: SelfServiceApiManager, @@ -39,7 +42,6 @@ class SelfServiceRepositoryImpl( override suspend fun loginSelf(payload: AuthenticationPayload): Result { return try { val result = apiManager.authenticationApi.authenticate(payload) - ?: return Result.Error(Exception("Authentication failed")) Result.Success(result) } catch (e: Exception) { @@ -60,34 +62,60 @@ class SelfServiceRepositoryImpl( return apiManager.clientsApi.clients().map { it.toModel() }.asResult().flowOn(dispatcher) } - override suspend fun getSelfAccountTransactions( + override fun getSelfAccountTransactions( accountId: Long, - ): Flow> { - return apiManager.savingAccountsListApi - .getSavingsWithAssociations(accountId, Constants.TRANSACTIONS) - .asResult().flowOn(dispatcher) + ): Flow> { + return flow { + try { + val result = withContext(dispatcher) { + apiManager.savingAccountsListApi + .getSavingsWithAssociations(accountId, Constants.TRANSACTIONS) + } + + emit(result.toTransactionList()) + } catch (e: Exception) { + throw e + } + } } override suspend fun getSelfAccountTransactionFromId( accountId: Long, transactionId: Long, - ): Flow> { - return apiManager.savingAccountsListApi - .getSavingAccountTransaction(accountId, transactionId) - .asResult().flowOn(dispatcher) + ): Result> { + return try { + val result = withContext(dispatcher) { + apiManager.savingAccountsListApi.getSavingAccountTransaction( + accountId, + transactionId, + ) + } + + Result.Success(result.map { it.toModel() }) + } catch (e: Exception) { + Result.Error(e) + } } - override suspend fun getSelfAccounts(clientId: Long): Flow> { - return apiManager.clientsApi - .getAccounts(clientId, Constants.SAVINGS) - .asResult().flowOn(dispatcher) + override suspend fun getSelfAccounts(clientId: Long): Result> { + return try { + val result = withContext(dispatcher) { + apiManager.clientsApi.getAccounts(clientId, Constants.SAVINGS) + } + + Result.Success(result.toAccount()) + } catch (e: Exception) { + Result.Error(e) + } } override suspend fun getBeneficiaryList(): Flow>> { return apiManager.beneficiaryApi.beneficiaryList().asResult().flowOn(dispatcher) } - override suspend fun createBeneficiary(beneficiaryPayload: BeneficiaryPayload): Flow> { + override suspend fun createBeneficiary( + beneficiaryPayload: BeneficiaryPayload, + ): Flow> { return apiManager.beneficiaryApi .createBeneficiary(beneficiaryPayload) .asResult().flowOn(dispatcher) diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/StandingInstructionRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/StandingInstructionRepositoryImpl.kt index 5693df4c1..4777a6339 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/StandingInstructionRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/StandingInstructionRepositoryImpl.kt @@ -15,12 +15,12 @@ import kotlinx.coroutines.flow.flowOn import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.StandingInstructionRepository -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.payload.StandingInstructionPayload -import org.mifospay.core.model.entity.standinginstruction.SDIResponse -import org.mifospay.core.model.entity.standinginstruction.StandingInstruction import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.payload.StandingInstructionPayload +import org.mifospay.core.network.model.entity.standinginstruction.SDIResponse +import org.mifospay.core.network.model.entity.standinginstruction.StandingInstruction class StandingInstructionRepositoryImpl( private val apiManager: FineractApiManager, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ThirdPartyTransferRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ThirdPartyTransferRepositoryImpl.kt index 8a4b466ce..e06b4ae17 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ThirdPartyTransferRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/ThirdPartyTransferRepositoryImpl.kt @@ -15,10 +15,10 @@ import kotlinx.coroutines.flow.flowOn import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.ThirdPartyTransferRepository -import org.mifospay.core.model.entity.TPTResponse -import org.mifospay.core.model.entity.payload.TransferPayload -import org.mifospay.core.model.entity.templates.account.AccountOptionsTemplate import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.entity.TPTResponse +import org.mifospay.core.network.model.entity.payload.TransferPayload +import org.mifospay.core.network.model.entity.templates.account.AccountOptionsTemplate class ThirdPartyTransferRepositoryImpl( private val apiManager: FineractApiManager, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/TwoFactorAuthRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/TwoFactorAuthRepositoryImpl.kt index d2342495e..1d4aadad3 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/TwoFactorAuthRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/TwoFactorAuthRepositoryImpl.kt @@ -15,9 +15,9 @@ import kotlinx.coroutines.flow.flowOn import org.mifospay.core.common.Result import org.mifospay.core.common.asResult import org.mifospay.core.data.repository.TwoFactorAuthRepository -import org.mifospay.core.model.domain.twofactor.AccessToken -import org.mifospay.core.model.domain.twofactor.DeliveryMethod import org.mifospay.core.network.FineractApiManager +import org.mifospay.core.network.model.twofactor.AccessToken +import org.mifospay.core.network.model.twofactor.DeliveryMethod class TwoFactorAuthRepositoryImpl( private val apiManager: FineractApiManager, diff --git a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt index e9edf0086..0a2541c25 100644 --- a/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt +++ b/core/data/src/commonMain/kotlin/org/mifospay/core/data/repositoryImp/UserRepositoryImpl.kt @@ -15,12 +15,13 @@ import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.withContext import org.mifospay.core.common.Result import org.mifospay.core.common.asResult +import org.mifospay.core.data.mapper.toEntity import org.mifospay.core.data.repository.UserRepository -import org.mifospay.core.model.domain.user.NewUser -import org.mifospay.core.model.entity.UserWithRole +import org.mifospay.core.model.user.NewUser import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.model.CommonResponse import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.UserWithRole class UserRepositoryImpl( private val apiManager: FineractApiManager, @@ -34,13 +35,13 @@ class UserRepositoryImpl( return apiManager.userApi.getUser().asResult().flowOn(ioDispatcher) } - override suspend fun createUser(newUser: NewUser): Result { + override suspend fun createUser(newUser: NewUser): Result { return try { val result = withContext(ioDispatcher) { - apiManager.userApi.createUser(newUser) + apiManager.userApi.createUser(newUser.toEntity()) } - Result.Success(result) + Result.Success(result.resourceId) } catch (e: Exception) { Result.Error(e) } @@ -50,7 +51,9 @@ class UserRepositoryImpl( userId: Int, updatedUser: NewUser, ): Flow> { - return apiManager.userApi.updateUser(userId, updatedUser).asResult().flowOn(ioDispatcher) + return apiManager.userApi + .updateUser(userId, updatedUser.toEntity()) + .asResult().flowOn(ioDispatcher) } override suspend fun deleteUser(userId: Int): Result { diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt index fb6b2803c..095f10293 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt @@ -12,12 +12,12 @@ package org.mifospay.core.datastore import org.mifospay.core.datastore.proto.ClientPreferences import org.mifospay.core.datastore.proto.RolePreferences import org.mifospay.core.datastore.proto.UserInfoPreferences -import org.mifospay.core.model.ClientInfo -import org.mifospay.core.model.RoleInfo -import org.mifospay.core.model.UserInfo +import org.mifospay.core.model.client.Client +import org.mifospay.core.model.user.RoleInfo +import org.mifospay.core.model.user.UserInfo -fun ClientPreferences.toClientInfo(): ClientInfo { - return ClientInfo( +fun ClientPreferences.toClientInfo(): Client { + return Client( name = name, image = image, externalId = externalId, @@ -27,7 +27,7 @@ fun ClientPreferences.toClientInfo(): ClientInfo { ) } -fun ClientInfo.toClientPreferences(): ClientPreferences { +fun Client.toClientPreferences(): ClientPreferences { return ClientPreferences( name = name, image = image, diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt index 501dbd040..7c4527b6e 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt @@ -23,8 +23,8 @@ import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi import org.mifospay.core.datastore.proto.ClientPreferences import org.mifospay.core.datastore.proto.UserInfoPreferences -import org.mifospay.core.model.ClientInfo -import org.mifospay.core.model.UserInfo +import org.mifospay.core.model.client.Client +import org.mifospay.core.model.user.UserInfo private const val USER_INFO_KEY = "userInfo" private const val CLIENT_INFO_KEY = "clientInfo" @@ -56,16 +56,17 @@ class UserPreferencesDataSource( ), ) - val token = _userInfo.map(UserInfoPreferences::toUserInfo).map { + val token = _userInfo.map { it.base64EncodedAuthenticationKey } val userInfo = _userInfo.map(UserInfoPreferences::toUserInfo) + val clientInfo = _clientInfo.map(ClientPreferences::toClientInfo) - suspend fun updateClientInfo(clientInfo: ClientInfo) { + suspend fun updateClientInfo(client: Client) { withContext(dispatcher) { - settings.putClientPreference(clientInfo.toClientPreferences()) - _clientInfo.value = clientInfo.toClientPreferences() + settings.putClientPreference(client.toClientPreferences()) + _clientInfo.value = client.toClientPreferences() } } @@ -76,6 +77,27 @@ class UserPreferencesDataSource( } } + suspend fun updateToken(token: String) { + withContext(dispatcher) { + settings.putUserInfoPreference( + UserInfoPreferences.DEFAULT.copy( + base64EncodedAuthenticationKey = token, + ), + ) + _userInfo.value = UserInfoPreferences.DEFAULT.copy( + base64EncodedAuthenticationKey = token, + ) + } + } + + fun updateAuthToken(token: String) { + settings.putString("authToken", token) + } + + fun getAuthToken(): String? { + return settings.getString("authToken", "").ifEmpty { null } + } + suspend fun clearInfo() { withContext(dispatcher) { settings.clear() diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepository.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepository.kt index 520001a82..8c7d072d8 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepository.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepository.kt @@ -12,19 +12,21 @@ package org.mifospay.core.datastore import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.common.Result -import org.mifospay.core.model.ClientInfo -import org.mifospay.core.model.UserInfo -import org.mifospay.core.model.domain.client.Client -import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.client.Client +import org.mifospay.core.model.user.UserInfo interface UserPreferencesRepository { val userInfo: Flow val token: StateFlow - val clientInfo: Flow + val client: StateFlow - suspend fun updateUserInfo(user: User): Result + val authToken: String? + + suspend fun updateToken(token: String): Result + + suspend fun updateUserInfo(user: UserInfo): Result suspend fun updateClientInfo(client: Client): Result diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepositoryImpl.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepositoryImpl.kt index a2c387553..1ffb73f55 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepositoryImpl.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesRepositoryImpl.kt @@ -17,11 +17,8 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.stateIn import org.mifospay.core.common.Result -import org.mifospay.core.datastore.utils.toUserInfo -import org.mifospay.core.model.ClientInfo -import org.mifospay.core.model.UserInfo -import org.mifospay.core.model.domain.client.Client -import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.client.Client +import org.mifospay.core.model.user.UserInfo class UserPreferencesRepositoryImpl( private val preferenceManager: UserPreferencesDataSource, @@ -35,17 +32,34 @@ class UserPreferencesRepositoryImpl( override val token: StateFlow get() = preferenceManager.token.stateIn( - unconfinedScope, + scope = unconfinedScope, initialValue = null, started = SharingStarted.Eagerly, ) - override val clientInfo: Flow - get() = preferenceManager.clientInfo.flowOn(ioDispatcher) + override val client: StateFlow + get() = preferenceManager.clientInfo.stateIn( + scope = unconfinedScope, + initialValue = null, + started = SharingStarted.Eagerly, + ) + + override val authToken: String? + get() = preferenceManager.getAuthToken() + + override suspend fun updateToken(token: String): Result { + return try { + val result = preferenceManager.updateAuthToken(token) + + Result.Success(result) + } catch (e: Exception) { + Result.Error(e) + } + } override suspend fun updateClientInfo(client: Client): Result { return try { - val result = preferenceManager.updateClientInfo(client.toUserInfo()) + val result = preferenceManager.updateClientInfo(client) Result.Success(result) } catch (e: Exception) { @@ -53,9 +67,9 @@ class UserPreferencesRepositoryImpl( } } - override suspend fun updateUserInfo(user: User): Result { + override suspend fun updateUserInfo(user: UserInfo): Result { return try { - val result = preferenceManager.updateUserInfo(user.toUserInfo()) + val result = preferenceManager.updateUserInfo(user) Result.Success(result) } catch (e: Exception) { diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/utils/UserMapper.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/utils/UserMapper.kt deleted file mode 100644 index 0c45d6589..000000000 --- a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/utils/UserMapper.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.datastore.utils - -import org.mifospay.core.model.ClientInfo -import org.mifospay.core.model.RoleInfo -import org.mifospay.core.model.UserInfo -import org.mifospay.core.model.domain.client.Client -import org.mifospay.core.model.domain.user.User -import org.mifospay.core.model.entity.Role - -fun User.toUserInfo() = UserInfo( - username = username, - userId = userId, - base64EncodedAuthenticationKey = base64EncodedAuthenticationKey, - authenticated = authenticated, - officeId = officeId, - officeName = officeName, - roles = roles.map { it.toRoleInfo() }, - permissions = permissions, - clients = clients, - shouldRenewPassword = shouldRenewPassword, - isTwoFactorAuthenticationRequired = isTwoFactorAuthenticationRequired, -) - -fun Role.toRoleInfo() = RoleInfo( - id = id ?: "", - name = name ?: "", - description = description ?: "", - disabled = disabled, -) - -fun Client.toUserInfo() = ClientInfo( - name = name ?: "", - image = image ?: "", - externalId = externalId ?: "", - clientId = clientId, - displayName = displayName ?: "", - mobileNo = mobileNo ?: "", -) diff --git a/core/designsystem/build.gradle.kts b/core/designsystem/build.gradle.kts index 868741ec2..14746ab93 100644 --- a/core/designsystem/build.gradle.kts +++ b/core/designsystem/build.gradle.kts @@ -48,21 +48,20 @@ kotlin { implementation(libs.coil.kt.compose) implementation(compose.runtime) implementation(compose.foundation) - implementation(compose.material) implementation(compose.material3) implementation(compose.materialIconsExtended) implementation(compose.ui) implementation(compose.uiUtil) implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) - implementation(libs.back.handler) + api(libs.back.handler) + api(libs.window.size) } } } compose.resources { publicResClass = true - packageOfResClass = "org.mifospay.core.designsystem.resources" generateResClass = always } diff --git a/core/designsystem/src/commonMain/composeResources/font/outfit_black.ttf b/core/designsystem/src/commonMain/composeResources/font/outfit_black.ttf new file mode 100644 index 0000000000000000000000000000000000000000..487752bb29df2226d3fef659ff657dd7c6718a90 GIT binary patch literal 55376 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 Yi_+;6pf5_VCmb$Dw_o(2@Xmez2QTNB>Hq)$ literal 0 HcmV?d00001 diff --git a/core/designsystem/src/commonMain/composeResources/font/outfit_extra_bold.ttf b/core/designsystem/src/commonMain/composeResources/font/outfit_extra_bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0977ed52aab468b0da0c644aa982d1568f615a76 GIT binary patch literal 55312 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 literal 0 HcmV?d00001 diff --git a/core/designsystem/src/commonMain/composeResources/font/outfit_light.ttf b/core/designsystem/src/commonMain/composeResources/font/outfit_light.ttf new file mode 100644 index 0000000000000000000000000000000000000000..c18b0c18584950500a759baffb24a466781dac6f GIT binary patch literal 54860 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 TrgDP)B0Cx#pU=o0?9;wAnN@ z)8d3!sZmbW7&a|rX^xP9k^zB1Sd-85e$TlNi)J&;`+h#Je7@)2=iGD8J&vMW6 zD5Ma=8^=kAAxVP9N5a#=_J^!{1w-EQCuS4;cAi>f%NCdvm=7 zN7n}zte8FUne#D1Eav{{C+5sbo!R-r$q`)N&Gpzhc=$ZpWD=j_`P^~N!p!AMt_*%y zh?b8FVO_8weMai0#H>FEVJU^43saXbl7EvH!nY-SU|Q9qQb7AVq_>+85qx|}#F2}zDRjRPG=Rl6$96UfCqoO^(mXouTgbi@r65x7wz z4!4&Wf;&=-$4wT~ac7D-xbs8??ozQHcZ1l1yIqh2aX=ixeNsG!`@Hxo?knOg+>_!I z?z@zw6nWxH+>7EeZlSn=TP6AN{+U8_upAkkM06BEQL zv6W{&CH^9gi@%GHsm9)Npb^F^Ht{?)}GcR>n7_S>lGJIml&62F3-Chb*XUq$u-V(pz99T zL#{_$|LxY)Ez&LCZJOHxx8-gd-FCY@>Gn^zuiUP=eedq--pRd(`vCWm?vvbCyB~Ic z-urw|MXM{)6|Qy-#|7;QfP73!gBbUOt0-e&_Rm&m5oCK5zMa?NiTqTvy;s}XqMl+Me}ye?`uA@`J(2pG_PpUwZ(`Q$t^at*xBN2i_cpIwCvn6 zrscYp`&$07<%=!PwY<=>xaD^(fAV$qjrC3N9pyX8cfRj7-vhqS_`dA>rteq2KlmAb zP5k`*g8UNwM)|Gq+vvC3?~LE4{w@6j{k!_d`49BJ*MGAA8~&g97qn{Ls(Y*ctroOe z-fBauw_3g5s;t$`)=sSlwBFwOmDbnWc(!@6?UVPcyXSBBd>$YIS_g~{csSs%0dEI< z*Dk!>@OInUz1Qxmz?i`Fz>R^&0zYXl+Ye|zrTvrbzi404VQ7a(Ivnay6x23oWzdeG z<3W`j-5q~{9S3xr-SI%j=R2P6_;v6-!IOehgI5RtKKNAdx!_B|rNPx9BE&PKbI9P3 z^&uxh@AG zTbF}fUg~1&I=<_+t{1ws?KY*`)^5kTz1Qu_ZYAArg>?>#4;vjeBWzXJb79BA&W4qT z4-S7Id|CL;@IQs03O^rS9$}5>8j%n&I^uzdjEKDvMswis2oL`OqH|b8u^jY#)vac81EbZvN%~>EuOTj zP63+&vI4#jY!TQxFd(o)U`Sx^z@)&;z`wK)Y~P{%zV?SYH0#hZwE4dc`Xj-U0!5_g zP1}80x=UXfAVXvq87^aGFPR{R%P}%V&Xn`yIm2H+>5TEEMbLuXc~VHgI-YbRuz8?= zU|ap9UX7l#yZr&jlj!+mJDyblzu})P-FDfQR~OK>%r;YquXCWA^84EF>n30O6&4oe z6do_^U)W3e6-+D`dojUkmgQ_b9w9FsWWKyAE9Fn}XK6EB4R@o3(ZT3s^fQu-!A6>) z#tr;478xszM~uz-9M{;XF!t(;jT~dMvAyA=43jATYO~lYc8FbKw|H7)i9e#cN5$X78{(MApMo+$v(ZL@2%*RD5v6H_2AU)?HdZs7n z>3>g;|153kInho0fp+zbh!!u19*iJj>8oPIOZ2RNMg6aecyUzp5w9_-cwG#lpG*>O zilOwBqr_=3TD&LjrC;(qZ7eesuKs`y-_iZ8@$aY-x? zSHwcGNL;07E)@@nYxMCe=(o>`N#Y~cNV>krH*qe{*xW&uEN_G?l^Z79gPsjxrYds zHy!7mB1C@bIBz05P?~0XyeQ?Bj`LOx>A~Q+QZhOWV^&Yf%se;nPjQ@EP?qDlj2+!k zm>I^oAukNAJgH05-vw24bey{qPg}>i8;WsvoV#--L?ZQ*N;{iRJuerTq$Cx;bbM#l zAIDMt3u%XS{-gM;+T{{_M{<0SI?8Nxe}mt6uFR#@CUQqzxW!_zZtv=zOmwjr#YOP9 zm{epCY7xGRQR-sO7jR6+_d%|YrZuVYo{DiXmSZqi(g+)f3ezdIOxji|VQ1lEhFHLH z2A|UiuTmUHiqkmGB2*yZ=jgEGus9?6Jent~u#IC@IcbQY8`qNc-70PB>4Dg-a7|#N zl->T^y40j%w^F%JmG^X9mCj{+R_O@DPdzt*R;A7}DU(3_|8GiY8L=)SRT-4Y5}l)! z#Hi9VlVdpfNvGcGLd_;zD&?C=n^gIq%~i9MGVlpU6Dv^dSbS#^Qq^I)PU$aWu8V0r zc6$tJ7)?Bx#HVr?MhvsKcZtq@#;=rOB)aHBC{>r~{4Jo~?#C~jejyxN6^9*d9Bbem zv6^*Z#!{D>KDXU*XF6_ARpYn^^87{Q-ORJ9i9k{i2~nIW6{`Acd`BR;&fuUxFg)YDOu&q2!d#ZubeRSN>vp9cCurjxGH`7)gUiju+tz zQZv)&U)3B_Fskw3pyt6&^jubYFjsmHcYGUPmv_1DnVPyFQyiEvW8osPQ@a~yE|~kE zSi^jFhFH!itt~xcW|~;AC~e6?F?+EJKW*{i$S9G#c*&y0Voav;AI|fYT~n@$p5?3c z2|nU9)vijRBvs1w(yps^o8VeVyOlqc2X&^7Dx8mHjU~x=(|C@*t;Td?yx}iDmM_zf zY?UGOrXBfH4^e9a2Cb>J_(oh8--gf{3QM@eipZc zP1u>UwUX1gyEXmvc6#ZZx}V-dkG+q+^#J3I7xZ}JReH&z^xCh}JLb^~ek8qRGG(h) zBowL_8BgEL{8uT}V%%hPKkj};S$UkBWh@zysQG%`C#$`Nuu`^`LE5jbCeS70 zEiZ+RM>67DN?OgD?P&H+q*T&Vse6>RRj&FIhQ5vZxbuoCWA&t_(x1>u)n>_e!`D~e z?Ic5mg;8j8e7wkSu>RzOPE235^5QL7|ERy$Mmd=}Q+24y$Dj15a8A0^_fsOOq@QdQ zN`+K;l8mnm@ds7~8sbxHTPhc7q^fdis#5j0DU7Ss+^3_C-%Py+1-wYT5L? zJ&dX=i(ZM4dUZ(3$9S>|ZQ*H8a?f)*Jx6%5N`ZQ|y7C;K)pO0VQr4miX$a8ymXt0&J7!-!u{jQ{t-*HFhB6xzKU{~NJl zti@SGG{$(B`&gl*J&!d~#8{5^NW*>}N;n?|ZjSRd@;eb=944Hi(;Z}rM9UET&fFbK zYo7b-gsW>#o5&|=P*|ckU&?u7x{5&KPVxxz5b3JpB{AIiExan)Sw0tmcVhgFxDJVX ze!&nCYBa)Wj0kWVECLX7fH9ac`ESH>M2Ah3--w_)(Q)(;otP(dG$w$*2>Nd@FZD47 z60R{FMWWG>wo=I0v%h;03_P@iYP%Gb4{+t)mGhVf?Q^*_49HA~e@v8IAazFJt zQOBp^{3WqG``2lyu326o%wX~BFb z@-QlxpWFfSBp<_I9(4!uZCYw0ERT^s8+G&F_>pv#l18v3k+vpx$FiTe-X*L9<3-ZZ z2R1`r6NVr`UeiQSlarLw>y*)6c!fMa#(mR8GdW2#Gj@vz)_~g?_lWjJYc!Y4@gC-g zN-s_D4-s8C50x`S8|;8T{0_Q9B(#HYhz8}?6QYdAMF%4bp3}!}^fB$^7|}tF76H6p zXm6PYmsCI^`ElU5#}R+~{2S1**@KUOY^O zPK_AX=)AFi-MJcJtFddSJSyU4h?p!}QO1hL;Q2=M=llaW4o!t8rH#~Uow`~O24jJw`v9`IMG#uzii%d86pvublo*u_l7ilO2g)<0cI{Vc|6ABeMz z+dh;Yj49RH(@j01>dKS5NpE^TMxu;o|Ec;^W?$jdXoT6bvKqr`o9srr~z zn+L^b^z3Tw=oMBhx>Kvv4LyH=Y$sx6pePpqRz0EWp>n#-4S4N7fdIhk%?7>RXTvp&>S#MY%=COj?lUejaR=x%? ztFcjD=~BJfxz6gLWMs5R_EB>u8804U{jVQ0_2J@2*Dc39Rk@ z4(+pgDN4l8ay)Bs6XgU(3zNheIZ>=*%(0gB!uwb!yq_8FWY!8FUhwq<2Zt&%+|x2e${YnVIbF52P= zb2h_D+FrSjm9_nh*AB2s*_3t409N;$SpDn3s^4i=4VwrnBhLPem(=Vfk+Hj{NDR z1L)aH&##V)K+&F+$bGCYJSP(5lgxPjAhYBj@-=ys_sp*|>$=2x>JHX$zhnjUD^>v2itc4mD6_2z(=%o*o#nD5ZEj@L zz$BN1g{d<#($icL(jQDun>F8k;LP;Q)EP5orDa-^W~6e3Lq>XPrgf113HNzM-++~;}=&;5?yT@8brp{QBIm3eS@ z-ySiRL1_;*89ir7+JmVXOBOCjU6ScC+KkmY)(k(kQTUix>p1PJBaM#gsg6;DdJVFU zZwM6~m0+Eqi=)Ye+ajLeNbUqPxy}5_xwA56 zEuOpBI`P4b)TOgL?rXScy-#~tC+pkXC)byXW&G6fFb5V`QyW*uAeU6flT#hlF{A!2 z>r9<+>nwe6pH+XsWtQWfS&a)fy1V;>^+BBGsCt+?&t)-<>Z6x6v*BuVRHAi> zSr1EYi*Sh}xl0`Nute9xG98h}vWB8|TUK8W%glOM(Qwha!mNjt`Zo8K^`+vHIxAc) zyI9SG$1EK{dwH0ptk1n?HN>Soyk^xsO@D0KP!*1Q_4D+(r=xBhAIxm%57r0G!+i6S zZjRmKOuvQZAx$4V%+hz9>q67#p8A#^v5pIwa~I4s^WjRxXit}PNB%O+FlLE2+)T0S z50=?eXTvj^C`QGk@WeVaed$jH#Ix?tx5KjEMR0m9sL^ z!!u`Fl?R8+W$Ke_=A4XK>a)x2^d%YkICrVOzIg6(b$v0mDNUWsn#*Ps6(DV{jzH@s zGO?HA80|QASI6kcxE{v9v8Go-r1px7GA~6%M|!0$Tr?|VacbI3oie9EOES`RnCPe& z^Pa>Qm(+}m^kqvHY5%BRaqjwahDwCPtEZdxnwh>V&EeC_^jR=#c3qfQ9bNZGZEYgE zN5;8nDa=S;INeQ)OPx8wBzmX{>>fEVob^A4pP4KC9G~mrOK{WG+vx5dW{4=q9np@E z(PmTb9^KPDRqZOuNMAH(7K2*GO74t+#yHkGz3y1+G*>iO`=oiPa*n*DcH0rQuF*=#9U6BO+N>P&-DZ(<6HFq~VNN`iY)y+ugP^ zR_exxEKsjPWf&I;b;($TTg=E;il>Zkaq|teqvSo~3EUmVIqk1P?lX4aUf_)?<4G^Z zmtGy9E%*X!qFy|`9_7zUPZRbeHMvQ8Z{GprtkcPgQ$!y=XZoMbSWAZ9qKPS)L(uXN>=E&Ds-qL zI@FP0hB92#6~je``l}B0SI*rSJ#1!7wUY5$8l%YRjG>Yn%GxaPySUQx0qRIv)w^?C z6|3_k<%5fl^CabC`9%5P;$!(l`4}UV53Wkf2<5{V2OnH~#NYAxzfaM3Dkhgm6_ZP( zire|1^1;Q&`JnQ#*pv@0J{FtuF=i8v7NB{I$|CRcN}>wUxTh zX`Q;yX`PD6d4Tf4#m9Mo^0DM9A6$Gaxyr}TVQ}#=bQngT>iN0KN2oA&s6rO2E3()) z%k`&qsHZu|v^R#Q8o9-FcT>Rg3eI55@?Y^L0)8`p=uKu|` z=|*~754i5u?l$di)b1MXF4t~`avdQTXrI}x)3|%GcE@Yi^tsn{DE^7sjn}T}W4f`f zXy3JqcFpsSt^uz8uFbUTsa>mfg>u=4rrc`nR%m}6-lbIgTyeR?M$z-y{aCwawflGN zo^m*B3l_eQRhI=9-idsDkN^i?zbBi1tFoTuGM z%C%lqF2_RaMQgrxKho|8+I?5MCzR_5bF9(%tJW8-&*6{$P1pK_wUD#D+BMHjce|B# zU|naW1z0n+o2FgUXHKK@>DDRMWa}914%cpycKd0!r*@;Y+fBLd)%sZ>+6`2$!>6^C z-q-4-U03azKBj9p|IF1!uJaGhmCo0li?w@MyI*SeQ|;zy_l$OPwQGhq-8Y?S1moELC)wsxm!cd~L_s4wU7s(x{)-+Gt&bsn$k z7nl0QrGB}p!;`1_x^TW%ojVWJZlZQgpZJDzuE(mnYjB+-oxAY4qjLb>j7p?>1M;MC z825-iKcdd1v$`r>)CdH(NV|+WSS!NLvr46`dW9Z)RH&<*t1*f0y@l?*rBovs+@0E0 zF-R4L6&Mw>)bT9SVV3DI%k)#0=`hQ5m}NSQVK5ewhVduusyGcD-q7I$O#hjv2 z#TyM3zoG7B45spUoZZk;{7a|vUpk%abyq$*OuqKd*D6RCit5PNPNQV7Rsyr9z zFpG5fbd?6ekY8NN5LcCRx=w$(4)dfApRS)0qUu7nviHLE)9LrqDfiR5S_aaH5Qd2I{pwHe~6AbMBf#n>mo$m%UZ3f z1@`c(@H&Pd%N)*wEULbOR0+r+T>_&l*_@BE%+;>CI!a$1rSBc3!(7*4uIn(@bqv>a znCm*sbsZ+za)x`8d7Gi!N3^SAPS$rN>${RI?AOLeJzbAXScy|9Ox7{<(qYtYM=5)0 zpHS@+s>3s$#y?d1hiLy0?H{N8L$v=6OB!Kz=rrumY1pAtzC)*BhrVlvy36=bl|OHx zlwxPRhZ>PsAm^xRf(4<%z3i4eQli zjNdQet~FgFhx1p>drjAoe(ojxs+4x$}G3tJBSM?XJ}KuGIc3bzbN%c-BgNb&4*BDf(Gc^s}bur%ch|r|48o(a$=p@0wz| z+-tCVLGA2kdc)eF2P=dfS)Ein``fd#CXSVCwf-BWcX|zAPB5J{U$wJ8nSC`GthFu` z>-em8_NVJN!0b?Af8%QXMti+bJNvh>g8dfzG*0sON4>NEDWP`u|5>P&!(*b5U5Ib7 z7vu(`f3?5=9J@b$X6J=keg0hU@BdQo@4ujTr>rBTD(9Jy26JF~Bb2|&ol@r*ayA^2 z$Yno{C-9T3s4G|9D@BI32A8y3tlfO=z9-dAiXHm=Dedml?giY&bHD9+PXIewoZm!` zhEd3xu5dbG*(_S<{SrK+@jv?w-aFh>KKA0q{*BM=Kh=G*f1}Rqm+C$@9PL&3s~$tx z&p^4IoY}9anC*G?3j0NlmG;l=zqh|-f60E({+NF5Mtp1aJ=|UQ&wjP;?3YKovJw2V z|DfG!{o%hj_8)av^6B_zRcSKM?H{S5{j^Gj{gO^)qm<}tI!`(@J%IhP_N&w`<>kn6 z33(%jcmHR9>F)mAz0h82e}<<&Ly0i&w!dNj#C}+XCcYQ#N)?XsQD^4AMs-nE@3)$8 z2kal&v+TSnvj1Rz&;FVHQO-UQE$mNI6IgD03Do7qpL3OZGq2q_%VV8i*k6DzsipJw z3>7z}?61<*_@BL8eQHpE{i6MZDnO3Z)u zefro8ecth}KD~|n8~n)cEtKDeR-yVfFVyYH8<2Lq%~1RMT9c!pTvhfVSlfqa>_Zy% zV=*l?o_94{Xn|^f_#knZeb1wLo0iMo$~^vNijR1UFpK>v->@6`TkJrF_<^@uXj3RYvPt#DYs&`rjd)`NIK9ZEG9ad^h<394{ zs`KWl^VWpCEy3UXZqp;Y<8{FfZspnA^m^5Pa_gq8p(M|Tx%wxpp$j>GoprBl-r`8! zl9w*_?E# zx#=2q(lyK*WcmRYN=TKFDv>6-M4WYrxa$(}phOnquXf2&bNm^)XYiyX_7kJ3d8zX+ z$^S{Ns{E_HZF!XJNBp_!oLhCyo9lck5wMR-tAHJPsKAvRy5ZwaK3#d=>cP1ux^Q*m zdAJqUHPYK(tB{sMh}YMI;oanE=~uX$ea{289{ zZo^$hTF+ZQwyv};vQE}?vvzCyyoHi7zBE2H^4KH#lyx$-9*GvP@@T9*N7W|PxFeJ| zqn&Aw?P$f_(PU5BV`u#hls@$5WB5KtGK%ZRKHYS_{h;(Vo));2Z}}-3lZ=fyz^-Jq z({2ts>W&cZPyEe8Z}0Ms`wV|8wBA-~y*-T5F7p0aeJ5oN@0m-)I$Byaaj89VJGAz8 zY3=RS+S{Wo&|dbj`SWHqOooZ4wCbMb9eRv-miOmz;yHFU#xo=A$I9>Xya!Jdf8yIN zN#X^*Gc%a|p~`N(sMYwgexLoSZih$ZG&xQDjd#_v#p}9F9%pA{Q~Qt7$6g^@a`d%- zE&c32OMm)UC)wP70pDVLEAXj6%gwdRXWmXr`V0ds-~`TK1s8AyH*g0J@PtVF$6^L| z&SVTR*Ip>*!F*T%3n2~OCe{~-mGy0K0%x#-3%G(CxPu3HLKFHuFZ*%P6uiL)nn82? zTL9@7zTgM`&6ZwSLg;|5DpO#1<}wQdO!@s zLLBsjUeFu*Ks@w?e$b!z2S5TO!azuZK`x9hZ*)9Y9g1KI6+OkNKL#*O}t1=yhu&FDAE~0EGE88 zSOQD!m0}qzhZV3A9)?x08rHyCSO@E218js%uohCQ$s_QB(@ zpIveXI39#2;1FcPG01`A@CLjIZ@~#T38&y4I0JdaaSlF$f7;8$$M6Y!3ZFqfd=BT~ z3-}T)uv_n<{emdu_%&RCA}EG$i1Rvp3uRCa74RKYLKWPATVS()DkT_T0Vi+H^j{t{(>iP^EVe~ESY66^3K)`9U0SiuEc!42HO13bZtkwR1O1|Mh!?V$q%K}U$R zzt6a%i5LJ0kO%`I2?oJn7y?6K1dOp?p~W4g#T})^9i=6mpe21yEu5w$y+liTiI(&d zE$Jm%(o3|YuW3m~X-P+ENk{2NyxG0v&9`j4=_kCIX?n9i$(tU+n>npFeS|kT^`@8b zrjPJubmPrl8}*GpZ{DAI(*t=k0`z7C=*^xSZ+atdu>*F(F4zrwU@z>0$6-IC`~w^h z!V_=^)V}FskOSCGzJus3-h{W{1e}CZ@DAj0|2g;wE?{vAn0*v-{2H!65fnoS^T}@r ze;vMsGAM@%_zo(e3U0tHu-VILA?37?a#~0^Eu@?lQZBviXX%rQWi$H+^ge%MDcA;Sd3l z)OZxfXy^_-AO>O~4thc_=nZ`!9{NH*=+83-KmsJfKuCf?Fc^lwP#8wo;V^>pksKL= z^KDHp<`rJp?L6#u9(FqqyPb#K&ckl!VYl~1!fS98{syl@ zHrJ0q4jhL!;7xc7PQXbx1#c5J7vACgU5=;W@9-Wdi^;kKDy=}J71;VxY<(%Vz7$(u zimflj)|X=IOR@E(*!ogzeJN_bg1xzdny;YdE2#MjYQBP+ub}2)?0p{gJ`a1JhrQ3k z-sfTO^RV}M*!w)}eIE8cPy9d{YT+jQ2tUEU;b*wTbsJ+S2?kie37o-dFQqRir7tLz zZtVPbhY9vPW=&qqRHeNL#TTLYA{1YQ;)_sx5sK$~!Qck&-~pcCWxs~nuc7v9sQnsh zzlLhBq1tPx_8O|ah9V14)-{xM4P{+JS=Uh3HI#J?WnDvA*HG3qlywb7UBlKrjjekc zTlX}hi*iO6<%}-M8C{e!x+rIKQO@Y1oY6%&qlc6Tlh4#@M&z})2Oosb=IKH8q`^XI%`m84eG2xoi(Vl26fh;&KlHNgF0(aXASDC zL7g?Ivj%n6pw1f9S%W%jP-hM5tU;YMsIvxj)}YQB)LDZ%Yfxql%B(?|H7K)&{wxv& z)}X)|6j*}-YfxYf3amkaH7KwK1=gUz8kARqB5F`X4T`8i5j7~H21V4Mh#C}8gCc5B zL=ClGLrvCDkICq0B1{5v1YAMMT%u(7rZg;sG+4~_OjrU(nE84T`ZZmSd~X4j7BChl z!8X3kc%aZRGC$2&AW!zD5AsJX#i*qiwG^Y4V$@QMT8dFiF={DBEybvXaRzuoBqY;E zPlQP@kI(aA0W5?xSd4!rECCOmU5j1*0lQpF8p=sS5%#%&G0Ar_!v2Pggt3fS#xXu| zA#??yYYAOWs3KBY&D9dFmN1`g$~|UW-x8OaY5a>&Rm63jkQKytg7{9ze)bR9qw6Qf zK`JfVO1#&IvsypdpE1-}Mn>c8|6oNz&0iRib00Y++y$QSJ+YU`7WNxl{U*24za2%BItY=Nz?4IYE-umg6&F4zrwU@z>0$6-H~=>W%r@B|!!Y&Zrv za2(!%H{mTf0Vm-UyaRdMe-1u^Z}@y2zJ)R*24za2%BItY=Nz?4IYE-umg6&F4zrw zU@z>0$Ke1RgeTw-WWzDYf#dK7ya{i?2{;L-;2rn|uEV!b2IWuz-$5l*!40^DnkI1M z8;i_am%(ya0W0BQSOu$L4XlNAupTzRM%VXoA4H#fRk_v-hm5H2w#I*yDx%b_y(@Sw@?PzH7;ME%~lR@73tN8ogJe_iFTBjozzScWH)o_=a+!94L{il*m;|bu2LdbDUqv`$W=<@DkXANJVGiqaNG!+U^8rit*{LqgYB>bcET>$4SQfO z?1RT)KlO2d<3V@=4#8pKev#iro>2ooKrP&aAK@qXH~b8@2x~*V5)80_6F7q# zwdf9YJxmmRLp1cG2O4OT0kxu0Mh)Dc2Ch;AWz;|!HBd$klu-j^lztVZUq$IxQTkPseifx(Md?>j`c;%Z z-<*eAV52vcV1Najz#01Ko>BMxlw1|FlBGOx87zktuo51IRj?Y?z*<-b>tO?IgiWv+ zw!l`{2I~FdcGv+sVHfO%J+K${!Q*fM4#E>~2%bcL*&L5S4jhL!;7xc7PQXbx1@FKa zv~z*dyND(W_*}^O*Kh@jpcqPs^Bb;Rhi{<_%Ao?jgG#7^8}L2)zJ<0T7$q_CMqkB@ zAL>f!25&pg5b7ea7Eli=X6~RYuPP<-=HLwP> zz6F$T0p(jj`4&*V1(a_A6{vEcb0^3u8?Ww@_ zRA755uss#no(gPFCAOy$+f#|{sl@hFVtXpFJ!);QfO;yRo(ia^0_v%NdMcov3aF<7 z>ZyQwD!}$sVtdpYUjeqK65CUW?Wx4}s5QT0l;5yg@lT%lF?<4_!e@{VpTl|h0=@*b zs&SFkivs3^cVF31V}=6iyns3{pw0`Z^8)I;fI2Ur&I_pX0_wbg8oZ2+s=!87V52Ir zQI*)JN^DdmHmVXERf&yKYlH=~rn|3zSW$rsxPlw&gYFQ)N=PKc+fSj8k9hmUdncHH zu9Au8FzZ_uHAX-q-=dLk)msb3+RI=$tbmp9Fsy>rum;w`I#>@IU?XgT&9DWw!Zvse zw!;qC3A{}SrIg!(U`{!6I;66(K%`Y)mW zOQ`>nM)hCvEA@XF%Xb;ecbRp7-&+3#)PDi>e~J1ppv@Q1<_l=^1+@7B+MlZb66(K% z`Y)mWOQ`=6>c52gFQNWRsQ(h`zl8d~{$J|7gnGY>6}^lVy^IyTj1|3%6}`-Qz}@P- zl6tR{v5dC++0RhlC3+oJ?G3z$#ZYUqJ$R$4`rSG!U&8tKtSQ9u-O%1>BwkzSJihhY zlkZE$${~!|4RU)+*&6JOd0!RztmK`NH#)k=&V&NyW9pL!b!wws*(g^V=0 z6KsYpuobq!W3U}|z)si&yI~LPg?;ci>}Q?$0LO#y1RR2FI0iXz9NvI8;Vn1;C*c&l z19{wk4nBeljg&eKrF;TPv`}`p%27EU+4$@dBy-pfJ7Jw zNiYZo!w?t>!w5SZMsPlo<0!ZnM#C81c_j0mbs|iH`_TJjxF4p#1CRn!VH&9Ql<6>o z8k>nW=JJ+I)!KYm01F`v(h0Me_%dM$ETuM=!E#suE8$^S1*>5Vtc7*39v)8K^Jz&}8;v+h8F7>{;wWXrQOby;lo3ZMBaTwqbUtnREN%KMZTc*2`YdhwEN%KM zJx?JcjzUHpg^V~#8F7@-B2UW^97n+fdp@o6rhI^r=rlM?d|9-(LRwrQEv}FjS4fL1 zq~#RSatdiVg|wVPTE$+}U5L61QFkHgE=1jhsJjq#7ozS$)Ln?W3sH3;DlS09S5Wa4 zRD1<>7CY2gj5>e0ZfdIY3hKOqIjEf9F)gzfx;jHgJd~G*^72p~dt$*< z-p45K-Ct4O8I+fU@^VmK4$8|xc{wOA2j%6Uyd0F5gYt4v-U-G!xhO6d#pR;7Tojj! z;&M@3E{e-RahFisB@}lF#a%*imr&d#6qkqM_!Ts8v*)6?T*kN`FxL4%MllwO2G!HV zqsV^t&rx6w3M@u_SNVkk$@>EXEZ_vrUpsQq``CER>ps zQnOHM7D~-Vso5ws8>MEW)NGWRjZ(8w>Jun63#DeE)GU;mg;KLnY8Fb(LaA9OH4CL? zqttAanuSucQEE0y%|@x&D3$%#Jhx#dMlMRtMX9+cH5aAkqSRcJnu}6%QEDzq%|)rX z*vPXe^$C=ki;c|1M)Iq;Pz)vZV<psQnOHM7D~-RsaYsB3#DeE)TdBt zHcHJ#so5ws8>MEW)NGWRjZ(8v>aXqC$VI8SC^Z+QW~0<>l=>Ptkc^Lcj>Z|7UR_M<8m zJ)XXf)~}=W>uCKtTEC9gucP(rX#F}`zmC?gqxI`({W|ZQEbM!*=yALcM>Q{O4;>%~ z)bGSbl7jvm)$htCKq3r;Bp3vPVF;+-sv7}g=);rI^hB5h_c7y`4EMtncmULQlBdEn zNCowM>KUvE%;Y`TTxPuUc;|fg!x~r%>tH=> zfQ_&THp3R!3ftf@*bX~jC+vdVum|?SK6o4sz(IHd4nZ~?gB&;xZ@`=I7My^Sa0=c5 zb7ixd8mvN}zg*e;hA`LRTPTBasDSUF5~|<^++y!tKYl-G0_X2z+5Wekb>_&o6zf)s zbt}cXm15mW{~t!arC7yMtYRrvvGg~Ne2e}cM!uz3+)^wqzvl%5AqfV-U>E{Jp<(1( zdY6&!zfk8n)Oikdo@3-&$;h{ok#8j<-%3Wlm5h8V8TnQ+@~vd#Tgk|`5_Nv*u-F$+ z=liJhebo6r>U&>|FCghGo@Xb}o6LZL+{vsy4vi%@tG3NJ$8MJT)og%_dlA{1VP!i!LN z5!UtYE5}wwlP=&2{p^3QA90RlEo2-_;N7trb*d4k+My-b!J~fPfd8@v)HlD>H|6}H z6|@HR&A+yw{*M;*P0Dr<2*IGf1Eqf9i|<*oV@I%KN3dgu|5*q4Uvk*3BiOAY*sUX2 zRT1pg;eX8m^-Z##&9V2w8t;)M^ZHS9EJs`~aEcz`6tm--*n^wQgl{qvzR67ZCNtri%!F?;6TZnz_$D*q zo6Ll7G84Wj0-zlPLNJ6vXXpZ5p&NujI7C1seOMI7Xy^_-AO>O~4thc_=nZ`!9{NH* z7zV>(B#eT4VKgMOf;kZ;!3@^H=i2{8$rVv@MU-3-C09hr712hoPn3W4#7n5;CB_OL&~DUvupjHeezcbo z+RIJWgZ=1#BN^q7(R*?(IP~`gCB|DqT1)|ZRN@KUPc)J2{N$}yHTwxAyM7F?fD<@_ z65WBS+B45j1iH zjg+C0GVFL6cDxKbUWOen!;Y6>$IGzeW!UjD?06Y=ybL>Dh8-`%j+bG_%dq2R*zq## zco}xQ3_D(i9WTR$IGzeW!UjDbW(;L zFT;+PVaLm`<7L?KGVFL6cDxKbUWOen!-ijA1buPT5;vB8w9IfIUt>PT5;vB8w9IfIUt>PT5;vB6a zk5-XKtH`5O$H-(^|EtV;R-no ze>HMZ`}IGj*44LP)VrCRSl;jSyh^>7SNlrTZeYpUmjM=V0%x#-3%G(CxPu3H0>5p} zOi%rim6aXt>h~S3%=E0x^sLPEtjzSRJoh3qJu5RkE8{0CGd(LaJu5RkD>FSSGd(La zJu5RkD>FSSX}p0l?_7T?C*36|?lTnk8H)Q1#eIh2K0|HwYj5;P=joHqGivdmB&x6% zRoIIw*o!Na0y`+k;c0SsnjD@cho{NmX>xd)9G)hJr^(@Ia(J2?o+gKhE=c{*1%d=2kT)2Y=lj) z8MeSy*anZmcGv+sVHfO%J+K${!Q*fM4#E>~2(sZADycu|OWG~FX!-uI zFz)9!3@q%_@E|s^*r&ZuaC@KjesO*-&HY?Le`mPc#>;zcM>}@D+}XKvX=mfut>G#1 zr)T&mn{@exX@;TZAI4!~QE~9ow%z%OjqaAXnD#B($+k(d&FpW2z73KK)t$zOTiJgY zJC^^$L*HY0-x|XEU4D>8uH$>FU)B2`s`uZ-uhxD=`poce>t`@OYWx(7pG#0^oL}f| zPmAfib@0|sPxo!~R7;1>hYxq&EbE{0cKuT}sHfEXuc-H5&G%Cp{2Rir<@*{9{xj>t zZ{>R}+TR{woHCBp`)`+g6Td$Gb@l$6iDzxS|HJkETiAQ2elLw&Tb`n1`ED{ZLmy^@ zt#sa72I=zkqm0}8boa4vlxBI`|NecboZD7DWE-6lD974fmGg~b$+w=W89TNnnV%ZD zHC*-{J647y^Yae;E^a^)z&|xH zZc>bTw)(}02>TDlE+ZE^E(Uc7H)4A9GrC9n`nmAj4qisf76E*Wjq|fw<&F{SruOJD zb?u0;t0EKHPwg8wB`G*KX-ZtewDt*+>)qp~KQes8BdKvcBNKwVgbtnFyZ7{=pnu2kfI4#79!p0$@=Bmc;8nds= zv~7R%ZqdsvqirAj+B0;zEpO{|2mPm%OGhc+H3u?SHRH}t^}X9;EN`2oN)f{E-UZH-S9sX~V2Qyx-E~be!j=9dh z-S&hB9ICthNph;ANa~-cY?k@N4Sb(l*(Nh3N@=G5YJQphZvJcdeVGRThIrQU8w3sh z%J!M@Y-L?s`=jtAZTn3B?Q$kLw&>?JsV_mD%R0NIayHL)Kt8N;Bcmv}2xXs4TX6wf z!OGSz+N#ysvW2g&u4KRVR6q+X#`a-rr^d!kTR(E#_K1Y`3kHl_l90G)=&<>{d)e~k z_z4G98yzuX{q)!Y@d=ULla}8*dU;aMg`+zsd#!j@^-8K0Ua+X%2kS&FZQ?tFDo+u% zmkrWU@4rpbZtBCUvNXf5;TP&vZ>7q3(d~IvhSSuEoStIqAP=g%>iov5ygKnb{y*pX zd+3X`in*)qPUFO_eJOP}y9^(G>&M%okm{-8RULya-LWa^x~g$<)xyYe3K5a%9Beo;t(npAi9YR9sn6w6n0tI{;fB!v+&3gp}#kNa{o9Z6Xsc+kWfIeO2 z6Xt^U7Dkt!Li#7JGhcH1*@;!4|2x$4&W6n^4lg{jLqt(v-)8W-Hs*^f*sOOYs>*(#=}$I8U4~jFT>*Ja=qjTlt7B*;BsMq%A^Qcq_-~wffcvYaTR4)6YBdovHKP%aQLdsD0Ct zX3{g5v9iW}d%X45u5tW3>#g1G&#CVM)bl7eQcJm+&)dc?VKt;fjjc@oEy5h5jm1ti z3ePW1e5~tK*?@1cIn8gkI%a1Zs(Z=e`I>xnq)cNVG-UT#R(!1x$!eH7D{!8A% z#zz0wJQ{y(@sFT4fjTnNqWTOo?OXZZDwMqpCr{TYa|?Y5s9{hW_SSP%1G~wng=RSP4?>G)b#L zjghOm{jbAxfWkK-JJc1e2noDA(76x28L+D*6oXhSSr^@49;@mZ^9Z~ja=ZJEb8KZ@A z{HMiFm!q!XJ4?_Rvl4t~+uC(U-SSJ*Z}pW)wxze#@h=K2R1WHEdn@UVmgcZ$_fb;n z|7m74t;>q}PQxt68e}0??JaR~&xyW?34KrICQgrunVx7*k^Ivm}hJQ63 zciKa8i=xf+Y!e@lF3F1W5Bz`Gx#|t!p!)tZrboDQOpn;u`k9!rZqAIUWb?6^VFTJH z_wP5NW8a}e@}!h0qL#}C72t$Td00pSs`5uuUoTHVuia7>?ZVKH3? zbnF<_EvRcitAOxfaZ~1~64FoBB{arSLX0HoMNR*=Nm2A~N>lyB>^G#Xi=)VXOB(B@ zX=Yj@R4GwtU54_ z)7TZ;`_y4wI`$cy)VA;a(UV7Sk_SI-b)tvuP#gb;f;tBc=+d=+2WRJ4H}@VX{Ss&O zGV+`IHy_~U)x@pykgm4&^6C(VK$JJ{jE!-$12yLmsVH9CDEAcGF(bx!=2nU^O^rw` zW;m3q!ZCuV3t6X8Y2NWf-Aaq&&c<_)0QzK}L@5%X9yficH8>o5uYQ}8-X9Hy#E^!% zvAjBEB%eHL#o(0i(NWz;g-sp2+$DsD`-ZewEQ>$c%oL=>gt(Tcjyp{Rf8 zzR>hn<9O456ThUU`bg7XjciT-4Y&ELKGpPJ&2N?5E&N)3S48z!W;_?Q&1DpQ_dL}1 zqqpZJJC=TvzVohmvbZ=pOQkjQDXO}Q!!K3OO;-||90ubnsQzEOZEPn`2`g9 zOT_J{?>&^Zs%_c5c~JB2QpVV>&n^kRHp^Cu5zA&>POr@bQthu3Qq{Iahg6{%FLviQ z1dCE$Z}VExYpq{@;L5P%`9(Ta?n=4)bx!nZWvYb{ExBng{VX!Hd3Pi9qK~a&(U<%e zVYeQYO$HQ6+5h}Jen)J%?Q`1_`A|>W`*L(oseZ4JS~FHVV&cDYGD}5Se;IE3ZsDb< zf6cd*k4(YjKWTeK{?0bjc2!QYy`b`_@6>sm=g?fPPP6H+(ro%~;BA1)yXmj;X!@__ zxBVLY8^W*Uw+&Sund=z$kTQ!o>R!ea#U&=r97wo?%B^X(>)$1)f=@_j znM{)%;Hy%n@7Aefs;7IQ1H|g&@KroZ}z9yavH48t*097j~R!TBM$yw!UhW@edx8-SS!@* zvV2>blVoj>X3NNdvB5n9gQF(I#*UA$B~Px4^VUVWWHO>OLlH!u>;{ zhIQ^TEFyAPml5kS7iZdnRUPZ+8fBFEQb!#h(tVTZf6C!+m7AErIXOZXJ5m|`Thm#m zi2t14x@D;Unr@@GVP(opXK{TxH;iq_RaU+4>QN28bzxoPT1P)@#_?!<=&gFr*^xP2 zXIbL#b>V-KV{M|Y#4NJje>1-|RqxNQDVil|m0J=WzLrh0#3@wpKhaUbR$b1_z^U&J z##u_zPqimy^+RLy>b36BgHg7NU(2|$i2?qOrP@9Hr+EK${bg1d3n_J_rp>qc}L78xpCHaVZ_*efx)m4er!wa9Buxzdr4!x+gv~h(~k|jc?ti z^U#QhpR)|s{h;jEpFg;6rTp&cFe>U- z$%E_>D!0^&N{>}Owo=uLnM$P)GnH%fk^R1^9qM`stg9DCI(;4O@V18N97Id>=`KAI z=k)D6Cov{D#$xG_92zz-By?a{SW;-{AnAYqFWVx`FluO*hQ=sos4-F}o~>3jTT(*I zTpQJmuU{x#s8)u#YEU;n^!2rb2K&i2NedI>XZ8(>YVXtlr-Dv}`8tv6b9EC2_%kNu36F?K-H_|0(WE0OP94{pZ|iGbPQ^ zWHOl~li8O$Gnvf3Br}s_lF8DfNz*oIk|yciQYfYit(L8{mM3NN0kZg1{!;Ma)2GOD z1I5SU^4uS_vIvR@3aBh9ihxRP-|sv3&XT22{cnXNbI;s+&Ue1^o$q|#@B7ZV?jHR1 zusb_1?NsFZLE-yA_^#sPcZ~glYhmKddT@r`eD0upz)tc=$>N%;rxxW;8S9tseHR`H z-u3Hee>hiZEy5^Se&2%pI_L6;LQB?|RYOrHWxfE-<8o~3yRfTsZx7kAYH2UqYPGfd z{Jk#sK+v77OWL+W<@79_E1 zYp0Bb6nJrFTJo~}ZZu_;_3|BQntCK^lF72P>Ge@h@amrD<~FD%ut%W-aA zp*&XyX~;uG<)k6yTCPgTcegT(gHj3&iSt}>?mD5V?5o0K&~3;(JwU!lkt@gpj92>C z#y#o!RJldp6gbJw6>PC#f1@E;Q5p8lKEtkFht&r8_t3x$B~BtUGh9V6%VDH;!x-NF4%oo zYUw^V`BeK%clQMyzTw#A(P7_uSC8M1m9?k2xmV=+1GEXWKHkc?Ew7K9Vs*JfaUYjY z1yw$Knzb4Y=NM$jZll?i08Dze-MFmXvUEkM&h9ccxX&r?`g?jM+5;BhyW znd>gg_mZTCdP#C}6PJ77$Ltm8f@+HYZ9Rhp^`Y*#1Ey1OEFK>T!gN|-FnxbEj#0)x zUKhm@k&#T13hfzc?C+mfC07|wELt(-FoCK+E!>SZ;DZ1eu2OS$LKwl?>|}Gj#Zr$S z_A|*TB(3#zR%>0o73(8P@~$-^!JB7E2wta>~@0s#@W63Kg?|iuO9y%kvCEUJ}*)ui(&% zMQWZ?+q_!H4j|ci5waskO~eG!JG53Z6t$-`KvTN`KRBURz;=P1QHPNrwcd< zoy;M|thwel9{HM@J@=&SX*P*UL9Z4>|2wN9?4xNhH>2@om9B_3flfh zXJULjB;h?8T)v4vuWrUUa@f@YP7~$~^?LB>kv}n1Ku#jRKjhdZroiPJEFj(U~`@3MM!hrVB0s=D{ z_H%E~-mcDlJ-z$8#$o38S9&}v{bZnn7rYHV5?@wE;`-b=ENHp@pmMD7D+_m%mX=Eo zXA7mYmdkY@fL+| z>g(aLDSU(9_F?diJhoO)ND{ZG$A%b&PNT2V{%?6~4+wW2hG+f_Rz1gM%e4+|bmrFK zFP>%VWX3G!FFv5YQM!4N=E*B+{X5VJZIz5ply?E0*xi{}AIYH;@QKLXcmTH8nZ0}o zr#c-xaCml8P7B`*uB*waB+Xg{oTgw-c1_wwhaJiKRHdUXoZ&jNvU2J@^~Sap6&V^$ z(jGVSne+`lV~+OGSh{&B&i_QM^^4V;Q)YAPzu$9p&(%oJn%54yxqwGtEy26xNsGzt z(OSZgng0gfNdE$@4p@ovW^B~IL~)+vlr;*JEP<#$D*kZ6Aej=+1Suv)M`!9CV=&#m~3b?)YUaqYb|kKb~W{$x66C~ZMpXd zKnO}HPU@!>MV1$BlQVE3R#nFWw>q6k`>-i)vxH3@(b?C9vX-e>bS#$HP-$Np8*gnMY#~sb zEMW#<4>ARNfh3hOlCGUR$+`(MWDvfPwXEo9v#8y)_#a2kKv~P+L zA9*cY3QqDij}iuzFDD;{%7O6(3Z=Ae$fZ{lmC_m`mmcQplw5P+-Xq&+cFCouL3JJ3 zo{LhRUsQzjbfE`#=2ntLdLsA=Ylz$etsycsSBWy^t;8**l>E^woCd5ILx2sod2o9`Ik87<#OViTz-XO>&WHAWx4z?&JCfS z&AL;j=>qPcz-Um5`5fCDJz1E8Pnt)-=F1fktYct2IzAJgZ75U(2qF0>%qZNPq zYK4UNDRh1Nxy=0}wJT1yvOg*{sKymOP`dUrkL>t}<&GWCJa}DratZr|bTvC9S-;85 z)87O={3+hAXO(^(BZe^5Lda09T*9*i>2eCkaZmS;}FS)hLr-=sOWa|AK@qMWX@s&}l=dlJ@=2(r$PGS0mfR%ONKxfzfzMk!7 z>FF3NXVppI_CRn$P1(9u+g8QWO2z5hvQD$zI}ix2@)#PBFF`cG#=^U(3Dt+ZLCYLf zU4y?e2KziLc?+$8MYikWROA@L-i4aB98x74TZ>XvtnFp$NJ@yhVx;PM?lH@y1*ED_ zIv1%zPx3u1Myj3{NHfT_6p$+LK7aRh&>MI!7k19UixBF8-nC)B4_^xjZ$ZL1@<9O} z$}yKYuwIE>l-Cmk-IXk71#HBW)BmAud$O*sue`jwHQkNqP<%WRok%1mBH{J%l8!Ac ziEV9`U}Iy@VhI@x;ky!h6Q}%Z;_i5Du*_WRi?&9rQFCZK4ty$v)Q)w5P;h;sWh}_9 zZ48>tL4$#QH{RE>kH_A-u#4j{*o54Z?olI6AfcyJ8g|p^zowp9@`AKyvVyTUlTRj} z_ZR!pcm|w!ol8c}mnKKH0@4ZFJCE4el>`G?MhQ~o>#6)99-B_LZ_qX9CfiAWx5X0a z$#guPW_9h;kz@q_Pq$0IVdd@J*$(MXth^&je`!U-{Qe2r(H7c4#4X=IJhri;14~+4 zYim2J>ew8QZRwDH&q`AR11aeZNH%|-OEzICB-!NE2uk_$sF!lv70j`?=A1AWxA2#o zXS$%JBEK|_l^GO+V{(g}V|hx*d!Taor4CL9B#QdC0+=Puusr(5y;A2Qgt69Q_(giO zhy(Nd(FIh>GhKaYk+<>^_f}wyKm&XR)(FR73oCFA5GUwfZ0hq)dd#)z^mTT$ z)Y%sm%4XjX#TAtalZo9pI*JzLn%+h~CC>39}2_o{tJ&85m8pth9HrU@#CmDZKx+VuVyrvpJX!$(a+27{V zuA4)Y<(a31ZJNtq%LXXUbk+%(Pzw9N{L3l|N`!>@!^I%O|BU%@q}5FJM-^#iG|+XaC5Dwu1Om zVJhNJf1W=(@z$c-@V?_O{)3#NAo8MIqMQk55dch_qW?I*m1rJ$OcYJayyySh zz?RNKfXH*{f`)zu<4Eyw6X|E#Z8I$y?#W!7C-T2*e5%t&~26imIkKo$}Mt7v!}> z-m~`p# zoA)eV-p6imXPcV3#h7QGnCJ?)oPnUj8B7oL_4G;4l3iBKu4lbysgh@F7uw0KJNbq_ z+tde;-skJ_xO;t$X1^Uj?0R>Pw<+ruyPLc{?rgy6^amWy0M$#o5Vi^r^VRKL=P4Ul z{rk)oYauYv|6 za*{>vDJhn14s4r~jvPxQG$Ixm&70kOU71DGk8l0KzEh90Pp&JCgfffd8?#-lzhSGJ7{lKVpw~gd^(Ne}dQ~8*oPxIP|vgb#ORD=X2#OvV@*?Qx{}M z22U5pw-D~g&m5-hIX~&>4XE8M#^_WsH5oM~+(NL&nLNMO+u?L}cs(?EJ>g6y9Li)$ zqtnU2>O`4gc_{0OuL}g$#a-FZazj~Sbs#w%U2jdgoJp%S>2xKnY@j_9Y-V_K2i)tQ~? z%v_M2o|0Z*2~UsLM@;oKb$iezyh^48Pidza=3oLU6YlGzt_i96qOCXJxxXDw*>2+zqeCA*H5 zPs8ypmEK_Y=G4RN$7N~69zaA7&q7B;*g0;0O+a3#h#-1SIkt+9fGnMrj$l=N7rHa`qv7C6w|gK`?W_{D&2`C*@yvxEeRTiN zo?>4*3nd|+>JU_``I?x-J$ zg$A0uyHZoCCWO+4ue^Vi|LoYS^LDa2UGn9hHQDQ)O|yOXGvdOFClX zEuc~Ne@IKXdf$_F^@Y@)R#R+KGQBZwYW1i?y{_~HD}9u+=xge7xw@L7*=#hD&Hm$B z0tf*3`uAvwk3ViJvxn_%=MqDE_jY#v$k0SS1Plw0r{`?6gzfYnh4X~(f@2!md8ih# zlR(dE#YcwNI{M{zNWU3i!%kL5rw0|^P58Z&_EF`Z;#OHir^Pm(Icqr_Gg`?bxh5i<`{@0gZ_WA0% z`yYQ?1#OBq0|*x@En0yXHQ{VY!U+nT$m5Awz*@Ij0L^F$)NPNPi}(^DlrG{nvm zA0CvV&i2}9sjJ3dbC}N2EpzBLyW6do$u(2Gku_D-T zCBpX9QGVOV8OPH>16W&Qt%~crFo5-z&D*;lVpl9aRItd{8fHV=^;~n2?VQ6Jxy`KD zV{^E4tFv84+-R^ljHNn_y;ir(n;5)cVtn$N=hJM>JMVhxkacc&YtUPH!rP3#--Ru8JF4WMu&rHRw!(A%M`M& zkK@{iwz&7}%X`a%c*=;Uzr(&QB?V8ODm)8om3cXLkJu zi$VgkY&k1oC!zI>5)v`5p@lCFOTDH#fQCO2f4EM02LF5=N z`~xTKxTW|@Ycd<$J+xc;u%ME9@!_DLBCGC+{{AQEFT1P1pXN>lPT{&p_&G*hHI6-A z6|8ntdfBaB`u5-EecOX?nL~PMJ=4iwQ?~14>{{lbXAhyhF4q6p`t_)@OZ6oC6>}EK z?|5=(h?hU5E@N~yx_rOz{ig;7P+o)6z+OPkD$#&?YS^jER8$Ji*MEKagX{Qz8*p&Y==TS3Cl-vX$udwIwB*m`TuR zN@`K`>d@e_vL&^R_*c86Y}w#Y*xT$}TDqj7NfetZmXt1WG<&y9j9un(^f;XtkB|5H zV|&DeW4UFSBO&gOHLnD{j?*WYQ)!haqEK`3gw8MIDX3MNQz#fiD~=_l>T+tOTwS`< z+3XDu4V_a=$(EJPvHfUjnPoYe+7t8ljgMdKboMx0myJz;+rwxT;XQofzQ8zEAvCU2 z<7aqKy#N0Dx2U~uKe2M9@TrQTS;d&u1Ec&Cegvg4z>y^2e>?wIkX>_|Amz(P^<89g-a+f4k=%?x- z-p|E)Ij>9e`+(;`v+CQNW~`nIR=DIl(}O-c@xHoGvg>iu6V_Ac=ZHoh;lDpLGc&z^ z|Hhe_sr~!cef;*@KTbcyB?q3kEB{17jOaC1{`=?q_fO5tNUvOY;q=T*;Sok{sD8(v zP+E}d=C=?JP^0Qq<$GR}qfiC4*u$P+gNk%P8%A*KSwu6d+fn@jCvY7Tl%! z6u*n#GpT%sZ)#Pmh1Z2$WIykO9<{?WVM~6OeBR6MNlDq&FDGAMPbDQQcn~}NN#TAW zicE$C&gkr;Q^X4=LC6_jB8R~UK`h?YRfN~vg5d6BFTgnH>qqANVn>g|bDcj^;j za~h%C{nAHz&TH-NY;yY@o!;1hHdWI(%yxJO{jrgd!Pl6wi18)|tl&MR@y%@==bBn- zdV*q$*=Or9G}S|Ew4A<;@B5~cL4YuJVj{~)!yI^)*^7+ywnL3pfJE^s#oJ(-oAZsb}BfjIx@TX${N zZL_*+_4c+XpooAkWwD7Cv%Rj)(H8b+9n#xDU&?B8o6U|oy`wGS?{Z{CyZk^T)JH2Q z>^8L^(D@u8$|otvqjK&{j%m3w3g^hBW?nuCyJP4W&Me&Y{?$WQY@)xtEz_~s#+IhR z##nX0XpNiAajPk~B4!whO+4|nm8#YW_KRR;#h7C82Vm|dC&FFRTpL{;baBjsY7wDC7a!ij1 zDUo@UCgz;+NNS!nc5F?=w{~QUbwsptUm%n|CS}c46O~-q|zsGT!SF;1s2WS6G zzj0q3OA1GX+kp%uIb{X8U;K=f#5_iP$djtIR5e-5F0IMwFjX5vW_zs4Qt8k)TD3-$ zXfxZbw}4GSV$*V#G#M@WIzyeduClyBZ!;LZwGFkFYHfXOmA-QM3caJzA6+_+fda>e zwn1Md=v@yoh6Rf~4cPn+KuXk2Y+RiI;A#IiJ1 z9_N5E8y*=U&WG^Mpy!0oLW?1)u(KfH3XwVDNUc(MfqAh(0|DgtW@}2{;gm<-nW;_N zHgD7KCjSx5?!T9)rHf z*Wv`|QO5AY|2DL4jK`;w{P*vJ6M;?Eu+bQ{S|g2(k)Lb`Oi0&H1jk)#OWgx)dBF`9zTRL*hDiwlhi5N^#<{IJiix^yxa+;G{d)dz5%>qKhh z1Pvc>M4al%{$*g`o>i-I5!Dddr+g*s z1voS}W{Wf(4S8Ysxua!Ux^J?+y|&eFi<=){&!L^8YW8gJ_GpXPZgrVj+>&0611CMG zcq!>mVGy33d}amdR8^;vUrR|pYP~(CL#;62bj<$J%)Oy|FL-5e(+3S-V86ZFeht&I zPe`}19nwbWRqUO>InOVV3MCdg#1)BPSmQxb5QS7#(mB*9~hV{x{YV{@?c3vX!$R>RypMFIB_#!C8 zyS&I6BpNaDM5iE2_+Eo3yZTJ~G^ z5k9^+XAZ`ujFy=4XAhs-=yf^k8a!2z`pza}lgm+C&p)%;it37*nuya`uC35%BMy!| zrBt6suRmSrwFsLOZI58|Cf2U){0-WSvG1`PU_XN|on&JJ=V9Fk90v!lPv5}4ck(1- z5&#ZbWqR0Ocs4b55YP&gz_=vj)K**}D76z-BY-` zU%8vk3#_sxtX1r(v~)=u`>1s1DBC2M($d9kjBOf~?j+7SRa3%+`Db+2n3j7(!tz|b z?C{u_geDfYuv5blYHJnFzZ7(ZO23h2$J5d-wvig39(X|0`(&DS!meJbPv~%D&%s=+ zH?S9#4$SWX%~%|}uCZ2qwW!W3`R7lp$07vvdJWm_q|vZ;e)mM*F~M*}?;SKt-GU9@y^{NGt>;*u zVDsDoR|B{w_H%9*{($dD&nTb;i?@qH`Z!*{FDMMF!jo}hcBL936M zYxJc{!{<~IBB#u@B_#}j5L_#B2G^JKYh_;G`iOGP=K`*e@@T_Z%0Fs$3tTesWo&dUU$Kt8nnU_rjpbJTW&Z=%d6t0y literal 0 HcmV?d00001 diff --git a/core/designsystem/src/commonMain/composeResources/font/outfit_semi_bold.ttf b/core/designsystem/src/commonMain/composeResources/font/outfit_semi_bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6b37eeb6ea6b9382526a0fb307f531962f9b7995 GIT binary patch literal 55496 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 XrO&59pO;QgIGm4O-*mh1_80#LzDa2* literal 0 HcmV?d00001 diff --git a/core/designsystem/src/commonMain/composeResources/font/outfit_thin.ttf b/core/designsystem/src/commonMain/composeResources/font/outfit_thin.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7d84201a78f970b6adf3130ddc7bcde8125a97a7 GIT binary patch literal 54584 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℧G^XU*?sd-1ZyMnw*$m=6gRg>3wQmXup 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 z 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 BwE_SD literal 0 HcmV?d00001 diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Background.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Background.kt index 012f0c038..1d534173a 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Background.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Background.kt @@ -16,7 +16,11 @@ import androidx.compose.material3.LocalAbsoluteTonalElevation import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.getValue +import androidx.compose.runtime.rememberUpdatedState import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp @@ -59,13 +63,14 @@ fun MifosBackground( * @param gradientColors The gradient colors to be rendered. * @param content The background content. */ -// TODO:: Fix the gradient background based on NewUI @Composable fun MifosGradientBackground( modifier: Modifier = Modifier, gradientColors: GradientColors = LocalGradientColors.current, content: @Composable () -> Unit, ) { + val currentTopColor by rememberUpdatedState(gradientColors.top) + val currentBottomColor by rememberUpdatedState(gradientColors.bottom) Surface( color = if (gradientColors.container == Color.Unspecified) { Color.Transparent @@ -76,21 +81,24 @@ fun MifosGradientBackground( ) { Box( Modifier - .fillMaxSize(), + .fillMaxSize() + .drawWithCache { + val mainGradient = Brush.linearGradient( + colors = listOf(currentTopColor, currentBottomColor), + ) + + onDrawBehind { + // There is overlap here, so order is important + drawRect(mainGradient) + } + }, ) { content() } } } -/** - * Multipreview annotation that represents light and dark themes. Add this annotation to a - * composable to render the both themes. - */ @Preview -annotation class ThemePreviews - -@ThemePreviews @Composable fun BackgroundDefault() { MifosTheme { @@ -98,7 +106,7 @@ fun BackgroundDefault() { } } -@ThemePreviews +@Preview @Composable fun BackgroundDynamic() { MifosTheme { @@ -106,7 +114,7 @@ fun BackgroundDynamic() { } } -@ThemePreviews +@Preview @Composable fun BackgroundAndroid() { MifosTheme { @@ -114,7 +122,7 @@ fun BackgroundAndroid() { } } -@ThemePreviews +@Preview @Composable fun GradientBackgroundDefault() { MifosTheme { @@ -122,7 +130,7 @@ fun GradientBackgroundDefault() { } } -@ThemePreviews +@Preview @Composable fun GradientBackgroundDynamic() { MifosTheme { @@ -130,7 +138,7 @@ fun GradientBackgroundDynamic() { } } -@ThemePreviews +@Preview @Composable fun GradientBackgroundAndroid() { MifosTheme { diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Button.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Button.kt index 2c1d566ad..b52403ecc 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Button.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Button.kt @@ -31,6 +31,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Shape import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.MifosTheme @@ -283,7 +284,7 @@ private fun MifosButtonContent( } } -@ThemePreviews +@Preview @Composable fun MifosButtonPreview() { MifosTheme { @@ -293,7 +294,7 @@ fun MifosButtonPreview() { } } -@ThemePreviews +@Preview @Composable fun MifosOutlinedButtonPreview() { MifosTheme { @@ -303,7 +304,7 @@ fun MifosOutlinedButtonPreview() { } } -@ThemePreviews +@Preview @Composable fun MifosButtonLeadingIconPreview() { MifosTheme { diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/IconBox.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/IconBox.kt new file mode 100644 index 000000000..aa0e4821f --- /dev/null +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/IconBox.kt @@ -0,0 +1,59 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.designsystem.component + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedIconButton +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.vector.ImageVector +import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.designsystem.theme.MifosTheme + +@Composable +fun IconBox( + icon: ImageVector, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + OutlinedIconButton( + onClick = onClick, + modifier = modifier, + shape = RoundedCornerShape(12.dp), + border = BorderStroke(2.dp, MaterialTheme.colorScheme.onSurface.copy(alpha = 0.1f)), + ) { + Icon( + imageVector = icon, + contentDescription = icon.name, + ) + } +} + +@Composable +@Preview +private fun IconBoxPreview( + modifier: Modifier = Modifier, +) { + MifosTheme { + Surface { + IconBox( + icon = MifosIcons.ArrowBack2, + modifier = modifier, + onClick = {}, + ) + } + } +} diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt index 89853c26c..d3990e66e 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/LoadingWheel.kt @@ -48,6 +48,7 @@ import androidx.compose.ui.semantics.contentDescription import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import kotlinx.coroutines.launch +import org.jetbrains.compose.ui.tooling.preview.Preview import org.mifospay.core.designsystem.theme.MifosTheme @Composable @@ -188,7 +189,7 @@ fun MfLoadingWheel( } } -@ThemePreviews +@Preview @Composable fun MifosLoadingWheelPreview() { MifosTheme { @@ -198,7 +199,7 @@ fun MifosLoadingWheelPreview() { } } -@ThemePreviews +@Preview @Composable fun NiaOverlayLoadingWheelPreview() { MifosTheme { diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Navigation.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Navigation.kt index 1e722d189..e532dbe3f 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Navigation.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/Navigation.kt @@ -24,6 +24,7 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.MifosTheme @@ -61,8 +62,7 @@ fun RowScope.MifosNavigationBarItem( enabled = enabled, label = label, alwaysShowLabel = alwaysShowLabel, - colors = - NavigationBarItemDefaults.colors( + colors = NavigationBarItemDefaults.colors( selectedIconColor = MifosNavigationDefaults.navigationSelectedItemColor(), unselectedIconColor = MifosNavigationDefaults.navigationContentColor(), selectedTextColor = MifosNavigationDefaults.navigationSelectedItemColor(), @@ -86,6 +86,7 @@ fun MifosNavigationBar( ) { NavigationBar( modifier = modifier, + containerColor = MaterialTheme.colorScheme.background, contentColor = MifosNavigationDefaults.navigationContentColor(), tonalElevation = 0.dp, content = content, @@ -126,8 +127,7 @@ fun MifosNavigationRailItem( enabled = enabled, label = label, alwaysShowLabel = alwaysShowLabel, - colors = - NavigationRailItemDefaults.colors( + colors = NavigationRailItemDefaults.colors( selectedIconColor = MifosNavigationDefaults.navigationSelectedItemColor(), unselectedIconColor = MifosNavigationDefaults.navigationContentColor(), selectedTextColor = MifosNavigationDefaults.navigationSelectedItemColor(), @@ -160,7 +160,7 @@ fun MifosNavigationRail( ) } -@ThemePreviews +@Preview @Composable fun MifosNavigationBarPreview() { val items = listOf("Home", "Payments", "Finance", "Profile") @@ -204,7 +204,7 @@ fun MifosNavigationBarPreview() { } } -@ThemePreviews +@Preview @Composable fun MifosNavigationRailPreview() { val items = listOf("Home", "Payments", "Finance", "Profile") diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TextField.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TextField.kt index a98e8e8ab..0fe292064 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TextField.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TextField.kt @@ -34,6 +34,7 @@ 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.unit.sp +import org.jetbrains.compose.ui.tooling.preview.Preview import org.mifospay.core.designsystem.theme.MifosTheme @Composable @@ -157,7 +158,7 @@ fun MifosOutlinedTextField( ) } -@ThemePreviews +@Preview @Composable fun MfOutlinedTextFieldPreview() { MifosTheme { @@ -177,7 +178,7 @@ fun MfOutlinedTextFieldPreview() { } } -@ThemePreviews +@Preview @Composable fun MfPasswordTextFieldPreview() { MifosTheme { diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt index 14ba54e2b..11c641dc1 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/TopAppBar.kt @@ -24,6 +24,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.testTag +import org.jetbrains.compose.ui.tooling.preview.Preview import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.MifosTheme @@ -87,7 +88,7 @@ fun MifosNavigationTopAppBar( } @OptIn(ExperimentalMaterial3Api::class) -@ThemePreviews +@Preview @Composable private fun MifosTopAppBarPreview() { MifosTheme { diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/AppScrollbars.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/AppScrollbars.kt new file mode 100644 index 000000000..292477587 --- /dev/null +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/AppScrollbars.kt @@ -0,0 +1,246 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.designsystem.component.scrollbar + +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.Spring +import androidx.compose.animation.core.SpringSpec +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.Orientation.Horizontal +import androidx.compose.foundation.gestures.Orientation.Vertical +import androidx.compose.foundation.gestures.ScrollableState +import androidx.compose.foundation.interaction.InteractionSource +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.collectIsDraggedAsState +import androidx.compose.foundation.interaction.collectIsHoveredAsState +import androidx.compose.foundation.interaction.collectIsPressedAsState +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Size +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.ColorProducer +import androidx.compose.ui.graphics.Outline +import androidx.compose.ui.graphics.drawOutline +import androidx.compose.ui.graphics.drawscope.ContentDrawScope +import androidx.compose.ui.node.DrawModifierNode +import androidx.compose.ui.node.ModifierNodeElement +import androidx.compose.ui.node.invalidateDraw +import androidx.compose.ui.unit.LayoutDirection +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.delay +import org.mifospay.core.designsystem.component.scrollbar.ThumbState.Active +import org.mifospay.core.designsystem.component.scrollbar.ThumbState.Dormant +import org.mifospay.core.designsystem.component.scrollbar.ThumbState.Inactive + +/** + * The time period for showing the scrollbar thumb after interacting with it, before it fades away + */ +private const val SCROLLBAR_INACTIVE_TO_DORMANT_TIME_IN_MS = 2_000L + +/** + * A [Scrollbar] that allows for fast scrolling of content by dragging its thumb. + * Its thumb disappears when the scrolling container is dormant. + * @param modifier a [Modifier] for the [Scrollbar] + * @param state the driving state for the [Scrollbar] + * @param orientation the orientation of the scrollbar + * @param onThumbMoved the fast scroll implementation + */ +@Composable +fun ScrollableState.DraggableScrollbar( + state: ScrollbarState, + orientation: Orientation, + onThumbMoved: (Float) -> Unit, + modifier: Modifier = Modifier, +) { + val interactionSource = remember { MutableInteractionSource() } + Scrollbar( + modifier = modifier, + orientation = orientation, + interactionSource = interactionSource, + state = state, + thumb = { + DraggableScrollbarThumb( + interactionSource = interactionSource, + orientation = orientation, + ) + }, + onThumbMoved = onThumbMoved, + ) +} + +/** + * A simple [Scrollbar]. + * Its thumb disappears when the scrolling container is dormant. + * @param modifier a [Modifier] for the [Scrollbar] + * @param state the driving state for the [Scrollbar] + * @param orientation the orientation of the scrollbar + */ +@Composable +fun ScrollableState.DecorativeScrollbar( + state: ScrollbarState, + orientation: Orientation, + modifier: Modifier = Modifier, +) { + val interactionSource = remember { MutableInteractionSource() } + Scrollbar( + modifier = modifier, + orientation = orientation, + interactionSource = interactionSource, + state = state, + thumb = { + DecorativeScrollbarThumb( + interactionSource = interactionSource, + orientation = orientation, + ) + }, + ) +} + +/** + * A scrollbar thumb that is intended to also be a touch target for fast scrolling. + */ +@Composable +private fun ScrollableState.DraggableScrollbarThumb( + interactionSource: InteractionSource, + orientation: Orientation, +) { + Box( + modifier = Modifier + .run { + when (orientation) { + Vertical -> width(12.dp).fillMaxHeight() + Horizontal -> height(12.dp).fillMaxWidth() + } + } + .scrollThumb(this, interactionSource), + ) +} + +/** + * A decorative scrollbar thumb used solely for communicating a user's position in a list. + */ +@Composable +private fun ScrollableState.DecorativeScrollbarThumb( + interactionSource: InteractionSource, + orientation: Orientation, +) { + Box( + modifier = Modifier + .run { + when (orientation) { + Vertical -> width(2.dp).fillMaxHeight() + Horizontal -> height(2.dp).fillMaxWidth() + } + } + .scrollThumb(this, interactionSource), + ) +} + +@Composable +private fun Modifier.scrollThumb( + scrollableState: ScrollableState, + interactionSource: InteractionSource, +): Modifier { + val colorState = scrollbarThumbColor(scrollableState, interactionSource) + return this then ScrollThumbElement { colorState.value } +} + +private data class ScrollThumbElement(val colorProducer: ColorProducer) : + ModifierNodeElement() { + override fun create(): ScrollThumbNode = ScrollThumbNode(colorProducer) + override fun update(node: ScrollThumbNode) { + node.colorProducer = colorProducer + node.invalidateDraw() + } +} + +private class ScrollThumbNode(var colorProducer: ColorProducer) : DrawModifierNode, Modifier.Node() { + private val shape = RoundedCornerShape(16.dp) + + // naive cache outline calculation if size is the same + private var lastSize: Size? = null + private var lastLayoutDirection: LayoutDirection? = null + private var lastOutline: Outline? = null + + override fun ContentDrawScope.draw() { + val color = colorProducer() + val outline = + if (size == lastSize && layoutDirection == lastLayoutDirection) { + lastOutline!! + } else { + shape.createOutline(size, layoutDirection, this) + } + if (color != Color.Unspecified) drawOutline(outline, color = color) + + lastOutline = outline + lastSize = size + lastLayoutDirection = layoutDirection + } +} + +/** + * The color of the scrollbar thumb as a function of its interaction state. + * @param interactionSource source of interactions in the scrolling container + */ +@Composable +private fun scrollbarThumbColor( + scrollableState: ScrollableState, + interactionSource: InteractionSource, +): State { + var state by remember { mutableStateOf(Dormant) } + val pressed by interactionSource.collectIsPressedAsState() + val hovered by interactionSource.collectIsHoveredAsState() + val dragged by interactionSource.collectIsDraggedAsState() + val active = (scrollableState.canScrollForward || scrollableState.canScrollBackward) && + (pressed || hovered || dragged || scrollableState.isScrollInProgress) + + val color = animateColorAsState( + targetValue = when (state) { + Active -> MaterialTheme.colorScheme.onSurface.copy(0.5f) + Inactive -> MaterialTheme.colorScheme.onSurface.copy(alpha = 0.2f) + Dormant -> Color.Transparent + }, + animationSpec = SpringSpec( + stiffness = Spring.StiffnessLow, + ), + label = "Scrollbar thumb color", + ) + LaunchedEffect(active) { + when (active) { + true -> state = Active + false -> if (state == Active) { + state = Inactive + delay(SCROLLBAR_INACTIVE_TO_DORMANT_TIME_IN_MS) + state = Dormant + } + } + } + + return color +} + +private enum class ThumbState { + Active, + Inactive, + Dormant, +} diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/LazyScrollbarUtilities.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/LazyScrollbarUtilities.kt new file mode 100644 index 000000000..898431341 --- /dev/null +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/LazyScrollbarUtilities.kt @@ -0,0 +1,81 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.designsystem.component.scrollbar + +import androidx.compose.foundation.gestures.ScrollableState +import kotlin.math.abs + +/** + * Linearly interpolates the index for the first item in [visibleItems] for smooth scrollbar + * progression. + * @param visibleItems a list of items currently visible in the layout. + * @param itemSize a lookup function for the size of an item in the layout. + * @param offset a lookup function for the offset of an item relative to the start of the view port. + * @param nextItemOnMainAxis a lookup function for the next item on the main axis in the direction + * of the scroll. + * @param itemIndex a lookup function for index of an item in the layout relative to + * the total amount of items available. + * + * @return a [Float] in the range [firstItemPosition..nextItemPosition) where nextItemPosition + * is the index of the consecutive item along the major axis. + * */ +internal inline fun LazyState.interpolateFirstItemIndex( + visibleItems: List, + crossinline itemSize: LazyState.(LazyStateItem) -> Int, + crossinline offset: LazyState.(LazyStateItem) -> Int, + crossinline nextItemOnMainAxis: LazyState.(LazyStateItem) -> LazyStateItem?, + crossinline itemIndex: (LazyStateItem) -> Int, +): Float { + if (visibleItems.isEmpty()) return 0f + + val firstItem = visibleItems.first() + val firstItemIndex = itemIndex(firstItem) + + if (firstItemIndex < 0) return Float.NaN + + val firstItemSize = itemSize(firstItem) + if (firstItemSize == 0) return Float.NaN + + val itemOffset = offset(firstItem).toFloat() + val offsetPercentage = abs(itemOffset) / firstItemSize + + val nextItem = nextItemOnMainAxis(firstItem) ?: return firstItemIndex + offsetPercentage + + val nextItemIndex = itemIndex(nextItem) + + return firstItemIndex + ((nextItemIndex - firstItemIndex) * offsetPercentage) +} + +/** + * Returns the percentage of an item that is currently visible in the view port. + * @param itemSize the size of the item + * @param itemStartOffset the start offset of the item relative to the view port start + * @param viewportStartOffset the start offset of the view port + * @param viewportEndOffset the end offset of the view port + */ +internal fun itemVisibilityPercentage( + itemSize: Int, + itemStartOffset: Int, + viewportStartOffset: Int, + viewportEndOffset: Int, +): Float { + if (itemSize == 0) return 0f + val itemEnd = itemStartOffset + itemSize + val startOffset = when { + itemStartOffset > viewportStartOffset -> 0 + else -> abs(abs(viewportStartOffset) - abs(itemStartOffset)) + } + val endOffset = when { + itemEnd < viewportEndOffset -> 0 + else -> abs(abs(itemEnd) - abs(viewportEndOffset)) + } + val size = itemSize.toFloat() + return (size - startOffset - endOffset) / size +} diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/Scrollbar.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/Scrollbar.kt new file mode 100644 index 000000000..5434926a6 --- /dev/null +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/Scrollbar.kt @@ -0,0 +1,412 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.designsystem.component.scrollbar + +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.gestures.Orientation.Horizontal +import androidx.compose.foundation.gestures.Orientation.Vertical +import androidx.compose.foundation.gestures.detectHorizontalDragGestures +import androidx.compose.foundation.gestures.detectTapGestures +import androidx.compose.foundation.gestures.detectVerticalDragGestures +import androidx.compose.foundation.hoverable +import androidx.compose.foundation.interaction.DragInteraction +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.interaction.PressInteraction +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Immutable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableLongStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.runtime.snapshotFlow +import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.input.pointer.PointerInputChange +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.Layout +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.positionInRoot +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.IntOffset +import androidx.compose.ui.unit.IntSize +import androidx.compose.ui.unit.dp +import androidx.compose.ui.util.packFloats +import androidx.compose.ui.util.unpackFloat1 +import androidx.compose.ui.util.unpackFloat2 +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.delay +import kotlinx.coroutines.withTimeout +import kotlin.jvm.JvmInline +import kotlin.math.max +import kotlin.math.min +import kotlin.math.roundToInt + +/** + * The delay between scrolls when a user long presses on the scrollbar track to initiate a scroll + * instead of dragging the scrollbar thumb. + */ +private const val SCROLLBAR_PRESS_DELAY_MS = 10L + +/** + * The percentage displacement of the scrollbar when scrolled by long presses on the scrollbar + * track. + */ +private const val SCROLLBAR_PRESS_DELTA_PCT = 0.02f + +class ScrollbarState { + private var packedValue by mutableLongStateOf(0L) + + internal fun onScroll(stateValue: ScrollbarStateValue) { + packedValue = stateValue.packedValue + } + + /** + * Returns the thumb size of the scrollbar as a percentage of the total track size + */ + val thumbSizePercent + get() = unpackFloat1(packedValue) + + /** + * Returns the distance the thumb has traveled as a percentage of total track size + */ + val thumbMovedPercent + get() = unpackFloat2(packedValue) + + /** + * Returns the max distance the thumb can travel as a percentage of total track size + */ + val thumbTrackSizePercent + get() = 1f - thumbSizePercent +} + +/** + * Returns the size of the scrollbar track in pixels + */ +private val ScrollbarTrack.size + get() = unpackFloat2(packedValue) - unpackFloat1(packedValue) + +/** + * Returns the position of the scrollbar thumb on the track as a percentage + */ +private fun ScrollbarTrack.thumbPosition( + dimension: Float, +): Float = max( + a = min( + a = dimension / size, + b = 1f, + ), + b = 0f, +) + +/** + * Class definition for the core properties of a scroll bar + */ +@Immutable +@JvmInline +value class ScrollbarStateValue internal constructor( + internal val packedValue: Long, +) + +/** + * Class definition for the core properties of a scroll bar track + */ +@Immutable +@JvmInline +private value class ScrollbarTrack( + val packedValue: Long, +) { + constructor( + max: Float, + min: Float, + ) : this(packFloats(max, min)) +} + +/** + * Creates a [ScrollbarStateValue] with the listed properties + * @param thumbSizePercent the thumb size of the scrollbar as a percentage of the total track size. + * Refers to either the thumb width (for horizontal scrollbars) + * or height (for vertical scrollbars). + * @param thumbMovedPercent the distance the thumb has traveled as a percentage of total + * track size. + */ +fun scrollbarStateValue( + thumbSizePercent: Float, + thumbMovedPercent: Float, +) = ScrollbarStateValue( + packFloats( + val1 = thumbSizePercent, + val2 = thumbMovedPercent, + ), +) + +/** + * Returns the value of [offset] along the axis specified by [this] + */ +internal fun Orientation.valueOf(offset: Offset) = when (this) { + Orientation.Horizontal -> offset.x + Orientation.Vertical -> offset.y +} + +/** + * Returns the value of [intSize] along the axis specified by [this] + */ +internal fun Orientation.valueOf(intSize: IntSize) = when (this) { + Orientation.Horizontal -> intSize.width + Orientation.Vertical -> intSize.height +} + +/** + * Returns the value of [intOffset] along the axis specified by [this] + */ +internal fun Orientation.valueOf(intOffset: IntOffset) = when (this) { + Orientation.Horizontal -> intOffset.x + Orientation.Vertical -> intOffset.y +} + +/** + * A Composable for drawing a scrollbar + * @param orientation the scroll direction of the scrollbar + * @param state the state describing the position of the scrollbar + * @param minThumbSize the minimum size of the scrollbar thumb + * @param interactionSource allows for observing the state of the scroll bar + * @param thumb a composable for drawing the scrollbar thumb + * @param onThumbMoved an function for reacting to scroll bar displacements caused by direct + * interactions on the scrollbar thumb by the user, for example implementing a fast scroll + */ +@Composable +fun Scrollbar( + orientation: Orientation, + state: ScrollbarState, + modifier: Modifier = Modifier, + interactionSource: MutableInteractionSource? = null, + minThumbSize: Dp = 40.dp, + onThumbMoved: ((Float) -> Unit)? = null, + thumb: @Composable () -> Unit, +) { + // Using Offset.Unspecified and Float.NaN instead of null + // to prevent unnecessary boxing of primitives + var pressedOffset by remember { mutableStateOf(Offset.Unspecified) } + var draggedOffset by remember { mutableStateOf(Offset.Unspecified) } + + // Used to immediately show drag feedback in the UI while the scrolling implementation + // catches up + var interactionThumbTravelPercent by remember { mutableFloatStateOf(Float.NaN) } + + var track by remember { mutableStateOf(ScrollbarTrack(packedValue = 0)) } + + // scrollbar track container + Box( + modifier = modifier + .run { + val withHover = interactionSource?.let(::hoverable) ?: this + when (orientation) { + Orientation.Vertical -> withHover.fillMaxHeight() + Orientation.Horizontal -> withHover.fillMaxWidth() + } + } + .onGloballyPositioned { coordinates -> + val scrollbarStartCoordinate = orientation.valueOf(coordinates.positionInRoot()) + track = ScrollbarTrack( + max = scrollbarStartCoordinate, + min = scrollbarStartCoordinate + orientation.valueOf(coordinates.size), + ) + } + // Process scrollbar presses + .pointerInput(Unit) { + detectTapGestures( + onPress = { offset -> + try { + // Wait for a long press before scrolling + withTimeout(viewConfiguration.longPressTimeoutMillis) { + tryAwaitRelease() + } + } catch (e: TimeoutCancellationException) { + // Start the press triggered scroll + val initialPress = PressInteraction.Press(offset) + interactionSource?.tryEmit(initialPress) + + pressedOffset = offset + interactionSource?.tryEmit( + when { + tryAwaitRelease() -> PressInteraction.Release(initialPress) + else -> PressInteraction.Cancel(initialPress) + }, + ) + + // End the press + pressedOffset = Offset.Unspecified + } + }, + ) + } + // Process scrollbar drags + .pointerInput(Unit) { + var dragInteraction: DragInteraction.Start? = null + val onDragStart: (Offset) -> Unit = { offset -> + val start = DragInteraction.Start() + dragInteraction = start + interactionSource?.tryEmit(start) + draggedOffset = offset + } + val onDragEnd: () -> Unit = { + dragInteraction?.let { interactionSource?.tryEmit(DragInteraction.Stop(it)) } + draggedOffset = Offset.Unspecified + } + val onDragCancel: () -> Unit = { + dragInteraction?.let { interactionSource?.tryEmit(DragInteraction.Cancel(it)) } + draggedOffset = Offset.Unspecified + } + val onDrag: (change: PointerInputChange, dragAmount: Float) -> Unit = + onDrag@{ _, delta -> + if (draggedOffset == Offset.Unspecified) return@onDrag + draggedOffset = when (orientation) { + Orientation.Vertical -> draggedOffset.copy( + y = draggedOffset.y + delta, + ) + + Orientation.Horizontal -> draggedOffset.copy( + x = draggedOffset.x + delta, + ) + } + } + + when (orientation) { + Orientation.Horizontal -> detectHorizontalDragGestures( + onDragStart = onDragStart, + onDragEnd = onDragEnd, + onDragCancel = onDragCancel, + onHorizontalDrag = onDrag, + ) + + Orientation.Vertical -> detectVerticalDragGestures( + onDragStart = onDragStart, + onDragEnd = onDragEnd, + onDragCancel = onDragCancel, + onVerticalDrag = onDrag, + ) + } + }, + ) { + // scrollbar thumb container + Layout(content = { thumb() }) { measurables, constraints -> + val measurable = measurables.first() + + val thumbSizePx = max( + a = state.thumbSizePercent * track.size, + b = minThumbSize.toPx(), + ) + + val trackSizePx = when (state.thumbTrackSizePercent) { + 0f -> track.size + else -> (track.size - thumbSizePx) / state.thumbTrackSizePercent + } + + val thumbTravelPercent = max( + a = min( + a = when { + interactionThumbTravelPercent.isNaN() -> state.thumbMovedPercent + else -> interactionThumbTravelPercent + }, + b = state.thumbTrackSizePercent, + ), + b = 0f, + ) + + val thumbMovedPx = trackSizePx * thumbTravelPercent + + val y = when (orientation) { + Horizontal -> 0 + Vertical -> thumbMovedPx.roundToInt() + } + val x = when (orientation) { + Horizontal -> thumbMovedPx.roundToInt() + Vertical -> 0 + } + + val updatedConstraints = when (orientation) { + Horizontal -> { + constraints.copy( + minWidth = thumbSizePx.roundToInt(), + maxWidth = thumbSizePx.roundToInt(), + ) + } + Vertical -> { + constraints.copy( + minHeight = thumbSizePx.roundToInt(), + maxHeight = thumbSizePx.roundToInt(), + ) + } + } + + val placeable = measurable.measure(updatedConstraints) + layout(placeable.width, placeable.height) { + placeable.place(x, y) + } + } + } + + if (onThumbMoved == null) return + + // Process presses + LaunchedEffect(Unit) { + snapshotFlow { pressedOffset }.collect { pressedOffset -> + // Press ended, reset interactionThumbTravelPercent + if (pressedOffset == Offset.Unspecified) { + interactionThumbTravelPercent = Float.NaN + return@collect + } + + var currentThumbMovedPercent = state.thumbMovedPercent + val destinationThumbMovedPercent = track.thumbPosition( + dimension = orientation.valueOf(pressedOffset), + ) + val isPositive = currentThumbMovedPercent < destinationThumbMovedPercent + val delta = SCROLLBAR_PRESS_DELTA_PCT * if (isPositive) 1f else -1f + + while (currentThumbMovedPercent != destinationThumbMovedPercent) { + currentThumbMovedPercent = when { + isPositive -> min( + a = currentThumbMovedPercent + delta, + b = destinationThumbMovedPercent, + ) + + else -> max( + a = currentThumbMovedPercent + delta, + b = destinationThumbMovedPercent, + ) + } + onThumbMoved(currentThumbMovedPercent) + interactionThumbTravelPercent = currentThumbMovedPercent + delay(SCROLLBAR_PRESS_DELAY_MS) + } + } + } + + // Process drags + LaunchedEffect(Unit) { + snapshotFlow { draggedOffset }.collect { draggedOffset -> + if (draggedOffset == Offset.Unspecified) { + interactionThumbTravelPercent = Float.NaN + return@collect + } + val currentTravel = track.thumbPosition( + dimension = orientation.valueOf(draggedOffset), + ) + onThumbMoved(currentTravel) + interactionThumbTravelPercent = currentTravel + } + } +} diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/ScrollbarExt.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/ScrollbarExt.kt new file mode 100644 index 000000000..f61cecd85 --- /dev/null +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/ScrollbarExt.kt @@ -0,0 +1,227 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.designsystem.component.scrollbar + +import androidx.compose.foundation.gestures.Orientation +import androidx.compose.foundation.lazy.LazyListItemInfo +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.grid.LazyGridItemInfo +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.foundation.lazy.staggeredgrid.LazyStaggeredGridItemInfo +import androidx.compose.foundation.lazy.staggeredgrid.LazyStaggeredGridState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember +import androidx.compose.runtime.snapshotFlow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.filterNotNull +import kotlin.math.min + +/** + * Calculates a [ScrollbarState] driven by the changes in a [LazyListState]. + * + * @param itemsAvailable the total amount of items available to scroll in the lazy list. + * @param itemIndex a lookup function for index of an item in the list relative to [itemsAvailable]. + */ +@Composable +fun LazyListState.scrollbarState( + itemsAvailable: Int, + itemIndex: (LazyListItemInfo) -> Int = LazyListItemInfo::index, +): ScrollbarState { + val state = remember { ScrollbarState() } + LaunchedEffect(this, itemsAvailable) { + snapshotFlow { + if (itemsAvailable == 0) return@snapshotFlow null + + val visibleItemsInfo = layoutInfo.visibleItemsInfo + if (visibleItemsInfo.isEmpty()) return@snapshotFlow null + + val firstIndex = min( + a = interpolateFirstItemIndex( + visibleItems = visibleItemsInfo, + itemSize = { it.size }, + offset = { it.offset }, + nextItemOnMainAxis = { first -> visibleItemsInfo.find { it != first } }, + itemIndex = itemIndex, + ), + b = itemsAvailable.toFloat(), + ) + if (firstIndex.isNaN()) return@snapshotFlow null + + val itemsVisible = visibleItemsInfo.floatSumOf { itemInfo -> + itemVisibilityPercentage( + itemSize = itemInfo.size, + itemStartOffset = itemInfo.offset, + viewportStartOffset = layoutInfo.viewportStartOffset, + viewportEndOffset = layoutInfo.viewportEndOffset, + ) + } + + val thumbTravelPercent = min( + a = firstIndex / itemsAvailable, + b = 1f, + ) + val thumbSizePercent = min( + a = itemsVisible / itemsAvailable, + b = 1f, + ) + scrollbarStateValue( + thumbSizePercent = thumbSizePercent, + thumbMovedPercent = when { + layoutInfo.reverseLayout -> 1f - thumbTravelPercent + else -> thumbTravelPercent + }, + ) + } + .filterNotNull() + .distinctUntilChanged() + .collect { state.onScroll(it) } + } + return state +} + +/** + * Calculates a [ScrollbarState] driven by the changes in a [LazyGridState] + * + * @param itemsAvailable the total amount of items available to scroll in the grid. + * @param itemIndex a lookup function for index of an item in the grid relative to [itemsAvailable]. + */ +@Composable +fun LazyGridState.scrollbarState( + itemsAvailable: Int, + itemIndex: (LazyGridItemInfo) -> Int = LazyGridItemInfo::index, +): ScrollbarState { + val state = remember { ScrollbarState() } + LaunchedEffect(this, itemsAvailable) { + snapshotFlow { + if (itemsAvailable == 0) return@snapshotFlow null + + val visibleItemsInfo = layoutInfo.visibleItemsInfo + if (visibleItemsInfo.isEmpty()) return@snapshotFlow null + + val firstIndex = min( + a = interpolateFirstItemIndex( + visibleItems = visibleItemsInfo, + itemSize = { layoutInfo.orientation.valueOf(it.size) }, + offset = { layoutInfo.orientation.valueOf(it.offset) }, + nextItemOnMainAxis = { first -> + when (layoutInfo.orientation) { + Orientation.Vertical -> visibleItemsInfo.find { + it != first && it.row != first.row + } + + Orientation.Horizontal -> visibleItemsInfo.find { + it != first && it.column != first.column + } + } + }, + itemIndex = itemIndex, + ), + b = itemsAvailable.toFloat(), + ) + if (firstIndex.isNaN()) return@snapshotFlow null + + val itemsVisible = visibleItemsInfo.floatSumOf { itemInfo -> + itemVisibilityPercentage( + itemSize = layoutInfo.orientation.valueOf(itemInfo.size), + itemStartOffset = layoutInfo.orientation.valueOf(itemInfo.offset), + viewportStartOffset = layoutInfo.viewportStartOffset, + viewportEndOffset = layoutInfo.viewportEndOffset, + ) + } + + val thumbTravelPercent = min( + a = firstIndex / itemsAvailable, + b = 1f, + ) + val thumbSizePercent = min( + a = itemsVisible / itemsAvailable, + b = 1f, + ) + scrollbarStateValue( + thumbSizePercent = thumbSizePercent, + thumbMovedPercent = when { + layoutInfo.reverseLayout -> 1f - thumbTravelPercent + else -> thumbTravelPercent + }, + ) + } + .filterNotNull() + .distinctUntilChanged() + .collect { state.onScroll(it) } + } + return state +} + +/** + * Remembers a [ScrollbarState] driven by the changes in a [LazyStaggeredGridState] + * + * @param itemsAvailable the total amount of items available to scroll in the staggered grid. + * @param itemIndex a lookup function for index of an item in the staggered grid relative + * to [itemsAvailable]. + */ +@Composable +fun LazyStaggeredGridState.scrollbarState( + itemsAvailable: Int, + itemIndex: (LazyStaggeredGridItemInfo) -> Int = LazyStaggeredGridItemInfo::index, +): ScrollbarState { + val state = remember { ScrollbarState() } + LaunchedEffect(this, itemsAvailable) { + snapshotFlow { + if (itemsAvailable == 0) return@snapshotFlow null + + val visibleItemsInfo = layoutInfo.visibleItemsInfo + if (visibleItemsInfo.isEmpty()) return@snapshotFlow null + + val firstIndex = min( + a = interpolateFirstItemIndex( + visibleItems = visibleItemsInfo, + itemSize = { layoutInfo.orientation.valueOf(it.size) }, + offset = { layoutInfo.orientation.valueOf(it.offset) }, + nextItemOnMainAxis = { first -> + visibleItemsInfo.find { it != first && it.lane == first.lane } + }, + itemIndex = itemIndex, + ), + b = itemsAvailable.toFloat(), + ) + if (firstIndex.isNaN()) return@snapshotFlow null + + val itemsVisible = visibleItemsInfo.floatSumOf { itemInfo -> + itemVisibilityPercentage( + itemSize = layoutInfo.orientation.valueOf(itemInfo.size), + itemStartOffset = layoutInfo.orientation.valueOf(itemInfo.offset), + viewportStartOffset = layoutInfo.viewportStartOffset, + viewportEndOffset = layoutInfo.viewportEndOffset, + ) + } + + val thumbTravelPercent = min( + a = firstIndex / itemsAvailable, + b = 1f, + ) + val thumbSizePercent = min( + a = itemsVisible / itemsAvailable, + b = 1f, + ) + scrollbarStateValue( + thumbSizePercent = thumbSizePercent, + thumbMovedPercent = thumbTravelPercent, + ) + } + .filterNotNull() + .distinctUntilChanged() + .collect { state.onScroll(it) } + } + return state +} + +private inline fun List.floatSumOf(selector: (T) -> Float): Float = + fold(initial = 0f) { accumulator, listItem -> accumulator + selector(listItem) } diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/ThumbExt.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/ThumbExt.kt new file mode 100644 index 000000000..4d64e992e --- /dev/null +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/component/scrollbar/ThumbExt.kt @@ -0,0 +1,82 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.designsystem.component.scrollbar + +import androidx.compose.foundation.lazy.LazyListState +import androidx.compose.foundation.lazy.grid.LazyGridState +import androidx.compose.foundation.lazy.staggeredgrid.LazyStaggeredGridState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.runtime.setValue +import kotlin.math.roundToInt + +/** + * Remembers a function to react to [Scrollbar] thumb position displacements for a [LazyListState] + * @param itemsAvailable the amount of items in the list. + */ +@Composable +fun LazyListState.rememberDraggableScroller( + itemsAvailable: Int, +): (Float) -> Unit = rememberDraggableScroller( + itemsAvailable = itemsAvailable, + scroll = ::scrollToItem, +) + +/** + * Remembers a function to react to [Scrollbar] thumb position displacements for a [LazyGridState] + * @param itemsAvailable the amount of items in the grid. + */ +@Composable +fun LazyGridState.rememberDraggableScroller( + itemsAvailable: Int, +): (Float) -> Unit = rememberDraggableScroller( + itemsAvailable = itemsAvailable, + scroll = ::scrollToItem, +) + +/** + * Remembers a function to react to [Scrollbar] thumb position displacements for a + * [LazyStaggeredGridState] + * @param itemsAvailable the amount of items in the staggered grid. + */ +@Composable +fun LazyStaggeredGridState.rememberDraggableScroller( + itemsAvailable: Int, +): (Float) -> Unit = rememberDraggableScroller( + itemsAvailable = itemsAvailable, + scroll = ::scrollToItem, +) + +/** + * Generic function to react to [Scrollbar] thumb displacements in a lazy layout. + * @param itemsAvailable the total amount of items available to scroll in the layout. + * @param scroll a function to be invoked when an index has been identified to scroll to. + */ +@Composable +private inline fun rememberDraggableScroller( + itemsAvailable: Int, + crossinline scroll: suspend (index: Int) -> Unit, +): (Float) -> Unit { + var percentage by remember { mutableFloatStateOf(Float.NaN) } + val itemCount by rememberUpdatedState(itemsAvailable) + + LaunchedEffect(percentage) { + if (percentage.isNaN()) return@LaunchedEffect + val indexToFind = (itemCount * percentage).roundToInt() + scroll(indexToFind) + } + return remember { + { newPercentage -> percentage = newPercentage } + } +} diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/icon/MifosIcons.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/icon/MifosIcons.kt index 3caf851dc..1f01147bb 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/icon/MifosIcons.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/icon/MifosIcons.kt @@ -12,10 +12,11 @@ package org.mifospay.core.designsystem.icon import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.outlined.ArrowBack -import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material.icons.filled.ArrowOutward +import androidx.compose.material.icons.filled.AttachMoney import androidx.compose.material.icons.filled.Camera import androidx.compose.material.icons.filled.Check +import androidx.compose.material.icons.filled.ChevronLeft import androidx.compose.material.icons.filled.ChevronRight import androidx.compose.material.icons.filled.Close import androidx.compose.material.icons.filled.ContentCopy @@ -24,6 +25,7 @@ import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.FlashOff import androidx.compose.material.icons.filled.FlashOn import androidx.compose.material.icons.filled.Info +import androidx.compose.material.icons.filled.KeyboardArrowDown import androidx.compose.material.icons.filled.Photo import androidx.compose.material.icons.filled.PhotoLibrary import androidx.compose.material.icons.filled.QrCode @@ -33,7 +35,9 @@ import androidx.compose.material.icons.filled.Visibility import androidx.compose.material.icons.filled.VisibilityOff import androidx.compose.material.icons.outlined.AccountCircle import androidx.compose.material.icons.outlined.Cancel +import androidx.compose.material.icons.outlined.Edit import androidx.compose.material.icons.outlined.Home +import androidx.compose.material.icons.outlined.Settings import androidx.compose.material.icons.outlined.Wallet import androidx.compose.material.icons.rounded.AccountBalance import androidx.compose.material.icons.rounded.AccountCircle @@ -56,10 +60,11 @@ object MifosIcons { val ChevronRight: ImageVector = Icons.Filled.ChevronRight val QrCode: ImageVector = Icons.Filled.QrCode val Close: ImageVector = Icons.Filled.Close + val AttachMoney: ImageVector = Icons.Filled.AttachMoney val VisibilityOff: ImageVector = Icons.Filled.VisibilityOff val Visibility: ImageVector = Icons.Filled.Visibility val Check: ImageVector = Icons.Default.Check - val ArrowDropDown: ImageVector = Icons.Default.ArrowDropDown + val KeyboardArrowDown: ImageVector = Icons.Default.KeyboardArrowDown val Home = Icons.Outlined.Home val HomeBoarder = Icons.Rounded.Home val Payment = Icons.Rounded.SwapHoriz @@ -74,6 +79,7 @@ object MifosIcons { val Copy = Icons.Filled.ContentCopy val Share = Icons.Filled.Share val ArrowBack = Icons.AutoMirrored.Filled.ArrowBack + val ArrowBack2 = Icons.Filled.ChevronLeft val Cancel = Icons.Outlined.Cancel val AccountCircle = Icons.Outlined.AccountCircle val SendRightTilted = Icons.Default.ArrowOutward @@ -84,6 +90,7 @@ object MifosIcons { val RoundedInfo = Icons.Rounded.Info val Contact = Icons.Rounded.Contacts val Settings = Icons.Rounded.Settings + val SettingsOutlined = Icons.Outlined.Settings val QR = Icons.Rounded.QrCode val Bank = Icons.Rounded.AccountBalance val Photo = Icons.Default.Photo @@ -91,4 +98,5 @@ object MifosIcons { val FlashOff = Icons.Default.FlashOff val QrCode2 = Icons.Filled.QrCode2 val Edit = Icons.Filled.Edit + val Edit2 = Icons.Outlined.Edit } diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Color.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Color.kt index c872243fc..8ffbff153 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Color.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Color.kt @@ -11,9 +11,9 @@ package org.mifospay.core.designsystem.theme import androidx.compose.ui.graphics.Color -val md_theme_light_primary = Color(0xFF000000) -val md_theme_light_onPrimary = Color(0xFFFFFFFF) -val md_theme_light_primaryContainer = Color(0xFFFFD9E2) +val md_theme_light_primary = Color(0xFF0673BA) // primary +val md_theme_light_onPrimary = Color(0xFFFFFFFF) // gradientOne +val md_theme_light_primaryContainer = Color(0xFFF5F5F5) // container color val md_theme_light_onPrimaryContainer = Color(0xFF3E001D) val md_theme_light_secondary = Color(0xFF984061) val md_theme_light_onSecondary = Color(0xFFFFFFFF) @@ -30,7 +30,7 @@ val md_theme_light_onErrorContainer = Color(0xFF410002) val md_theme_light_background = Color(0xFFFFFBFF) val md_theme_light_onBackground = Color(0xFF330045) val md_theme_light_surface = Color(0xFFFFFBFF) -val md_theme_light_onSurface = Color(0xFF000000) +val md_theme_light_onSurface = Color(0xFF333333) // onSurface val md_theme_light_surfaceVariant = Color(0xFFF2DDE1) val md_theme_light_onSurfaceVariant = Color(0xFF514347) val md_theme_light_outline = Color(0xFF837377) @@ -90,3 +90,21 @@ val primaryDarkBlue = Color(0xFF303F9F) val InitialAvatarBgColor = Color(0xFF9999CC) val submitButtonColor = Color(0xFF0000FF) val ElectricViolet = Color(0xFF6200EE) + +val MifosBlue = Color(0xFF0673BA) + +// This should be applied directly to the theme +// New UI Colors +object NewUi { + val gradientOne = Color(0xFFFFFFFF) + val gradientTwo = Color(0xFFD0D1D6) + val containerColor = Color(0xFFF5F5F5) + val primaryColor = Color(0xFF0673BA) + val tertiaryContainer = Color(0xFFFDFDFE) + val onSurface = Color(0xFF333333) + val secondaryColor = Color(0xFFFF3325) + + // general color + val walletColor1 = Color(0xFF1f7dd5) + val walletColor2 = Color(0xFF1ec0a0) +} diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Theme.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Theme.kt index 2562a413b..e31d96dbf 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Theme.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Theme.kt @@ -15,7 +15,10 @@ import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp +import org.mifospay.core.designsystem.theme.NewUi.gradientOne +import org.mifospay.core.designsystem.theme.NewUi.gradientTwo private val LightDefaultColorScheme = lightColorScheme( primary = md_theme_light_primary, @@ -91,16 +94,16 @@ fun MifosTheme( else -> if (darkTheme) DarkDefaultColorScheme else LightDefaultColorScheme } val defaultGradientColors = GradientColors( - top = colorScheme.inverseOnSurface, - bottom = colorScheme.primaryContainer, - container = colorScheme.surface, + top = gradientOne, + bottom = gradientTwo, + container = Color.Transparent, ) val gradientColors = when { else -> defaultGradientColors } // Background theme val defaultBackgroundTheme = BackgroundTheme( - color = colorScheme.surface, + color = Color.Transparent, tonalElevation = 2.dp, ) val backgroundTheme = when { @@ -117,7 +120,7 @@ fun MifosTheme( ) { MaterialTheme( colorScheme = colorScheme, - typography = MifosTypography, + typography = mifosTypography(), content = content, ) } diff --git a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Type.kt b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Type.kt index 68823df6b..cf918ca06 100644 --- a/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Type.kt +++ b/core/designsystem/src/commonMain/kotlin/org/mifospay/core/designsystem/theme/Type.kt @@ -10,44 +10,79 @@ package org.mifospay.core.designsystem.theme import androidx.compose.material3.Typography +import androidx.compose.runtime.Composable import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.LineHeightStyle import androidx.compose.ui.unit.sp +import mobile_wallet.core.designsystem.generated.resources.Res +import mobile_wallet.core.designsystem.generated.resources.outfit_black +import mobile_wallet.core.designsystem.generated.resources.outfit_bold +import mobile_wallet.core.designsystem.generated.resources.outfit_extra_bold +import mobile_wallet.core.designsystem.generated.resources.outfit_extra_light +import mobile_wallet.core.designsystem.generated.resources.outfit_light +import mobile_wallet.core.designsystem.generated.resources.outfit_medium +import mobile_wallet.core.designsystem.generated.resources.outfit_regular +import mobile_wallet.core.designsystem.generated.resources.outfit_semi_bold +import mobile_wallet.core.designsystem.generated.resources.outfit_thin +import org.jetbrains.compose.resources.Font + +@Composable +private fun fontFamily(): FontFamily { + return FontFamily( + Font(Res.font.outfit_black, FontWeight.Black), + Font(Res.font.outfit_bold, FontWeight.Bold), + Font(Res.font.outfit_semi_bold, FontWeight.SemiBold), + Font(Res.font.outfit_medium, FontWeight.Medium), + Font(Res.font.outfit_regular, FontWeight.Normal), + Font(Res.font.outfit_light, FontWeight.Light), + Font(Res.font.outfit_thin, FontWeight.Thin), + Font(Res.font.outfit_extra_light, FontWeight.ExtraLight), + Font(Res.font.outfit_extra_bold, FontWeight.ExtraBold), + ) +} // Set of Material typography styles to start with -internal val MifosTypography = Typography( +@Composable +internal fun mifosTypography() = Typography( displayLarge = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Normal, fontSize = 57.sp, lineHeight = 64.sp, letterSpacing = (-0.25).sp, ), displayMedium = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Normal, fontSize = 45.sp, lineHeight = 52.sp, letterSpacing = 0.sp, ), displaySmall = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Normal, fontSize = 36.sp, lineHeight = 44.sp, letterSpacing = 0.sp, ), headlineLarge = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Normal, fontSize = 32.sp, lineHeight = 40.sp, letterSpacing = 0.sp, ), headlineMedium = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Normal, fontSize = 28.sp, lineHeight = 36.sp, letterSpacing = 0.sp, ), headlineSmall = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Normal, fontSize = 24.sp, lineHeight = 32.sp, @@ -58,22 +93,20 @@ internal val MifosTypography = Typography( ), ), titleLarge = TextStyle( - fontWeight = FontWeight.Bold, - fontSize = 22.sp, - lineHeight = 28.sp, - letterSpacing = 0.sp, - lineHeightStyle = LineHeightStyle( - alignment = LineHeightStyle.Alignment.Bottom, - trim = LineHeightStyle.Trim.LastLineBottom, - ), + fontFamily = fontFamily(), + fontWeight = FontWeight.SemiBold, + fontSize = 24.sp, + lineHeight = 30.24.sp, ), titleMedium = TextStyle( - fontWeight = FontWeight.Bold, - fontSize = 18.sp, - lineHeight = 24.sp, + fontFamily = fontFamily(), + fontWeight = FontWeight.SemiBold, + fontSize = 20.sp, + lineHeight = 28.sp, letterSpacing = 0.1.sp, ), titleSmall = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Medium, fontSize = 14.sp, lineHeight = 20.sp, @@ -81,6 +114,7 @@ internal val MifosTypography = Typography( ), // Default text style bodyLarge = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Normal, fontSize = 16.sp, lineHeight = 24.sp, @@ -91,12 +125,14 @@ internal val MifosTypography = Typography( ), ), bodyMedium = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Normal, fontSize = 14.sp, lineHeight = 20.sp, letterSpacing = 0.25.sp, ), bodySmall = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Normal, fontSize = 12.sp, lineHeight = 16.sp, @@ -104,17 +140,15 @@ internal val MifosTypography = Typography( ), // Used for Button labelLarge = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Medium, - fontSize = 14.sp, + fontSize = 16.sp, lineHeight = 20.sp, letterSpacing = 0.1.sp, - lineHeightStyle = LineHeightStyle( - alignment = LineHeightStyle.Alignment.Center, - trim = LineHeightStyle.Trim.LastLineBottom, - ), ), // Used for Navigation items labelMedium = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Medium, fontSize = 12.sp, lineHeight = 16.sp, @@ -126,6 +160,7 @@ internal val MifosTypography = Typography( ), // Used for Tag labelSmall = TextStyle( + fontFamily = fontFamily(), fontWeight = FontWeight.Medium, fontSize = 10.sp, lineHeight = 14.sp, diff --git a/core/domain/src/commonMain/kotlin/org/mifospay/core/domain/LoginUseCase.kt b/core/domain/src/commonMain/kotlin/org/mifospay/core/domain/LoginUseCase.kt index 53eeea344..95fc90a4d 100644 --- a/core/domain/src/commonMain/kotlin/org/mifospay/core/domain/LoginUseCase.kt +++ b/core/domain/src/commonMain/kotlin/org/mifospay/core/domain/LoginUseCase.kt @@ -10,12 +10,11 @@ package org.mifospay.core.domain import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.withContext import org.mifospay.core.common.Result import org.mifospay.core.data.repository.AuthenticationRepository import org.mifospay.core.data.repository.ClientRepository import org.mifospay.core.datastore.UserPreferencesRepository -import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.user.UserInfo class LoginUseCase( private val repository: AuthenticationRepository, @@ -23,42 +22,44 @@ class LoginUseCase( private val userPreferencesRepository: UserPreferencesRepository, private val ioDispatcher: CoroutineDispatcher, ) { - suspend operator fun invoke(username: String, password: String): Result { + suspend operator fun invoke(username: String, password: String): Result { return when (val result = repository.authenticate(username, password)) { is Result.Loading -> Result.Loading is Result.Error -> Result.Error(Exception("Invalid credentials")) is Result.Success -> { - if (result.data.clients.isNotEmpty()) { - withContext(ioDispatcher) { - val userInfo = userPreferencesRepository.updateUserInfo(result.data) - when (userInfo) { - is Result.Success -> { - val clientInfo = - clientRepository.getClient(result.data.clients.first()) - - when (clientInfo) { - is Result.Success -> { - userPreferencesRepository.updateClientInfo(clientInfo.data) + if (result.data.clients.isEmpty()) { + return Result.Error(Exception("No clients found")) + } + updateUserInfo(result.data) + } + } + } - Result.Success(result.data) - } + private suspend fun updateUserInfo(userInfo: UserInfo): Result { + val updateResult = + userPreferencesRepository.updateToken(userInfo.base64EncodedAuthenticationKey) + return when (updateResult) { + is Result.Success -> updateClientInfo(userInfo) + is Result.Error -> Result.Error(Exception("Something went wrong")) + is Result.Loading -> Result.Loading + } + } - is Result.Error -> { - return@withContext Result.Error(Exception("No client found")) - } + private suspend fun updateClientInfo(userInfo: UserInfo): Result { + return when (val clientInfo = clientRepository.getClient(userInfo.clients.first())) { + is Result.Success -> { + userPreferencesRepository.updateClientInfo(clientInfo.data) + userPreferencesRepository.updateUserInfo(userInfo) - is Result.Loading -> Result.Loading - } - } + Result.Success(userInfo) + } - is Result.Error -> Result.Error(Exception("Something went wrong")) - is Result.Loading -> Result.Loading - } - } - } else { - Result.Error(Exception("No clients found")) - } + is Result.Error -> { + userPreferencesRepository.logOut() + Result.Error(Exception("No client found")) } + + is Result.Loading -> Result.Loading } } } diff --git a/core/model/build.gradle.kts b/core/model/build.gradle.kts index 8862c945a..a9a929e86 100644 --- a/core/model/build.gradle.kts +++ b/core/model/build.gradle.kts @@ -20,7 +20,7 @@ android { kotlin { sourceSets { commonMain.dependencies { - api(libs.kotlinx.datetime) + implementation(projects.core.common) implementation(libs.kotlinx.serialization.json) } } diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Account.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/account/Account.kt similarity index 71% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Account.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/account/Account.kt index a60910d53..7970d27da 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Account.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/account/Account.kt @@ -7,11 +7,13 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain +package org.mifospay.core.model.account -import kotlinx.serialization.Serializable +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize +import org.mifospay.core.model.savingsaccount.Currency -@Serializable +@Parcelize data class Account( val image: String = "", val name: String, @@ -20,4 +22,4 @@ data class Account( val id: Long = 0L, val productId: Long = 0L, val currency: Currency, -) +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NewAccount.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/account/NewAccount.kt similarity index 93% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NewAccount.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/account/NewAccount.kt index 54ce3f3ab..f24e7c7dc 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NewAccount.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/account/NewAccount.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain +package org.mifospay.core.model.account import kotlinx.datetime.LocalDate diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Bank.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/bank/Bank.kt similarity index 76% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Bank.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/bank/Bank.kt index 90778f5f9..caefece0f 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Bank.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/bank/Bank.kt @@ -7,13 +7,17 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain +package org.mifospay.core.model.bank +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize data class Bank( val name: String, val image: Int, val bankType: BankType = BankType.OTHER, -) +) : Parcelable enum class BankType { POPULAR, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/bank/BankAccountDetails.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/bank/BankAccountDetails.kt new file mode 100644 index 000000000..9d57090ca --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/bank/BankAccountDetails.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.bank + +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize +data class BankAccountDetails( + val bankName: String?, + val accountHolderName: String?, + val branch: String?, + val ifsc: String?, + val type: String?, + val isUpiEnabled: Boolean = false, + val upiPin: String?, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/AccountWithTransactions.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/AccountWithTransactions.kt new file mode 100644 index 000000000..b7d08db38 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/AccountWithTransactions.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.client + +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize +import org.mifospay.core.model.account.Account +import org.mifospay.core.model.savingsaccount.Transaction + +@Parcelize +data class AccountWithTransactions( + val account: Account, + val transactions: List, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/Client.kt similarity index 73% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/client/Client.kt index 6a9bf7701..b5b3cfe9d 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/Client.kt @@ -7,13 +7,17 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model +package org.mifospay.core.model.client -data class ClientInfo( +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize +data class Client( val name: String, val image: String, val externalId: String, val clientId: Long, val displayName: String, val mobileNo: String, -) +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/ClientAccount.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/ClientAccount.kt new file mode 100644 index 000000000..734c83bd5 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/ClientAccount.kt @@ -0,0 +1,16 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.client + +import org.mifospay.core.model.savingsaccount.SavingAccount + +data class ClientAccount( + val savingAccounts: List, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/ClientAddress.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/ClientAddress.kt new file mode 100644 index 000000000..758db66b9 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/ClientAddress.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.client + +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize +data class ClientAddress( + val addressLine1: String, + val addressLine2: String, + val postalCode: String, + val stateProvinceId: String, + val countryId: String, + val addressTypeId: Int = 805, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/NewClient.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/NewClient.kt new file mode 100644 index 000000000..fac3c47c9 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/client/NewClient.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.client + +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize +data class NewClient( + val firstname: String, + val lastname: String, + val externalId: String, + val mobileNo: String, + val address: ClientAddress, + val savingsProductId: Int, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/BankAccountDetails.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/BankAccountDetails.kt deleted file mode 100644 index 9ae668614..000000000 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/BankAccountDetails.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.model.domain - -import kotlinx.serialization.Serializable - -@Serializable -data class BankAccountDetails( - var bankName: String? = null, - var accountholderName: String? = null, - var branch: String? = null, - var ifsc: String? = null, - var type: String? = null, - var isUpiEnabled: Boolean = false, - var upiPin: String? = null, -) { - constructor() : this( - bankName = "", - accountholderName = "", - branch = "", - ifsc = "", - type = "", - isUpiEnabled = false, - upiPin = "", - ) -} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Transaction.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Transaction.kt deleted file mode 100644 index 9ed8063ae..000000000 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Transaction.kt +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.model.domain - -import kotlinx.serialization.Serializable -import org.mifospay.core.model.entity.accounts.savings.TransferDetail - -@Serializable -data class Transaction( - val transactionId: String? = null, - val clientId: Long = 0, - val accountId: Long = 0, - val amount: Double = 0.0, - val date: String? = null, - val currency: Currency = Currency(), - val transactionType: TransactionType = TransactionType.OTHER, - val transferId: Long = 0, - val transferDetail: TransferDetail = TransferDetail(), - val receiptId: String? = null, -) { - constructor() : this( - transactionId = "", - clientId = 0, - accountId = 0, - amount = 0.0, - date = "", - currency = Currency(), - transactionType = TransactionType.OTHER, - transferId = 0, - transferDetail = TransferDetail(), - receiptId = "", - ) -} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt deleted file mode 100644 index fe550e20b..000000000 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.model.domain.user - -import kotlinx.serialization.Serializable - -// Mandatory Fields -// username, firstname, lastname, email, officeId, roles, sendPasswordToEmail -// -// Optional Fields -// staffId,passwordNeverExpires,isSelfServiceUser,clients - -@Serializable -class NewUser( - val username: String, - val firstname: String, - val lastname: String, - val email: String, - val password: String, - val officeId: Int, - val roles: ArrayList, - val sendPasswordToEmail: Boolean, - val isSelfServiceUser: Boolean, - val repeatPassword: String, -) { - constructor( - username: String, - firstname: String, - lastname: String, - email: String, - password: String, - ) : this( - username = username, - firstname = firstname, - lastname = lastname, - email = email, - password = password, - officeId = OFFICE_ID, - roles = NEW_USER_ROLE_IDS, - sendPasswordToEmail = false, - isSelfServiceUser = true, - repeatPassword = password, - ) -} - -private const val OFFICE_ID = 1 -private const val MOBILE_WALLET_ROLE_ID = 2 -private const val SUPER_USER_ROLE_ID = 1 - -val NEW_USER_ROLE_IDS: ArrayList = arrayListOf(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingAccount.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingAccount.kt deleted file mode 100644 index 903579230..000000000 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingAccount.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.model.entity.accounts.savings - -import kotlinx.serialization.Serializable -import org.mifospay.core.model.entity.client.DepositType - -@Serializable -data class SavingAccount( - val id: Long = 0L, - val accountNo: String = "", - val productName: String = "", - val productId: Int = 0, - val overdraftLimit: Long = 0L, - val minRequiredBalance: Long = 0L, - val accountBalance: Double = 0.0, - val totalDeposits: Double = 0.0, - val savingsProductName: String? = null, - val clientName: String? = null, - val savingsProductId: String? = null, - val nominalAnnualInterestRate: Double = 0.0, - val status: Status? = null, - val currency: Currency = Currency(), - val depositType: DepositType? = null, -) { - fun isRecurring(): Boolean { - return this.depositType != null && this.depositType.isRecurring - } - - constructor() : this( - id = 0L, - accountNo = "", - productName = "", - productId = 0, - overdraftLimit = 0L, - minRequiredBalance = 0L, - accountBalance = 0.0, - totalDeposits = 0.0, - savingsProductName = "", - clientName = "", - savingsProductId = "", - nominalAnnualInterestRate = 0.0, - status = Status(), - currency = Currency(), - depositType = DepositType(), - ) -} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransferDetail.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransferDetail.kt deleted file mode 100644 index b236e99cc..000000000 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransferDetail.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.model.entity.accounts.savings - -import kotlinx.serialization.Serializable -import org.mifospay.core.model.domain.client.Client - -@Serializable -data class TransferDetail( - val id: Long = 0L, - val fromClient: Client = Client(), - val fromAccount: SavingAccount = SavingAccount(), - val toClient: Client = Client(), - val toAccount: SavingAccount = SavingAccount(), -) { - constructor() : this( - id = 0L, - fromClient = Client(), - fromAccount = SavingAccount(), - toClient = Client(), - toAccount = SavingAccount(), - ) -} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Currency.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Currency.kt similarity index 67% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Currency.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Currency.kt index d29ae7244..1c6c03392 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/Currency.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Currency.kt @@ -7,19 +7,14 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain +package org.mifospay.core.model.savingsaccount -import kotlinx.serialization.Serializable +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize -@Serializable +@Parcelize data class Currency( val code: String, val displaySymbol: String, val displayLabel: String, -) { - constructor() : this( - code = "", - displaySymbol = "", - displayLabel = "", - ) -} +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/DepositType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/DepositType.kt new file mode 100644 index 000000000..d78b7aa2c --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/DepositType.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.savingsaccount + +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize +data class DepositType( + val id: Int?, + val code: String?, + val value: String?, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/SavingAccount.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/SavingAccount.kt new file mode 100644 index 000000000..61a1d802e --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/SavingAccount.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.savingsaccount + +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize +data class SavingAccount( + val id: Long, + val accountNo: String, + val productName: String, + val productId: Int, + val overdraftLimit: Long, + val minRequiredBalance: Long, + val accountBalance: Double, + val totalDeposits: Double, + val savingsProductName: String?, + val clientName: String?, + val savingsProductId: String?, + val nominalAnnualInterestRate: Double, + val status: Status?, + val currency: Currency, + val depositType: DepositType?, + val isRecurring: Boolean, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Status.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Status.kt new file mode 100644 index 000000000..ac00755b5 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Status.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.savingsaccount + +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize +data class Status( + val id: Int?, + val code: String?, + val value: String?, + val submittedAndPendingApproval: Boolean?, + val approved: Boolean?, + val rejected: Boolean?, + val withdrawnByApplicant: Boolean?, + val active: Boolean?, + val closed: Boolean?, + val prematureClosed: Boolean?, + val transferInProgress: Boolean?, + val transferOnHold: Boolean?, + val matured: Boolean?, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Transaction.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Transaction.kt new file mode 100644 index 000000000..7e4fecc0b --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/Transaction.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.savingsaccount + +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize +data class Transaction( + val clientId: Long, + val accountId: Long, + val amount: Double, + val date: String, + val currency: Currency, + val transactionType: TransactionType, + val transactionId: String, + val transferId: Long, + val transferDetail: TransferDetail?, + val receiptId: String?, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/TransactionType.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/TransactionType.kt similarity index 89% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/TransactionType.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/TransactionType.kt index 314983835..9a79d2c16 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/TransactionType.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/TransactionType.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain +package org.mifospay.core.model.savingsaccount enum class TransactionType { DEBIT, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/TransferDetail.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/TransferDetail.kt new file mode 100644 index 000000000..2be865493 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/savingsaccount/TransferDetail.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.savingsaccount + +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize +import org.mifospay.core.model.client.Client + +@Parcelize +data class TransferDetail( + val id: Long, + val fromClient: Client, + val fromAccount: SavingAccount, + val toClient: Client, + val toAccount: SavingAccount, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/SearchResult.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/search/SearchResult.kt similarity index 52% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/SearchResult.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/search/SearchResult.kt index 889084dbc..e0f8c21cb 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/SearchResult.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/search/SearchResult.kt @@ -7,19 +7,17 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain +package org.mifospay.core.model.search -import kotlinx.serialization.Serializable +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize -@Serializable +@Parcelize data class SearchResult( - val resultId: Int = 0, - val resultName: String, - val resultType: String, -) { - constructor() : this( - resultId = 0, - resultName = "", - resultType = "", - ) -} + val entityId: Int, + val entityAccountNo: String, + val entityName: String, + val entityType: String, + val parentId: Int, + val parentName: String, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/SignupData.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/SignupData.kt deleted file mode 100644 index 9307c399a..000000000 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/SignupData.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.core.model.signup - -import kotlinx.serialization.Serializable - -@Serializable -data class SignupData( - val firstName: String? = null, - val lastName: String? = null, - val mobileNumber: String? = null, - val email: String? = null, - val userName: String? = null, - val password: String? = null, - val addressLine1: String? = null, - val addressLine2: String? = null, - val pinCode: String? = null, - val stateId: String? = null, - val businessName: String? = null, - val city: String? = null, - val countryName: String? = null, - val countryId: String? = null, - val mifosSavingsProductId: Int = 0, -) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/user/NewUser.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/user/NewUser.kt new file mode 100644 index 000000000..c204427c2 --- /dev/null +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/user/NewUser.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.model.user + +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize +class NewUser( + val username: String, + val firstname: String, + val lastname: String, + val email: String, + val password: String, +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/user/RoleInfo.kt similarity index 74% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/user/RoleInfo.kt index 224b9ad7a..c3f767bf3 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/user/RoleInfo.kt @@ -7,11 +7,15 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model +package org.mifospay.core.model.user +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize data class RoleInfo( val id: String, val name: String, val description: String, val disabled: Boolean, -) +) : Parcelable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/user/UserData.kt similarity index 85% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/user/UserData.kt index 93e6a2875..2555e8f4b 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/user/UserData.kt @@ -7,7 +7,9 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model +package org.mifospay.core.model.user + +import org.mifospay.core.model.client.Client data class UserData( val token: String, @@ -20,6 +22,6 @@ data class UserData( val clientVpa: String, val accountId: Int, val firebaseRegId: String, - val client: ClientInfo, + val client: Client, val user: UserInfo, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/user/UserInfo.kt similarity index 82% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt rename to core/model/src/commonMain/kotlin/org/mifospay/core/model/user/UserInfo.kt index 4045cbd42..717ad7df8 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/user/UserInfo.kt @@ -7,8 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model +package org.mifospay.core.model.user +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize + +@Parcelize data class UserInfo( val username: String, val userId: Long, @@ -21,4 +25,4 @@ data class UserInfo( val clients: List, val shouldRenewPassword: Boolean, val isTwoFactorAuthenticationRequired: Boolean, -) +) : Parcelable diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index 9f836460f..0c2f52597 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -1,13 +1,3 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ - /* * Copyright 2024 Mifos Initiative * @@ -40,9 +30,7 @@ android { kotlin { sourceSets { commonMain.dependencies { - api(libs.kotlinx.datetime) api(projects.core.common) - api(projects.core.model) implementation(projects.core.datastore) implementation(libs.kotlinx.serialization.json) implementation(libs.ktor.client.core) diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/FineractApiManager.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/FineractApiManager.kt index 8c89cdc72..388b1df68 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/FineractApiManager.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/FineractApiManager.kt @@ -9,72 +9,39 @@ */ package org.mifospay.core.network -import org.mifospay.core.network.services.AccountTransfersService -import org.mifospay.core.network.services.AuthenticationService -import org.mifospay.core.network.services.ClientService -import org.mifospay.core.network.services.DocumentService -import org.mifospay.core.network.services.InvoiceService -import org.mifospay.core.network.services.KYCLevel1Service -import org.mifospay.core.network.services.NotificationService -import org.mifospay.core.network.services.RegistrationService -import org.mifospay.core.network.services.RunReportService -import org.mifospay.core.network.services.SavedCardService -import org.mifospay.core.network.services.SavingsAccountsService -import org.mifospay.core.network.services.SearchService -import org.mifospay.core.network.services.StandingInstructionService -import org.mifospay.core.network.services.ThirdPartyTransferService -import org.mifospay.core.network.services.TwoFactorAuthService -import org.mifospay.core.network.services.UserService - class FineractApiManager( private val ktorfitClient: KtorfitClient, ) { - val authenticationApi: AuthenticationService - get() = ktorfitClient.authenticationApi + val authenticationApi by lazy { ktorfitClient.authenticationApi } - val clientsApi: ClientService - get() = ktorfitClient.clientsApi + val clientsApi by lazy { ktorfitClient.clientsApi } - val registrationAPi: RegistrationService - get() = ktorfitClient.registrationAPi + val registrationAPi by lazy { ktorfitClient.registrationAPi } - val searchApi: SearchService - get() = ktorfitClient.searchApi + val searchApi by lazy { ktorfitClient.searchApi } - val documentApi: DocumentService - get() = ktorfitClient.documentApi + val documentApi by lazy { ktorfitClient.documentApi } - val runReportApi: RunReportService - get() = ktorfitClient.runReportApi + val runReportApi by lazy { ktorfitClient.runReportApi } - val twoFactorAuthApi: TwoFactorAuthService - get() = ktorfitClient.twoFactorAuthApi + val twoFactorAuthApi by lazy { ktorfitClient.twoFactorAuthApi } - val accountTransfersApi: AccountTransfersService - get() = ktorfitClient.accountTransfersApi + val accountTransfersApi by lazy { ktorfitClient.accountTransfersApi } - val savedCardApi: SavedCardService - get() = ktorfitClient.savedCardApi + val savedCardApi by lazy { ktorfitClient.savedCardApi } - val kycLevel1Api: KYCLevel1Service - get() = ktorfitClient.kycLevel1Api + val kycLevel1Api by lazy { ktorfitClient.kycLevel1Api } - val invoiceApi: InvoiceService - get() = ktorfitClient.invoiceApi + val invoiceApi by lazy { ktorfitClient.invoiceApi } - val userApi: UserService - get() = ktorfitClient.userApi + val userApi by lazy { ktorfitClient.userApi } - val thirdPartyTransferApi: ThirdPartyTransferService - get() = ktorfitClient.thirdPartyTransferApi + val thirdPartyTransferApi by lazy { ktorfitClient.thirdPartyTransferApi } - val notificationApi: NotificationService - get() = ktorfitClient.notificationApi + val notificationApi by lazy { ktorfitClient.notificationApi } - val savingsAccountsApi: SavingsAccountsService - get() = ktorfitClient.savingsAccountsApi + val savingsAccountsApi by lazy { ktorfitClient.savingsAccountsApi } - val standingInstructionApi: StandingInstructionService - get() = ktorfitClient.standingInstructionApi + val standingInstructionApi by lazy { ktorfitClient.standingInstructionApi } } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt index a2349b14e..4df8740d7 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/SelfServiceApiManager.kt @@ -9,26 +9,18 @@ */ package org.mifospay.core.network -import org.mifospay.core.network.services.AuthenticationService -import org.mifospay.core.network.services.BeneficiaryService -import org.mifospay.core.network.services.ClientService -import org.mifospay.core.network.services.RegistrationService -import org.mifospay.core.network.services.SavingsAccountsService -import org.mifospay.core.network.services.ThirdPartyTransferService - class SelfServiceApiManager( private val ktorfitClient: KtorfitClient, ) { - val authenticationApi: AuthenticationService - get() = ktorfitClient.authenticationApi - val clientsApi: ClientService - get() = ktorfitClient.clientsApi - val savingAccountsListApi: SavingsAccountsService - get() = ktorfitClient.savingsAccountsApi - val registrationAPi: RegistrationService - get() = ktorfitClient.registrationAPi - val beneficiaryApi: BeneficiaryService - get() = ktorfitClient.beneficiaryApi - val thirdPartyTransferApi: ThirdPartyTransferService - get() = ktorfitClient.thirdPartyTransferApi + val authenticationApi by lazy { ktorfitClient.authenticationApi } + + val clientsApi by lazy { ktorfitClient.clientsApi } + + val savingAccountsListApi by lazy { ktorfitClient.savingsAccountsApi } + + val registrationAPi by lazy { ktorfitClient.registrationAPi } + + val beneficiaryApi by lazy { ktorfitClient.beneficiaryApi } + + val thirdPartyTransferApi by lazy { ktorfitClient.thirdPartyTransferApi } } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt index f5ff5d5dc..b703218c6 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt @@ -16,6 +16,7 @@ import io.ktor.client.plugins.auth.providers.basic import io.ktor.client.plugins.defaultRequest import io.ktor.client.request.header import org.koin.dsl.module +import org.mifospay.core.datastore.UserPreferencesRepository import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.KtorfitClient import org.mifospay.core.network.SelfServiceApiManager @@ -24,12 +25,13 @@ import org.mifospay.core.network.utils.BaseURL import org.mifospay.core.network.utils.KtorInterceptor val NetworkModule = module { - single(KtorClient) { + val preferencesRepository = get() + ktorHttpClient.config { install(Auth) install(KtorInterceptor) { - preferenceRepository = get() + getToken = { preferencesRepository.authToken } } } } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt index d884d5157..013c31d0f 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetDataSource.kt @@ -9,9 +9,9 @@ */ package org.mifospay.core.network.localAssets -import org.mifospay.core.model.City -import org.mifospay.core.model.Country -import org.mifospay.core.model.State +import org.mifospay.core.network.model.entity.signup.City +import org.mifospay.core.network.model.entity.signup.Country +import org.mifospay.core.network.model.entity.signup.State interface LocalAssetDataSource { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt index 417fc9810..59720fe96 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt @@ -11,9 +11,9 @@ package org.mifospay.core.network.localAssets import kotlinx.coroutines.CoroutineDispatcher import kotlinx.serialization.json.Json -import org.mifospay.core.model.City -import org.mifospay.core.model.Country -import org.mifospay.core.model.State +import org.mifospay.core.network.model.entity.signup.City +import org.mifospay.core.network.model.entity.signup.Country +import org.mifospay.core.network.model.entity.signup.State class MifosLocalAssetDataSource( private val ioDispatcher: CoroutineDispatcher, diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponse.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponseEntity.kt similarity index 93% rename from core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponse.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponseEntity.kt index 5fb91288a..c130d1f44 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponse.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponseEntity.kt @@ -12,7 +12,7 @@ package org.mifospay.core.network.model import kotlinx.serialization.Serializable @Serializable -data class ClientResponse( +data class ClientResponseEntity( val officeId: Int, val clientId: Int, val resourceId: Int, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NotificationPayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/NotificationPayload.kt similarity index 92% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NotificationPayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/NotificationPayload.kt index 1520e7413..38f8902e6 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/NotificationPayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/NotificationPayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain +package org.mifospay.core.network.model import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Invoice.kt similarity index 95% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Invoice.kt index f14092bf9..2810e21f3 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Invoice.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Invoice.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity +package org.mifospay.core.network.model.entity import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Page.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Page.kt similarity index 91% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Page.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Page.kt index 4e24e6354..ecda6cc4e 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Page.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Page.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity +package org.mifospay.core.network.model.entity import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Role.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Role.kt similarity index 91% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Role.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Role.kt index bd22ef392..4b48d9112 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Role.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Role.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity +package org.mifospay.core.network.model.entity import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/SearchedEntity.kt similarity index 92% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/SearchedEntity.kt index 4775b6f5e..498979203 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/SearchedEntity.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity +package org.mifospay.core.network.model.entity import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/TPTResponse.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/TPTResponse.kt similarity index 91% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/TPTResponse.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/TPTResponse.kt index 621b95a86..bc67132ac 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/TPTResponse.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/TPTResponse.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity +package org.mifospay.core.network.model.entity import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Timeline.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Timeline.kt similarity index 96% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Timeline.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Timeline.kt index 968d2a3e0..1fe17d368 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/Timeline.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/Timeline.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity +package org.mifospay.core.network.model.entity import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserEntity.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/UserEntity.kt similarity index 94% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserEntity.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/UserEntity.kt index 65ab8bfd6..30381ca4e 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserEntity.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/UserEntity.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity +package org.mifospay.core.network.model.entity import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserWithRole.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/UserWithRole.kt similarity index 92% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserWithRole.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/UserWithRole.kt index c5b3404f0..100a6941d 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/UserWithRole.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/UserWithRole.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity +package org.mifospay.core.network.model.entity import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/SavingAccountsListResponse.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/SavingAccountsListResponse.kt similarity index 70% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/SavingAccountsListResponse.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/SavingAccountsListResponse.kt index 4887472a2..c8496b02c 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/SavingAccountsListResponse.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/SavingAccountsListResponse.kt @@ -7,12 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts +package org.mifospay.core.network.model.entity.accounts import kotlinx.serialization.Serializable -import org.mifospay.core.model.entity.accounts.savings.SavingAccount @Serializable data class SavingAccountsListResponse( - var savingsAccounts: List = ArrayList(), + var savingsAccounts: List = ArrayList(), ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/CurrencyEntity.kt similarity index 89% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/CurrencyEntity.kt index abc0bc9ae..d15b53f95 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Currency.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/CurrencyEntity.kt @@ -7,12 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.network.model.entity.accounts.savings import kotlinx.serialization.Serializable @Serializable -data class Currency( +data class CurrencyEntity( val code: String = "", val name: String = "", val decimalPlaces: Int? = null, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/PaymentDetailData.kt similarity index 83% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/PaymentDetailData.kt index f8f175073..e5531fe70 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentDetailData.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/PaymentDetailData.kt @@ -7,14 +7,14 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.network.model.entity.accounts.savings import kotlinx.serialization.Serializable @Serializable data class PaymentDetailData( val id: Int? = null, - val paymentType: PaymentType? = null, + val paymentType: org.mifospay.core.network.model.entity.accounts.savings.PaymentType? = null, val accountNumber: String? = null, val checkNumber: String? = null, val routingCode: String? = null, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentType.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/PaymentType.kt similarity index 88% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentType.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/PaymentType.kt index 3318b0fb9..718708d0f 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/PaymentType.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/PaymentType.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.network.model.entity.accounts.savings import kotlinx.serialization.Serializable diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/SavingAccountEntity.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/SavingAccountEntity.kt new file mode 100644 index 000000000..018a4eca9 --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/SavingAccountEntity.kt @@ -0,0 +1,106 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.model.entity.accounts.savings + +import kotlinx.serialization.Serializable +import org.mifospay.core.network.model.entity.client.DepositTypeEntity +import org.mifospay.core.network.model.entity.templates.account.AccountType + +@Serializable +data class SavingAccountEntity( + val id: Long = 0L, + val accountNo: String = "", + val productName: String = "", + val productId: Int = 0, + val overdraftLimit: Long = 0L, + val minRequiredBalance: Long = 0L, + val accountBalance: Double = 0.0, + val totalDeposits: Double = 0.0, + val savingsProductName: String? = null, + val clientName: String? = null, + val savingsProductId: String? = null, + val nominalAnnualInterestRate: Double = 0.0, + val status: StatusEntity? = null, + val currency: CurrencyEntity = CurrencyEntity(), + val depositType: DepositTypeEntity? = null, + val shortProductName: String? = null, + val accountType: AccountType = AccountType(), + val timeline: TimelineEntity = TimelineEntity(), + val subStatus: SubStatus = SubStatus(), + val lastActiveTransactionDate: List = emptyList(), + val externalId: String? = null, +) { + fun isRecurring(): Boolean { + return this.depositType != null && this.depositType.isRecurring + } + + constructor() : this( + id = 0L, + accountNo = "", + productName = "", + productId = 0, + overdraftLimit = 0L, + minRequiredBalance = 0L, + accountBalance = 0.0, + totalDeposits = 0.0, + savingsProductName = "", + clientName = "", + savingsProductId = "", + nominalAnnualInterestRate = 0.0, + status = StatusEntity(), + currency = CurrencyEntity(), + depositType = DepositTypeEntity(), + shortProductName = "", + accountType = AccountType(), + timeline = TimelineEntity(), + subStatus = SubStatus(), + lastActiveTransactionDate = emptyList(), + ) +} + +@Serializable +data class SubStatus( + val id: Long, + val code: String, + val value: String, + val none: Boolean, + val inactive: Boolean, + val dormant: Boolean, + val escheat: Boolean, + val block: Boolean, + val blockCredit: Boolean, + val blockDebit: Boolean, +) { + constructor() : this( + id = 0L, + code = "", + value = "", + none = false, + inactive = false, + dormant = false, + escheat = false, + block = false, + blockCredit = false, + blockDebit = false, + ) +} + +@Serializable +data class TimelineEntity( + val submittedOnDate: List = emptyList(), + val submittedByUsername: String? = null, + val submittedByFirstname: String? = null, + val submittedByLastname: String? = null, + val approvedOnDate: List = emptyList(), + val approvedByUsername: String? = null, + val approvedByFirstname: String? = null, + val approvedByLastname: String? = null, + val activatedOnDate: List = emptyList(), +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociationsEntity.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/SavingsWithAssociationsEntity.kt similarity index 57% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociationsEntity.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/SavingsWithAssociationsEntity.kt index 5e4f55c7c..4e60200f6 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/SavingsWithAssociationsEntity.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/SavingsWithAssociationsEntity.kt @@ -7,36 +7,44 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.network.model.entity.accounts.savings -import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.mifospay.core.model.entity.client.DepositType +import org.mifospay.core.network.model.entity.client.DepositTypeEntity @Serializable data class SavingsWithAssociationsEntity( val id: Long = 0L, val accountNo: String? = null, - val depositType: DepositType? = null, - val externalId: String = "", + val depositType: DepositTypeEntity? = null, val clientId: Int = 0, val clientName: String = "", val savingsProductId: Int? = null, val savingsProductName: String? = null, val fieldOfficerId: Int? = null, - val status: Status? = null, + val status: StatusEntity? = null, val timeline: TimeLine? = null, - val currency: Currency? = null, + val currency: CurrencyEntity? = null, val nominalAnnualInterestRate: Double? = null, - val minRequiredOpeningBalance: Double? = null, - val lockinPeriodFrequency: Double? = null, val withdrawalFeeForTransfers: Boolean? = null, val allowOverdraft: Boolean? = null, val enforceMinRequiredBalance: Boolean? = null, val withHoldTax: Boolean? = null, val lastActiveTransactionDate: List? = null, - @SerialName("isDormancyTrackingActive") - val dormancyTrackingActive: Boolean? = null, val summary: Summary? = null, val transactions: List = ArrayList(), + val subStatus: SubStatus = SubStatus(), + val interestCompoundingPeriodType: InterestPeriod = InterestPeriod(), + val interestPostingPeriodType: InterestPeriod = InterestPeriod(), + val interestCalculationType: InterestPeriod = InterestPeriod(), + val interestCalculationDaysInYearType: InterestPeriod = InterestPeriod(), + val lienAllowed: Boolean = false, + val isDormancyTrackingActive: Boolean = false, +) + +@Serializable +data class InterestPeriod( + val id: Long = 0, + val code: String = "", + val value: String = "", ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Status.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/StatusEntity.kt similarity index 93% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Status.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/StatusEntity.kt index cb2fdf8ca..eacfa7ca7 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Status.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/StatusEntity.kt @@ -7,12 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.network.model.entity.accounts.savings import kotlinx.serialization.Serializable @Serializable -data class Status( +data class StatusEntity( val id: Int? = null, val code: String? = null, val value: String? = null, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Summary.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/Summary.kt similarity index 82% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Summary.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/Summary.kt index 96852b986..194f2e391 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Summary.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/Summary.kt @@ -7,13 +7,13 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.network.model.entity.accounts.savings import kotlinx.serialization.Serializable @Serializable data class Summary( - val currency: Currency? = null, + val currency: org.mifospay.core.network.model.entity.accounts.savings.CurrencyEntity? = null, val totalDeposits: Double? = null, val totalWithdrawals: Double? = null, val totalInterestEarned: Double? = null, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TimeLine.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TimeLine.kt similarity index 95% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TimeLine.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TimeLine.kt index 3aff25db6..22c94a461 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TimeLine.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TimeLine.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.network.model.entity.accounts.savings import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TransactionType.kt similarity index 94% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TransactionType.kt index 975a3018d..81c623fa0 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionType.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TransactionType.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.network.model.entity.accounts.savings import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionsEntity.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TransactionsEntity.kt similarity index 90% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionsEntity.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TransactionsEntity.kt index 6407fcf72..6d00a0677 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/TransactionsEntity.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TransactionsEntity.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.network.model.entity.accounts.savings import kotlinx.serialization.Serializable @@ -19,7 +19,7 @@ data class TransactionsEntity( val accountId: Int? = null, val accountNo: String? = null, val date: List = ArrayList(), - val currency: Currency = Currency(), + val currency: CurrencyEntity = CurrencyEntity(), val paymentDetailData: PaymentDetailData? = null, val amount: Double = 0.0, val runningBalance: Double? = null, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transfer.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/Transfer.kt similarity index 87% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transfer.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/Transfer.kt index e5c5a878e..e00e68989 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/accounts/savings/Transfer.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/Transfer.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.accounts.savings +package org.mifospay.core.network.model.entity.accounts.savings import kotlinx.serialization.Serializable diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TransferDetailEntity.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TransferDetailEntity.kt new file mode 100644 index 000000000..c3b4a8c70 --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/accounts/savings/TransferDetailEntity.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.model.entity.accounts.savings + +import kotlinx.serialization.Serializable +import org.mifospay.core.network.model.entity.client.ClientEntity + +@Serializable +data class TransferDetailEntity( + val id: Long = 0L, + val fromClient: ClientEntity = ClientEntity(), + val fromAccount: SavingAccountEntity = SavingAccountEntity(), + val toClient: ClientEntity = ClientEntity(), + val toAccount: SavingAccountEntity = SavingAccountEntity(), +) { + constructor() : this( + id = 0L, + fromClient = ClientEntity(), + fromAccount = SavingAccountEntity(), + toClient = ClientEntity(), + toAccount = SavingAccountEntity(), + ) +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/authentication/AuthenticationPayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/authentication/AuthenticationPayload.kt similarity index 88% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/authentication/AuthenticationPayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/authentication/AuthenticationPayload.kt index c96c77306..687f7f2a3 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/authentication/AuthenticationPayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/authentication/AuthenticationPayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.authentication +package org.mifospay.core.network.model.entity.authentication import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/Beneficiary.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/beneficary/Beneficiary.kt similarity index 72% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/Beneficiary.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/beneficary/Beneficiary.kt index 50a4b3466..da8b1f57f 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/Beneficiary.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/beneficary/Beneficiary.kt @@ -7,10 +7,10 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.beneficary +package org.mifospay.core.network.model.entity.beneficary import kotlinx.serialization.Serializable -import org.mifospay.core.model.entity.templates.account.AccountType +import org.mifospay.core.network.model.entity.templates.account.AccountType @Serializable data class Beneficiary( @@ -18,7 +18,7 @@ data class Beneficiary( val name: String? = null, val officeName: String? = null, val clientName: String? = null, - val accountType: AccountType? = null, + val accountType: org.mifospay.core.network.model.entity.templates.account.AccountType? = null, val accountNumber: String? = null, val transferLimit: Int = 0, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/beneficary/BeneficiaryPayload.kt similarity index 93% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/beneficary/BeneficiaryPayload.kt index ca8c3ebd7..970ddef75 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryPayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/beneficary/BeneficiaryPayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.beneficary +package org.mifospay.core.network.model.entity.beneficary import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryUpdatePayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/beneficary/BeneficiaryUpdatePayload.kt similarity index 89% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryUpdatePayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/beneficary/BeneficiaryUpdatePayload.kt index 35c2e6e1e..155ac3643 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/beneficary/BeneficiaryUpdatePayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/beneficary/BeneficiaryUpdatePayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.beneficary +package org.mifospay.core.network.model.entity.beneficary import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientAccounts.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/ClientAccountsEntity.kt similarity index 53% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientAccounts.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/ClientAccountsEntity.kt index 355155ab5..db6ce275d 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientAccounts.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/ClientAccountsEntity.kt @@ -7,28 +7,30 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.client +package org.mifospay.core.network.model.entity.client import kotlinx.serialization.Serializable -import org.mifospay.core.model.entity.accounts.savings.SavingAccount +import org.mifospay.core.network.model.entity.accounts.savings.SavingAccountEntity @Serializable -data class ClientAccounts( - var savingsAccounts: List = ArrayList(), +data class ClientAccountsEntity( + var savingsAccounts: List = emptyList(), + val groupLoanIndividualMonitoringAccounts: List = emptyList(), + val guarantorAccounts: List = emptyList(), ) { - fun withSavingsAccounts(savingsAccounts: List): ClientAccounts { + fun withSavingsAccounts(savingsAccounts: List): ClientAccountsEntity { this.savingsAccounts = savingsAccounts return this } - val recurringSavingsAccounts: List + val recurringSavingsAccounts: List get() = getSavingsAccounts(true) - val nonRecurringSavingsAccounts: List + val nonRecurringSavingsAccounts: List get() = getSavingsAccounts(false) - private fun getSavingsAccounts(wantRecurring: Boolean): List { - val result: MutableList = ArrayList() + private fun getSavingsAccounts(wantRecurring: Boolean): List { + val result: MutableList = ArrayList() for (account in savingsAccounts) { if (account.isRecurring() == wantRecurring) { result.add(account) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientEntity.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/ClientEntity.kt similarity index 89% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientEntity.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/ClientEntity.kt index a0e9915b2..4a74a4718 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/ClientEntity.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/ClientEntity.kt @@ -7,11 +7,10 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.client +package org.mifospay.core.network.model.entity.client import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import org.mifospay.core.model.entity.Timeline @Serializable data class ClientEntity( @@ -30,7 +29,7 @@ data class ClientEntity( val officeName: String? = null, val staffId: Int? = null, val staffName: String? = null, - val timeline: Timeline? = null, + val timeline: org.mifospay.core.network.model.entity.Timeline? = null, val imageId: Int = 0, @SerialName("imagePresent") val isImagePresent: Boolean = false, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Currency.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/Currency.kt similarity index 93% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Currency.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/Currency.kt index d1293d618..25090b732 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Currency.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/Currency.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.client +package org.mifospay.core.network.model.entity.client import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/DepositTypeEntity.kt similarity index 83% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/DepositTypeEntity.kt index 2ef4b138f..bab9669bf 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/DepositType.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/DepositTypeEntity.kt @@ -7,12 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.client +package org.mifospay.core.network.model.entity.client import kotlinx.serialization.Serializable @Serializable -data class DepositType( +data class DepositTypeEntity( val id: Int? = null, val code: String? = null, val value: String? = null, @@ -20,9 +20,13 @@ data class DepositType( val isRecurring: Boolean get() = ServerTypes.RECURRING.id == id val endpoint: String - get() = ServerTypes.fromId(id!!).endpoint + get() = ServerTypes.fromId( + id!!, + ).endpoint val serverType: ServerTypes - get() = ServerTypes.fromId(id!!) + get() = ServerTypes.fromId( + id!!, + ) enum class ServerTypes(val id: Int, val code: String, val endpoint: String) { SAVINGS(id = 100, code = "depositAccountType.savingsDeposit", endpoint = "savingsaccounts"), @@ -41,7 +45,7 @@ data class DepositType( return type } } - return SAVINGS + return ServerTypes.SAVINGS } } } diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/NewClientEntity.kt similarity index 92% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/NewClientEntity.kt index dd79fd813..6dd862574 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/NewClient.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/NewClientEntity.kt @@ -7,13 +7,13 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain.client +package org.mifospay.core.network.model.entity.client import kotlinx.serialization.Serializable -import org.mifospay.core.model.utils.DateHelper +import org.mifospay.core.common.DateHelper @Serializable -data class NewClient( +data class NewClientEntity( val firstname: String, val lastname: String, val externalId: String, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Status.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/Status.kt similarity index 91% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Status.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/Status.kt index ae033b9ff..2b0819d12 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Status.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/Status.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.client +package org.mifospay.core.network.model.entity.client import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Type.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/Type.kt similarity index 89% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Type.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/Type.kt index 18243c23d..77950f4da 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/client/Type.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/Type.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.client +package org.mifospay.core.network.model.entity.client import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/UpdateClientEntityMobile.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/UpdateClientEntityMobile.kt similarity index 87% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/UpdateClientEntityMobile.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/UpdateClientEntityMobile.kt index f7087edd4..651a2962d 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/UpdateClientEntityMobile.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/client/UpdateClientEntityMobile.kt @@ -7,6 +7,6 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain.client +package org.mifospay.core.network.model.entity.client data class UpdateClientEntityMobile(val mobileNo: String) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/kyc/KYCLevel1Details.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/kyc/KYCLevel1Details.kt similarity index 92% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/kyc/KYCLevel1Details.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/kyc/KYCLevel1Details.kt index 4327b2389..411111bdf 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/kyc/KYCLevel1Details.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/kyc/KYCLevel1Details.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.kyc +package org.mifospay.core.network.model.entity.kyc import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/noncore/Document.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/noncore/Document.kt similarity index 92% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/noncore/Document.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/noncore/Document.kt index 1f2d63b78..d80599c06 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/noncore/Document.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/noncore/Document.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.noncore +package org.mifospay.core.network.model.entity.noncore import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/ClientPayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/ClientPayload.kt similarity index 86% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/ClientPayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/ClientPayload.kt index 5fbc50c73..f67b18b27 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/ClientPayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/ClientPayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.payload +package org.mifospay.core.network.model.entity.payload import kotlinx.serialization.Serializable @@ -29,5 +29,5 @@ data class ClientPayload( val clientClassificationId: Int? = null, val dateFormat: String? = "DD_MMMM_YYYY", val locale: String? = "en", - val datatables: List = ArrayList(), + val datatables: List = ArrayList(), ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/DataTablePayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/DataTablePayload.kt similarity index 93% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/DataTablePayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/DataTablePayload.kt index 427258782..993a087c4 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/DataTablePayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/DataTablePayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.payload +package org.mifospay.core.network.model.entity.payload import kotlinx.serialization.Serializable import kotlinx.serialization.Transient diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayPayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/PayPayload.kt similarity index 91% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayPayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/PayPayload.kt index 6bd61d55c..63ff10353 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayPayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/PayPayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.payload +package org.mifospay.core.network.model.entity.payload import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayResponse.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/PayResponse.kt similarity index 81% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayResponse.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/PayResponse.kt index 11ce8f688..5ab543171 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/PayResponse.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/PayResponse.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.payload +package org.mifospay.core.network.model.entity.payload import kotlinx.serialization.Serializable @@ -17,7 +17,7 @@ data class PayResponse( val clientId: Int, val savingsId: Int, val resourceId: Int, - val changes: Change, + val changes: org.mifospay.core.network.model.entity.payload.Change, ) @Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/StandingInstructionPayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/StandingInstructionPayload.kt similarity index 95% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/StandingInstructionPayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/StandingInstructionPayload.kt index cf568f61f..3519215d0 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/StandingInstructionPayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/StandingInstructionPayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.payload +package org.mifospay.core.network.model.entity.payload import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/TransferPayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/TransferPayload.kt similarity index 95% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/TransferPayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/TransferPayload.kt index f10e40638..a3cafee18 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/TransferPayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/TransferPayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.payload +package org.mifospay.core.network.model.entity.payload import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/UpdateVpaPayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/UpdateVpaPayload.kt similarity index 89% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/UpdateVpaPayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/UpdateVpaPayload.kt index 1bb8e906f..edc93ade6 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/payload/UpdateVpaPayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/payload/UpdateVpaPayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.payload +package org.mifospay.core.network.model.entity.payload import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/RegisterPayload.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/register/RegisterPayload.kt similarity index 92% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/RegisterPayload.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/register/RegisterPayload.kt index 11c8ad663..37e572314 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/RegisterPayload.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/register/RegisterPayload.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.register +package org.mifospay.core.network.model.entity.register import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/UserVerify.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/register/UserVerify.kt similarity index 89% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/UserVerify.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/register/UserVerify.kt index 8e97fffe0..ae775b651 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/register/UserVerify.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/register/UserVerify.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.register +package org.mifospay.core.network.model.entity.register import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/savedcards/Card.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/savedcards/Card.kt similarity index 90% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/savedcards/Card.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/savedcards/Card.kt index 094749765..50f8f28d1 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/savedcards/Card.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/savedcards/Card.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.savedcards +package org.mifospay.core.network.model.entity.savedcards import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/City.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup/City.kt similarity index 90% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/City.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup/City.kt index 8d3d0cb96..027c4bc37 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/City.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup/City.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model +package org.mifospay.core.network.model.entity.signup import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/Country.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup/Country.kt similarity index 89% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/Country.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup/Country.kt index c1e079fba..d7c03f6ef 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/Country.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup/Country.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model +package org.mifospay.core.network.model.entity.signup import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/State.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup/State.kt similarity index 90% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/State.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup/State.kt index 24b8a4c70..89984d428 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/State.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/signup/State.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model +package org.mifospay.core.network.model.entity.signup import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/SDIResponse.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/standinginstruction/SDIResponse.kt similarity index 87% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/SDIResponse.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/standinginstruction/SDIResponse.kt index a10d64f2f..b5e8ab857 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/SDIResponse.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/standinginstruction/SDIResponse.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.standinginstruction +package org.mifospay.core.network.model.entity.standinginstruction import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/standinginstruction/StandingInstruction.kt similarity index 55% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/standinginstruction/StandingInstruction.kt index 874762bcd..5db037f92 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/standinginstruction/StandingInstruction.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/standinginstruction/StandingInstruction.kt @@ -7,22 +7,19 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.standinginstruction +package org.mifospay.core.network.model.entity.standinginstruction import kotlinx.serialization.Serializable -import org.mifospay.core.model.entity.accounts.savings.SavingAccount -import org.mifospay.core.model.entity.client.ClientEntity -import org.mifospay.core.model.entity.client.Status @Serializable data class StandingInstruction( val id: Long, val name: String, - val fromClient: ClientEntity, - val fromAccount: SavingAccount, - val toClient: ClientEntity, - val toAccount: SavingAccount, - val status: Status, + val fromClient: org.mifospay.core.network.model.entity.client.ClientEntity, + val fromAccount: org.mifospay.core.network.model.entity.accounts.savings.SavingAccountEntity, + val toClient: org.mifospay.core.network.model.entity.client.ClientEntity, + val toAccount: org.mifospay.core.network.model.entity.accounts.savings.SavingAccountEntity, + val status: org.mifospay.core.network.model.entity.client.Status, val amount: Double, val validFrom: List, val validTill: List?, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOption.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/account/AccountOption.kt similarity index 78% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOption.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/account/AccountOption.kt index 1bbf350ed..0741583b7 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOption.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/account/AccountOption.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.templates.account +package org.mifospay.core.network.model.entity.templates.account import kotlinx.serialization.Serializable @@ -15,7 +15,7 @@ import kotlinx.serialization.Serializable data class AccountOption( val accountId: Int? = null, val accountNo: String? = null, - val accountType: AccountType? = null, + val accountType: org.mifospay.core.network.model.entity.templates.account.AccountType? = null, val clientId: Long? = null, val clientName: String? = null, val officeId: Int? = null, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/account/AccountOptionsTemplate.kt similarity index 58% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/account/AccountOptionsTemplate.kt index 17afff35c..65b4456a8 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountOptionsTemplate.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/account/AccountOptionsTemplate.kt @@ -7,12 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.templates.account +package org.mifospay.core.network.model.entity.templates.account import kotlinx.serialization.Serializable @Serializable data class AccountOptionsTemplate( - val fromAccountOptions: List? = listOf(), - val toAccountOptions: List? = listOf(), + val fromAccountOptions: List? = listOf(), + val toAccountOptions: List? = listOf(), ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/account/AccountType.kt similarity index 88% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/account/AccountType.kt index e9eab35bd..2b4f3dc75 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/account/AccountType.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/account/AccountType.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.templates.account +package org.mifospay.core.network.model.entity.templates.account import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/beneficiary/AccountTypeOption.kt similarity index 87% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/beneficiary/AccountTypeOption.kt index bd537a5a0..00733f0e9 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/AccountTypeOption.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/beneficiary/AccountTypeOption.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.templates.beneficiary +package org.mifospay.core.network.model.entity.templates.beneficiary import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/beneficiary/BeneficiaryTemplate.kt similarity index 68% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/beneficiary/BeneficiaryTemplate.kt index 962bebc05..9d50bda1f 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/templates/beneficiary/BeneficiaryTemplate.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/templates/beneficiary/BeneficiaryTemplate.kt @@ -7,11 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.entity.templates.beneficiary +package org.mifospay.core.network.model.entity.templates.beneficiary import kotlinx.serialization.Serializable @Serializable data class BeneficiaryTemplate( - val accountTypeOptions: List? = null, + val accountTypeOptions: List? = null, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/NewUserEntity.kt similarity index 51% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/NewUserEntity.kt index 151fd5a2e..9085115d0 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/client/Client.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/NewUserEntity.kt @@ -7,16 +7,20 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain.client +package org.mifospay.core.network.model.entity.user import kotlinx.serialization.Serializable @Serializable -data class Client( - val name: String? = null, - val image: String? = null, - val externalId: String? = null, - val clientId: Long = 0L, - val displayName: String? = null, - val mobileNo: String? = null, +class NewUserEntity( + val username: String, + val firstname: String, + val lastname: String, + val email: String, + val password: String, + val officeId: Int, + val roles: ArrayList, + val sendPasswordToEmail: Boolean, + val isSelfServiceUser: Boolean, + val repeatPassword: String, ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityClients.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/UpdateUserEntityClients.kt similarity index 89% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityClients.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/UpdateUserEntityClients.kt index 0748b9978..1a39f356b 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityClients.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/UpdateUserEntityClients.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain.user +package org.mifospay.core.network.model.entity.user import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityEmail.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/UpdateUserEntityEmail.kt similarity index 89% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityEmail.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/UpdateUserEntityEmail.kt index 2231efd18..acde42e19 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityEmail.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/UpdateUserEntityEmail.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain.user +package org.mifospay.core.network.model.entity.user import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityPassword.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/UpdateUserEntityPassword.kt similarity index 90% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityPassword.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/UpdateUserEntityPassword.kt index 8a4b3d42f..bf4bdb29c 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/UpdateUserEntityPassword.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/UpdateUserEntityPassword.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain.user +package org.mifospay.core.network.model.entity.user import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/User.kt similarity index 88% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/User.kt index 0d45ba07c..1792e2dad 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/entity/user/User.kt @@ -7,10 +7,10 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain.user +package org.mifospay.core.network.model.entity.user import kotlinx.serialization.Serializable -import org.mifospay.core.model.entity.Role +import org.mifospay.core.network.model.entity.Role @Serializable data class User( diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/AccessToken.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/twofactor/AccessToken.kt similarity index 90% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/AccessToken.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/twofactor/AccessToken.kt index 0d24b0b22..60b6ee552 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/AccessToken.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/twofactor/AccessToken.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain.twofactor +package org.mifospay.core.network.model.twofactor import kotlinx.serialization.Serializable diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/DeliveryMethod.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/twofactor/DeliveryMethod.kt similarity index 90% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/DeliveryMethod.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/twofactor/DeliveryMethod.kt index 320fffdae..ec6ded9c6 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/twofactor/DeliveryMethod.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/twofactor/DeliveryMethod.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.domain.twofactor +package org.mifospay.core.network.model.twofactor import kotlinx.serialization.Serializable diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt index b5e7ae1ce..0aad33963 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt @@ -12,7 +12,7 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.entity.accounts.savings.TransferDetail +import org.mifospay.core.network.model.entity.accounts.savings.TransferDetailEntity import org.mifospay.core.network.utils.ApiEndPoints /** @@ -20,5 +20,5 @@ import org.mifospay.core.network.utils.ApiEndPoints */ interface AccountTransfersService { @GET(ApiEndPoints.ACCOUNT_TRANSFER + "/{transferId}") - suspend fun getAccountTransfer(@Path("transferId") transferId: Long): Flow + suspend fun getAccountTransfer(@Path("transferId") transferId: Long): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt index 4c23736ef..7637a8237 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt @@ -11,8 +11,8 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.POST -import org.mifospay.core.model.domain.user.User -import org.mifospay.core.model.entity.authentication.AuthenticationPayload +import org.mifospay.core.network.model.entity.authentication.AuthenticationPayload +import org.mifospay.core.network.model.entity.user.User import org.mifospay.core.network.utils.ApiEndPoints interface AuthenticationService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt index c06628a2a..8723689ff 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt @@ -16,11 +16,11 @@ import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.entity.beneficary.Beneficiary -import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload -import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload -import org.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate import org.mifospay.core.network.model.CommonResponse +import org.mifospay.core.network.model.entity.beneficary.Beneficiary +import org.mifospay.core.network.model.entity.beneficary.BeneficiaryPayload +import org.mifospay.core.network.model.entity.beneficary.BeneficiaryUpdatePayload +import org.mifospay.core.network.model.entity.templates.beneficiary.BeneficiaryTemplate import org.mifospay.core.network.utils.ApiEndPoints interface BeneficiaryService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt index f32e8b422..416cfb737 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt @@ -18,11 +18,11 @@ import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import de.jensklingenberg.ktorfit.http.Query import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.domain.client.NewClient -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.client.ClientAccounts -import org.mifospay.core.model.entity.client.ClientEntity -import org.mifospay.core.network.model.ClientResponse +import org.mifospay.core.network.model.ClientResponseEntity +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.client.ClientAccountsEntity +import org.mifospay.core.network.model.entity.client.ClientEntity +import org.mifospay.core.network.model.entity.client.NewClientEntity import org.mifospay.core.network.utils.ApiEndPoints interface ClientService { @@ -49,17 +49,17 @@ interface ClientService { ): Flow @GET(ApiEndPoints.CLIENTS + "/{clientId}/accounts") - suspend fun getClientAccounts(@Path("clientId") clientId: Long): Flow + suspend fun getClientAccounts(@Path("clientId") clientId: Long): Flow @GET(ApiEndPoints.CLIENTS + "/{clientId}/accounts") suspend fun getAccounts( @Path("clientId") clientId: Long, @Query("fields") accountType: String, - ): Flow + ): ClientAccountsEntity @POST(ApiEndPoints.CLIENTS) - suspend fun createClient(@Body newClient: NewClient): ClientResponse + suspend fun createClient(@Body newClient: NewClientEntity): ClientResponseEntity @DELETE(ApiEndPoints.CLIENTS + "/{clientId}") - suspend fun deleteClient(@Path("clientId") clientId: Int): ClientResponse + suspend fun deleteClient(@Path("clientId") clientId: Int): ClientResponseEntity } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt index b605ad4e0..62f47b915 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt @@ -18,7 +18,7 @@ import de.jensklingenberg.ktorfit.http.Part import de.jensklingenberg.ktorfit.http.Path import io.ktor.http.content.PartData import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.entity.noncore.Document +import org.mifospay.core.network.model.entity.noncore.Document import org.mifospay.core.network.utils.ApiEndPoints interface DocumentService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt index 94ac56fff..65f998250 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt @@ -16,8 +16,8 @@ import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.entity.Invoice import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.Invoice import org.mifospay.core.network.utils.ApiEndPoints // TODO:: Fix this endpoints, there's no such endpoint for invoices diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt index 538863215..bda3168ed 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt @@ -15,8 +15,8 @@ import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.kyc.KYCLevel1Details import org.mifospay.core.network.utils.ApiEndPoints interface KYCLevel1Service { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt index a19c37df6..cd8cd53ae 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt @@ -12,7 +12,7 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.domain.NotificationPayload +import org.mifospay.core.network.model.NotificationPayload import org.mifospay.core.network.utils.ApiEndPoints interface NotificationService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt index f93f575f4..7f583c133 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt @@ -11,8 +11,8 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.POST -import org.mifospay.core.model.entity.register.RegisterPayload -import org.mifospay.core.model.entity.register.UserVerify +import org.mifospay.core.network.model.entity.register.RegisterPayload +import org.mifospay.core.network.model.entity.register.UserVerify import org.mifospay.core.network.utils.ApiEndPoints interface RegistrationService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt index b32f50fab..9444a8312 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt @@ -12,7 +12,7 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Query import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity +import org.mifospay.core.network.model.entity.accounts.savings.TransactionsEntity import org.mifospay.core.network.utils.ApiEndPoints interface RunReportService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt index d513872d8..a46faf62a 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt @@ -16,8 +16,8 @@ import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.entity.savedcards.Card import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.savedcards.Card import org.mifospay.core.network.utils.ApiEndPoints interface SavedCardService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt index 1a20ce280..cb2743f76 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt @@ -15,11 +15,11 @@ import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.Path import de.jensklingenberg.ktorfit.http.Query import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.accounts.savings.SavingAccount -import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity -import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.accounts.savings.SavingAccountEntity +import org.mifospay.core.network.model.entity.accounts.savings.SavingsWithAssociationsEntity +import org.mifospay.core.network.model.entity.accounts.savings.TransactionsEntity import org.mifospay.core.network.utils.ApiEndPoints interface SavingsAccountsService { @@ -27,7 +27,7 @@ interface SavingsAccountsService { suspend fun getSavingsWithAssociations( @Path("accountId") accountId: Long, @Query("associations") associationType: String, - ): Flow + ): SavingsWithAssociationsEntity @GET(ApiEndPoints.SAVINGS_ACCOUNTS) suspend fun getSavingsAccounts( @@ -35,7 +35,7 @@ interface SavingsAccountsService { ): Flow> @POST(ApiEndPoints.SAVINGS_ACCOUNTS) - suspend fun createSavingsAccount(@Body savingAccount: SavingAccount): Flow + suspend fun createSavingsAccount(@Body savingAccount: SavingAccountEntity): Flow @POST(ApiEndPoints.SAVINGS_ACCOUNTS + "/{accountId}") suspend fun blockUnblockAccount( diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt index c075e395c..4575a9687 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt @@ -11,7 +11,7 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Query -import org.mifospay.core.model.entity.SearchedEntity +import org.mifospay.core.network.model.entity.SearchedEntity import org.mifospay.core.network.utils.ApiEndPoints interface SearchService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt index 134d910a8..8660352d4 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt @@ -16,11 +16,11 @@ import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import de.jensklingenberg.ktorfit.http.Query import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.entity.Page -import org.mifospay.core.model.entity.payload.StandingInstructionPayload -import org.mifospay.core.model.entity.standinginstruction.SDIResponse -import org.mifospay.core.model.entity.standinginstruction.StandingInstruction import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.Page +import org.mifospay.core.network.model.entity.payload.StandingInstructionPayload +import org.mifospay.core.network.model.entity.standinginstruction.SDIResponse +import org.mifospay.core.network.model.entity.standinginstruction.StandingInstruction import org.mifospay.core.network.utils.ApiEndPoints interface StandingInstructionService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt index 0586c2393..a99510617 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt @@ -13,9 +13,9 @@ import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.POST import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.entity.TPTResponse -import org.mifospay.core.model.entity.payload.TransferPayload -import org.mifospay.core.model.entity.templates.account.AccountOptionsTemplate +import org.mifospay.core.network.model.entity.TPTResponse +import org.mifospay.core.network.model.entity.payload.TransferPayload +import org.mifospay.core.network.model.entity.templates.account.AccountOptionsTemplate import org.mifospay.core.network.utils.ApiEndPoints interface ThirdPartyTransferService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt index 18b4f9a19..285a0072f 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt @@ -13,8 +13,8 @@ import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.Query import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.domain.twofactor.AccessToken -import org.mifospay.core.model.domain.twofactor.DeliveryMethod +import org.mifospay.core.network.model.twofactor.AccessToken +import org.mifospay.core.network.model.twofactor.DeliveryMethod import org.mifospay.core.network.utils.ApiEndPoints interface TwoFactorAuthService { diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt index 2ec6be88e..70d99d6e8 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt @@ -16,10 +16,10 @@ import de.jensklingenberg.ktorfit.http.POST import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow -import org.mifospay.core.model.domain.user.NewUser -import org.mifospay.core.model.entity.UserWithRole import org.mifospay.core.network.model.CommonResponse import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.model.entity.UserWithRole +import org.mifospay.core.network.model.entity.user.NewUserEntity import org.mifospay.core.network.utils.ApiEndPoints interface UserService { @@ -27,12 +27,12 @@ interface UserService { suspend fun users(): Flow> @POST(ApiEndPoints.USER) - suspend fun createUser(@Body user: NewUser): CommonResponse + suspend fun createUser(@Body user: NewUserEntity): CommonResponse @PUT(ApiEndPoints.USER + "/{userId}") suspend fun updateUser( @Path("userId") userId: Int, - @Body updateUserEntity: NewUser, + @Body updateUserEntity: NewUserEntity, ): Flow @DELETE(ApiEndPoints.USER + "/{userId}") diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt index 89fae835a..060f025a6 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt @@ -17,7 +17,7 @@ import io.ktor.util.AttributeKey import org.mifospay.core.datastore.UserPreferencesRepository class KtorInterceptor( - private val repository: UserPreferencesRepository, + private val getToken: () -> String?, ) { companion object Plugin : HttpClientPlugin { private const val HEADER_TENANT = "Fineract-Platform-TenantId" @@ -27,25 +27,63 @@ class KtorInterceptor( override val key: AttributeKey = AttributeKey("KtorInterceptor") override fun install(plugin: KtorInterceptor, scope: HttpClient) { - val authToken = plugin.repository.token.value - scope.requestPipeline.intercept(HttpRequestPipeline.State) { context.header("Content-Type", "application/json") context.header("Accept", "application/json") context.header(HEADER_TENANT, DEFAULT) - if (!authToken.isNullOrEmpty()) { - context.header(HEADER_AUTH, "Basic $authToken") + + plugin.getToken()?.let { token -> + if (token.isNotEmpty()) { + context.headers[HEADER_AUTH] = "Basic $token" + } } } } override fun prepare(block: Config.() -> Unit): KtorInterceptor { val config = Config().apply(block) - return KtorInterceptor(config.preferenceRepository!!) + return KtorInterceptor(config.getToken) } } } -class Config( - var preferenceRepository: UserPreferencesRepository? = null, -) +class Config { + lateinit var getToken: () -> String? +} + +class KtorInterceptorRe( + private val repository: UserPreferencesRepository, +) { + companion object Plugin : HttpClientPlugin { + private const val HEADER_TENANT = "Fineract-Platform-TenantId" + private const val HEADER_AUTH = "Authorization" + private const val DEFAULT = "venus" + + override val key: AttributeKey = AttributeKey("KtorInterceptorRe") + + override fun install(plugin: KtorInterceptorRe, scope: HttpClient) { + val token = plugin.repository.token.value + + scope.requestPipeline.intercept(HttpRequestPipeline.State) { + context.header("Content-Type", "application/json") + context.header("Accept", "application/json") + context.header(HEADER_TENANT, DEFAULT) + + token?.let { token -> + if (token.isNotEmpty()) { + context.headers[HEADER_AUTH] = "Basic $token" + } + } + } + } + + override fun prepare(block: ConfigRe.() -> Unit): KtorInterceptorRe { + val config = ConfigRe().apply(block) + return KtorInterceptorRe(config.repository) + } + } +} + +class ConfigRe { + lateinit var repository: UserPreferencesRepository +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/FaqItemScreen.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/FaqItemScreen.kt index aa6792e43..319682002 100644 --- a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/FaqItemScreen.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/FaqItemScreen.kt @@ -66,7 +66,7 @@ fun FaqItemScreen( ) Icon( - imageVector = MifosIcons.ArrowDropDown, + imageVector = MifosIcons.KeyboardArrowDown, contentDescription = "drop down", tint = MaterialTheme.colorScheme.onSurface, modifier = Modifier diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt index c97fe367e..3037d6d76 100644 --- a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/TransactionItemScreen.kt @@ -31,12 +31,11 @@ import mobile_wallet.core.ui.generated.resources.Res import mobile_wallet.core.ui.generated.resources.core_ui_money_in import mobile_wallet.core.ui.generated.resources.core_ui_money_out import org.jetbrains.compose.resources.painterResource -import org.jetbrains.compose.ui.tooling.preview.Preview import org.mifospay.core.common.CurrencyFormatter import org.mifospay.core.designsystem.theme.green import org.mifospay.core.designsystem.theme.red -import org.mifospay.core.model.domain.Transaction -import org.mifospay.core.model.domain.TransactionType +import org.mifospay.core.model.savingsaccount.Transaction +import org.mifospay.core.model.savingsaccount.TransactionType @Composable fun TransactionItemScreen( @@ -112,9 +111,3 @@ fun TransactionItemScreen( ) } } - -@Preview -@Composable -fun ItemTransactionPreview() { - TransactionItemScreen(Transaction(), modifier = Modifier) -} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt index 0f673bb5a..f8aa21734 100644 --- a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt @@ -28,7 +28,6 @@ import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -38,6 +37,7 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.launch import mobile_wallet.feature.auth.generated.resources.Res import mobile_wallet.feature.auth.generated.resources.feature_auth_login @@ -68,7 +68,7 @@ internal fun LoginScreen( modifier: Modifier = Modifier, viewModel: LoginViewModel = koinViewModel(), ) { - val state by viewModel.stateFlow.collectAsState() + val state by viewModel.stateFlow.collectAsStateWithLifecycle() val snackbarHostState = remember { SnackbarHostState() } val scope = rememberCoroutineScope() diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt index 9bd45e200..f2b8aaca8 100644 --- a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt @@ -18,7 +18,7 @@ import org.mifospay.core.common.Parcelable import org.mifospay.core.common.Parcelize import org.mifospay.core.common.Result import org.mifospay.core.domain.LoginUseCase -import org.mifospay.core.model.domain.user.User +import org.mifospay.core.model.user.UserInfo import org.mifospay.core.ui.utils.BaseViewModel private const val KEY_STATE = "state" @@ -148,7 +148,7 @@ sealed class LoginAction { sealed class Internal : LoginAction() { data class ReceiveLoginResult( - val loginResult: Result, + val loginResult: Result, ) : Internal() } } diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt index d81788914..9ec663fb7 100644 --- a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt @@ -22,12 +22,12 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.launch import mobile_wallet.feature.auth.generated.resources.Res import mobile_wallet.feature.auth.generated.resources.feature_auth_enter_mobile_number @@ -60,7 +60,7 @@ internal fun MobileVerificationScreen( modifier: Modifier = Modifier, viewModel: MobileVerificationViewModel = koinViewModel(), ) { - val state by viewModel.stateFlow.collectAsState() + val state by viewModel.stateFlow.collectAsStateWithLifecycle() val snackbarHostState = remember { SnackbarHostState() } val scope = rememberCoroutineScope() diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt index 0d1266f4d..61e633f0b 100644 --- a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt @@ -25,7 +25,6 @@ import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -35,6 +34,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.launch import mobile_wallet.feature.auth.generated.resources.Res import mobile_wallet.feature.auth.generated.resources.feature_auth_address_line_1 @@ -74,7 +74,7 @@ internal fun SignupScreen( modifier: Modifier = Modifier, viewModel: SignupViewModel = koinViewModel(), ) { - val state by viewModel.stateFlow.collectAsState() + val state by viewModel.stateFlow.collectAsStateWithLifecycle() val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) val snackbarHostState = remember { SnackbarHostState() } val scope = rememberCoroutineScope() diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt index 45d9e040f..5577de7bf 100644 --- a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt @@ -24,9 +24,9 @@ import org.mifospay.core.data.repository.ClientRepository import org.mifospay.core.data.repository.SearchRepository import org.mifospay.core.data.repository.UserRepository import org.mifospay.core.data.util.Constants -import org.mifospay.core.model.domain.client.Address -import org.mifospay.core.model.domain.client.NewClient -import org.mifospay.core.model.domain.user.NewUser +import org.mifospay.core.model.client.ClientAddress +import org.mifospay.core.model.client.NewClient +import org.mifospay.core.model.user.NewUser import org.mifospay.core.ui.utils.BaseViewModel import org.mifospay.core.ui.utils.PasswordChecker import org.mifospay.core.ui.utils.PasswordStrength @@ -406,7 +406,7 @@ class SignupViewModel( } is Result.Success -> { - createClient(result.data.resourceId) + createClient(result.data) } is Result.Loading -> Unit @@ -422,7 +422,7 @@ class SignupViewModel( externalId = state.userNameInput.plus("_client"), mobileNo = state.mobileNumberInput, savingsProductId = state.savingsProductId, - address = Address( + address = ClientAddress( addressLine1 = state.addressLine1Input, addressLine2 = state.addressLine2Input, postalCode = state.pinCodeInput, @@ -441,7 +441,7 @@ class SignupViewModel( } is Result.Success -> { - assignClientToUser(result.data.clientId, userId) + assignClientToUser(result.data, userId) } is Result.Loading -> Unit diff --git a/feature/home/build.gradle.kts b/feature/home/build.gradle.kts index 0fe68be92..6f819bc4b 100644 --- a/feature/home/build.gradle.kts +++ b/feature/home/build.gradle.kts @@ -8,14 +8,26 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.feature) - alias(libs.plugins.mifospay.android.library.compose) + alias(libs.plugins.mifospay.cmp.feature) + alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.kotlin.serialization) } android { namespace = "org.mifospay.feature.home" } -dependencies { +kotlin { + sourceSets { + commonMain.dependencies { + implementation(compose.ui) + implementation(compose.foundation) + implementation(compose.material3) + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) + implementation(libs.koin.compose.viewmodel) + implementation(libs.koin.compose) + } + } } \ No newline at end of file diff --git a/feature/home/src/main/AndroidManifest.xml b/feature/home/src/androidMain/AndroidManifest.xml similarity index 100% rename from feature/home/src/main/AndroidManifest.xml rename to feature/home/src/androidMain/AndroidManifest.xml diff --git a/feature/home/src/main/res/drawable/feature_home_ic_arrow_back_black_24dp.xml b/feature/home/src/commonMain/composeResources/drawable/arrow_backward.xml similarity index 60% rename from feature/home/src/main/res/drawable/feature_home_ic_arrow_back_black_24dp.xml rename to feature/home/src/commonMain/composeResources/drawable/arrow_backward.xml index a5dc0c323..f2e539735 100644 --- a/feature/home/src/main/res/drawable/feature_home_ic_arrow_back_black_24dp.xml +++ b/feature/home/src/commonMain/composeResources/drawable/arrow_backward.xml @@ -8,12 +8,8 @@ See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md --> - - + + + + diff --git a/feature/home/src/main/res/values/colors.xml b/feature/home/src/commonMain/composeResources/drawable/arrow_outward.xml similarity index 52% rename from feature/home/src/main/res/values/colors.xml rename to feature/home/src/commonMain/composeResources/drawable/arrow_outward.xml index 94cf69f37..95e05cbfa 100644 --- a/feature/home/src/main/res/values/colors.xml +++ b/feature/home/src/commonMain/composeResources/drawable/arrow_outward.xml @@ -8,6 +8,8 @@ See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md --> - - #DE000000 - \ No newline at end of file + + + + + diff --git a/feature/home/src/commonMain/composeResources/drawable/coin_image.png b/feature/home/src/commonMain/composeResources/drawable/coin_image.png new file mode 100644 index 0000000000000000000000000000000000000000..000c53aedb4f57bae41ed2f816d1fba37fa008f3 GIT binary patch literal 345967 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 >>+Adf-#BTw8@V?yg?tDiWb;l1n&Gh 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