refactor: handle api responses, cleaning up modules (#2837)

This commit is contained in:
Nagarjuna 2025-04-09 17:17:37 +05:30 committed by Rajan Maurya
parent 825895c1bc
commit a56ee69ba7
42 changed files with 360 additions and 529 deletions

View File

@ -71,10 +71,6 @@ gradlePlugin {
}
// Room Plugin
register("androidHilt") {
id = "mifos.android.hilt"
implementationClass = "AndroidHiltConventionPlugin"
}
register("kmpRoom") {
id = "mifos.kmp.room"
implementationClass = "KMPRoomConventionPlugin"

View File

@ -1,31 +0,0 @@
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.dependencies
import org.mifos.mobile.libs
class AndroidHiltConventionPlugin : Plugin<Project> {
override fun apply(target: Project) {
with(target) {
pluginManager.apply("com.google.devtools.ksp")
dependencies {
"ksp"(libs.findLibrary("hilt.compiler").get())
}
// Add support for Jvm Module, base on org.jetbrains.kotlin.jvm
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
dependencies {
"implementation"(libs.findLibrary("hilt.core").get())
}
}
/** Add support for Android modules, based on [AndroidBasePlugin] */
pluginManager.withPlugin("com.android.base") {
pluginManager.apply("dagger.hilt.android.plugin")
dependencies {
"implementation"(libs.findLibrary("hilt.android").get())
}
}
}
}
}

View File

@ -21,7 +21,6 @@ plugins {
alias(libs.plugins.firebase.perf) apply false
alias(libs.plugins.gms) apply false
alias(libs.plugins.hilt) apply false
alias(libs.plugins.room) apply false
alias(libs.plugins.ksp) apply false

View File

@ -104,34 +104,7 @@ dependencyGuard {
dependencies {
implementation(projects.cmpShared)
implementation(projects.core.logs)
implementation(projects.core.common)
implementation(projects.core.model)
implementation(projects.core.data)
implementation(projects.core.database)
implementation(projects.core.ui)
implementation(projects.core.designsystem)
// implementation(projects.feature.loan)
// implementation(projects.feature.beneficiary)
// implementation(projects.feature.guarantor)
// implementation(projects.feature.savings)
// implementation(projects.feature.qr)
// implementation(projects.feature.transferProcess)
// implementation(projects.feature.clientCharge)
// implementation(projects.feature.recentTransaction)
// implementation(projects.feature.thirdPartyTransfer)
implementation(projects.feature.help)
// implementation(projects.feature.notification)
// implementation(projects.feature.location)
// implementation(projects.feature.about)
// implementation(projects.feature.settings)
// implementation(projects.feature.updatePassword)
// implementation(projects.feature.home)
// implementation(projects.feature.auth)
// implementation(projects.feature.userProfile)
// implementation(projects.libs.mifosPasscode)
// Compose
implementation(libs.androidx.core.ktx)

View File

@ -71,7 +71,6 @@ androidx.databinding:databinding-common:8.7.3
androidx.databinding:databinding-ktx:8.7.3
androidx.databinding:databinding-runtime:8.7.3
androidx.databinding:viewbinding:8.7.3
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
@ -80,7 +79,6 @@ androidx.fragment:fragment-ktx:1.8.5
androidx.fragment:fragment:1.8.5
androidx.graphics:graphics-path:1.0.1
androidx.interpolator:interpolator:1.0.0
androidx.legacy:legacy-support-core-utils:1.0.0
androidx.lifecycle:lifecycle-common-java8:2.8.7
androidx.lifecycle:lifecycle-common-jvm:2.8.7
androidx.lifecycle:lifecycle-common:2.8.7
@ -102,7 +100,6 @@ androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.7
androidx.lifecycle:lifecycle-viewmodel:2.8.7
androidx.loader:loader:1.0.0
androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
androidx.metrics:metrics-performance:1.0.0-beta01
androidx.navigation:navigation-common-ktx:2.8.4
androidx.navigation:navigation-common:2.8.4
@ -111,25 +108,11 @@ androidx.navigation:navigation-fragment-ktx:2.8.4
androidx.navigation:navigation-fragment:2.8.4
androidx.navigation:navigation-runtime-ktx:2.8.4
androidx.navigation:navigation-runtime:2.8.4
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.4.1
androidx.resourceinspection:resourceinspection-annotation:1.0.1
androidx.room:room-common-jvm:2.7.0-alpha12
androidx.room:room-common:2.7.0-alpha12
androidx.room:room-ktx:2.7.0-alpha12
androidx.room:room-runtime-android:2.7.0-alpha12
androidx.room:room-runtime:2.7.0-alpha12
androidx.savedstate:savedstate-ktx:1.2.1
androidx.savedstate:savedstate:1.2.1
androidx.slidingpanelayout:slidingpanelayout:1.2.0
androidx.sqlite:sqlite-android:2.5.0-alpha12
androidx.sqlite:sqlite-bundled-android:2.5.0-alpha12
androidx.sqlite:sqlite-bundled:2.5.0-alpha12
androidx.sqlite:sqlite-framework-android:2.5.0-alpha12
androidx.sqlite:sqlite-framework:2.5.0-alpha12
androidx.sqlite:sqlite:2.5.0-alpha12
androidx.startup:startup-runtime:1.1.1
androidx.tracing:tracing-ktx:1.2.0
androidx.tracing:tracing:1.2.0
@ -165,36 +148,20 @@ com.google.accompanist:accompanist-permissions:0.34.0
com.google.android.datatransport:transport-api:2.2.1
com.google.android.datatransport:transport-backend-cct:2.3.3
com.google.android.datatransport:transport-runtime:2.2.6
com.google.android.gms:play-services-ads-identifier:18.0.0
com.google.android.gms:play-services-base:18.5.0
com.google.android.gms:play-services-basement:18.4.0
com.google.android.gms:play-services-maps:18.2.0
com.google.android.gms:play-services-measurement-api:22.1.2
com.google.android.gms:play-services-measurement-base:22.1.2
com.google.android.gms:play-services-measurement-impl:22.1.2
com.google.android.gms:play-services-measurement-sdk-api:22.1.2
com.google.android.gms:play-services-measurement-sdk:22.1.2
com.google.android.gms:play-services-measurement:22.1.2
com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1
com.google.android.gms:play-services-oss-licenses:17.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.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.errorprone:error_prone_annotations:2.28.0
com.google.firebase:firebase-analytics-ktx:22.1.2
com.google.firebase:firebase-analytics:22.1.2
com.google.firebase:firebase-annotations:16.2.0
com.google.firebase:firebase-bom:33.7.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-annotations:16.0.0
com.google.firebase:firebase-components:16.1.0
com.google.firebase:firebase-encoders-json:17.1.0
com.google.firebase:firebase-encoders:17.0.0
com.google.firebase:firebase-installations-interop:17.1.1
com.google.firebase:firebase-installations:18.0.0
com.google.firebase:firebase-measurement-connector:19.0.0
com.google.firebase:firebase-encoders:16.1.0
com.google.guava:failureaccess:1.0.2
com.google.guava:guava:33.3.1-android
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
@ -348,7 +315,6 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.10.1
org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1
org.jetbrains.kotlinx:kotlinx-datetime:0.6.1

View File

@ -67,7 +67,6 @@ androidx.databinding:databinding-common:8.7.3
androidx.databinding:databinding-ktx:8.7.3
androidx.databinding:databinding-runtime:8.7.3
androidx.databinding:viewbinding:8.7.3
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
@ -76,7 +75,6 @@ androidx.fragment:fragment-ktx:1.8.5
androidx.fragment:fragment:1.8.5
androidx.graphics:graphics-path:1.0.1
androidx.interpolator:interpolator:1.0.0
androidx.legacy:legacy-support-core-utils:1.0.0
androidx.lifecycle:lifecycle-common-java8:2.8.7
androidx.lifecycle:lifecycle-common-jvm:2.8.7
androidx.lifecycle:lifecycle-common:2.8.7
@ -98,7 +96,6 @@ androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.7
androidx.lifecycle:lifecycle-viewmodel:2.8.7
androidx.loader:loader:1.0.0
androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
androidx.metrics:metrics-performance:1.0.0-beta01
androidx.navigation:navigation-common-ktx:2.8.4
androidx.navigation:navigation-common:2.8.4
@ -107,25 +104,11 @@ androidx.navigation:navigation-fragment-ktx:2.8.4
androidx.navigation:navigation-fragment:2.8.4
androidx.navigation:navigation-runtime-ktx:2.8.4
androidx.navigation:navigation-runtime:2.8.4
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.4.1
androidx.resourceinspection:resourceinspection-annotation:1.0.1
androidx.room:room-common-jvm:2.7.0-alpha12
androidx.room:room-common:2.7.0-alpha12
androidx.room:room-ktx:2.7.0-alpha12
androidx.room:room-runtime-android:2.7.0-alpha12
androidx.room:room-runtime:2.7.0-alpha12
androidx.savedstate:savedstate-ktx:1.2.1
androidx.savedstate:savedstate:1.2.1
androidx.slidingpanelayout:slidingpanelayout:1.2.0
androidx.sqlite:sqlite-android:2.5.0-alpha12
androidx.sqlite:sqlite-bundled-android:2.5.0-alpha12
androidx.sqlite:sqlite-bundled:2.5.0-alpha12
androidx.sqlite:sqlite-framework-android:2.5.0-alpha12
androidx.sqlite:sqlite-framework:2.5.0-alpha12
androidx.sqlite:sqlite:2.5.0-alpha12
androidx.startup:startup-runtime:1.1.1
androidx.tracing:tracing-ktx:1.2.0
androidx.tracing:tracing:1.2.0
@ -161,36 +144,20 @@ com.google.accompanist:accompanist-permissions:0.34.0
com.google.android.datatransport:transport-api:2.2.1
com.google.android.datatransport:transport-backend-cct:2.3.3
com.google.android.datatransport:transport-runtime:2.2.6
com.google.android.gms:play-services-ads-identifier:18.0.0
com.google.android.gms:play-services-base:18.5.0
com.google.android.gms:play-services-basement:18.4.0
com.google.android.gms:play-services-maps:18.2.0
com.google.android.gms:play-services-measurement-api:22.1.2
com.google.android.gms:play-services-measurement-base:22.1.2
com.google.android.gms:play-services-measurement-impl:22.1.2
com.google.android.gms:play-services-measurement-sdk-api:22.1.2
com.google.android.gms:play-services-measurement-sdk:22.1.2
com.google.android.gms:play-services-measurement:22.1.2
com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1
com.google.android.gms:play-services-oss-licenses:17.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.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.errorprone:error_prone_annotations:2.28.0
com.google.firebase:firebase-analytics-ktx:22.1.2
com.google.firebase:firebase-analytics:22.1.2
com.google.firebase:firebase-annotations:16.2.0
com.google.firebase:firebase-bom:33.7.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-annotations:16.0.0
com.google.firebase:firebase-components:16.1.0
com.google.firebase:firebase-encoders-json:17.1.0
com.google.firebase:firebase-encoders:17.0.0
com.google.firebase:firebase-installations-interop:17.1.1
com.google.firebase:firebase-installations:18.0.0
com.google.firebase:firebase-measurement-connector:19.0.0
com.google.firebase:firebase-encoders:16.1.0
com.google.guava:failureaccess:1.0.2
com.google.guava:guava:33.3.1-android
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
@ -344,7 +311,6 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.10.1
org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1
org.jetbrains.kotlinx:kotlinx-datetime:0.6.1

View File

@ -71,7 +71,6 @@ androidx.databinding:databinding-common:8.7.3
androidx.databinding:databinding-ktx:8.7.3
androidx.databinding:databinding-runtime:8.7.3
androidx.databinding:viewbinding:8.7.3
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
@ -80,7 +79,6 @@ androidx.fragment:fragment-ktx:1.8.5
androidx.fragment:fragment:1.8.5
androidx.graphics:graphics-path:1.0.1
androidx.interpolator:interpolator:1.0.0
androidx.legacy:legacy-support-core-utils:1.0.0
androidx.lifecycle:lifecycle-common-java8:2.8.7
androidx.lifecycle:lifecycle-common-jvm:2.8.7
androidx.lifecycle:lifecycle-common:2.8.7
@ -102,7 +100,6 @@ androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.7
androidx.lifecycle:lifecycle-viewmodel:2.8.7
androidx.loader:loader:1.0.0
androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
androidx.metrics:metrics-performance:1.0.0-beta01
androidx.navigation:navigation-common-ktx:2.8.4
androidx.navigation:navigation-common:2.8.4
@ -111,25 +108,11 @@ androidx.navigation:navigation-fragment-ktx:2.8.4
androidx.navigation:navigation-fragment:2.8.4
androidx.navigation:navigation-runtime-ktx:2.8.4
androidx.navigation:navigation-runtime:2.8.4
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.4.1
androidx.resourceinspection:resourceinspection-annotation:1.0.1
androidx.room:room-common-jvm:2.7.0-alpha12
androidx.room:room-common:2.7.0-alpha12
androidx.room:room-ktx:2.7.0-alpha12
androidx.room:room-runtime-android:2.7.0-alpha12
androidx.room:room-runtime:2.7.0-alpha12
androidx.savedstate:savedstate-ktx:1.2.1
androidx.savedstate:savedstate:1.2.1
androidx.slidingpanelayout:slidingpanelayout:1.2.0
androidx.sqlite:sqlite-android:2.5.0-alpha12
androidx.sqlite:sqlite-bundled-android:2.5.0-alpha12
androidx.sqlite:sqlite-bundled:2.5.0-alpha12
androidx.sqlite:sqlite-framework-android:2.5.0-alpha12
androidx.sqlite:sqlite-framework:2.5.0-alpha12
androidx.sqlite:sqlite:2.5.0-alpha12
androidx.startup:startup-runtime:1.1.1
androidx.tracing:tracing-ktx:1.2.0
androidx.tracing:tracing:1.2.0
@ -165,36 +148,20 @@ com.google.accompanist:accompanist-permissions:0.34.0
com.google.android.datatransport:transport-api:2.2.1
com.google.android.datatransport:transport-backend-cct:2.3.3
com.google.android.datatransport:transport-runtime:2.2.6
com.google.android.gms:play-services-ads-identifier:18.0.0
com.google.android.gms:play-services-base:18.5.0
com.google.android.gms:play-services-basement:18.4.0
com.google.android.gms:play-services-maps:18.2.0
com.google.android.gms:play-services-measurement-api:22.1.2
com.google.android.gms:play-services-measurement-base:22.1.2
com.google.android.gms:play-services-measurement-impl:22.1.2
com.google.android.gms:play-services-measurement-sdk-api:22.1.2
com.google.android.gms:play-services-measurement-sdk:22.1.2
com.google.android.gms:play-services-measurement:22.1.2
com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1
com.google.android.gms:play-services-oss-licenses:17.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.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.errorprone:error_prone_annotations:2.28.0
com.google.firebase:firebase-analytics-ktx:22.1.2
com.google.firebase:firebase-analytics:22.1.2
com.google.firebase:firebase-annotations:16.2.0
com.google.firebase:firebase-bom:33.7.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-annotations:16.0.0
com.google.firebase:firebase-components:16.1.0
com.google.firebase:firebase-encoders-json:17.1.0
com.google.firebase:firebase-encoders:17.0.0
com.google.firebase:firebase-installations-interop:17.1.1
com.google.firebase:firebase-installations:18.0.0
com.google.firebase:firebase-measurement-connector:19.0.0
com.google.firebase:firebase-encoders:16.1.0
com.google.guava:failureaccess:1.0.2
com.google.guava:guava:33.3.1-android
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
@ -348,7 +315,6 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.10.1
org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1
org.jetbrains.kotlinx:kotlinx-datetime:0.6.1

View File

@ -67,7 +67,6 @@ androidx.databinding:databinding-common:8.7.3
androidx.databinding:databinding-ktx:8.7.3
androidx.databinding:databinding-runtime:8.7.3
androidx.databinding:viewbinding:8.7.3
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
@ -76,7 +75,6 @@ androidx.fragment:fragment-ktx:1.8.5
androidx.fragment:fragment:1.8.5
androidx.graphics:graphics-path:1.0.1
androidx.interpolator:interpolator:1.0.0
androidx.legacy:legacy-support-core-utils:1.0.0
androidx.lifecycle:lifecycle-common-java8:2.8.7
androidx.lifecycle:lifecycle-common-jvm:2.8.7
androidx.lifecycle:lifecycle-common:2.8.7
@ -98,7 +96,6 @@ androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.7
androidx.lifecycle:lifecycle-viewmodel:2.8.7
androidx.loader:loader:1.0.0
androidx.localbroadcastmanager:localbroadcastmanager:1.0.0
androidx.metrics:metrics-performance:1.0.0-beta01
androidx.navigation:navigation-common-ktx:2.8.4
androidx.navigation:navigation-common:2.8.4
@ -107,25 +104,11 @@ androidx.navigation:navigation-fragment-ktx:2.8.4
androidx.navigation:navigation-fragment:2.8.4
androidx.navigation:navigation-runtime-ktx:2.8.4
androidx.navigation:navigation-runtime:2.8.4
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.4.1
androidx.resourceinspection:resourceinspection-annotation:1.0.1
androidx.room:room-common-jvm:2.7.0-alpha12
androidx.room:room-common:2.7.0-alpha12
androidx.room:room-ktx:2.7.0-alpha12
androidx.room:room-runtime-android:2.7.0-alpha12
androidx.room:room-runtime:2.7.0-alpha12
androidx.savedstate:savedstate-ktx:1.2.1
androidx.savedstate:savedstate:1.2.1
androidx.slidingpanelayout:slidingpanelayout:1.2.0
androidx.sqlite:sqlite-android:2.5.0-alpha12
androidx.sqlite:sqlite-bundled-android:2.5.0-alpha12
androidx.sqlite:sqlite-bundled:2.5.0-alpha12
androidx.sqlite:sqlite-framework-android:2.5.0-alpha12
androidx.sqlite:sqlite-framework:2.5.0-alpha12
androidx.sqlite:sqlite:2.5.0-alpha12
androidx.startup:startup-runtime:1.1.1
androidx.tracing:tracing-ktx:1.2.0
androidx.tracing:tracing:1.2.0
@ -161,36 +144,20 @@ com.google.accompanist:accompanist-permissions:0.34.0
com.google.android.datatransport:transport-api:2.2.1
com.google.android.datatransport:transport-backend-cct:2.3.3
com.google.android.datatransport:transport-runtime:2.2.6
com.google.android.gms:play-services-ads-identifier:18.0.0
com.google.android.gms:play-services-base:18.5.0
com.google.android.gms:play-services-basement:18.4.0
com.google.android.gms:play-services-maps:18.2.0
com.google.android.gms:play-services-measurement-api:22.1.2
com.google.android.gms:play-services-measurement-base:22.1.2
com.google.android.gms:play-services-measurement-impl:22.1.2
com.google.android.gms:play-services-measurement-sdk-api:22.1.2
com.google.android.gms:play-services-measurement-sdk:22.1.2
com.google.android.gms:play-services-measurement:22.1.2
com.google.android.gms:play-services-mlkit-barcode-scanning:18.3.1
com.google.android.gms:play-services-oss-licenses:17.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.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.errorprone:error_prone_annotations:2.28.0
com.google.firebase:firebase-analytics-ktx:22.1.2
com.google.firebase:firebase-analytics:22.1.2
com.google.firebase:firebase-annotations:16.2.0
com.google.firebase:firebase-bom:33.7.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-annotations:16.0.0
com.google.firebase:firebase-components:16.1.0
com.google.firebase:firebase-encoders-json:17.1.0
com.google.firebase:firebase-encoders:17.0.0
com.google.firebase:firebase-installations-interop:17.1.1
com.google.firebase:firebase-installations:18.0.0
com.google.firebase:firebase-measurement-connector:19.0.0
com.google.firebase:firebase-encoders:16.1.0
com.google.guava:failureaccess:1.0.2
com.google.guava:guava:33.3.1-android
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
@ -344,7 +311,6 @@ org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.10.1
org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.10.1
org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1
org.jetbrains.kotlinx:kotlinx-datetime:0.6.1

View File

@ -14,7 +14,6 @@ import androidx.compose.ui.Modifier
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import cmp.navigation.ui.AppState
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import org.mifos.mobile.core.model.entity.TransferSuccessDestination
import org.mifos.mobile.core.model.enums.AccountType
import org.mifos.mobile.core.model.enums.ChargeType
@ -119,7 +118,6 @@ internal fun FeatureNavHost(
viewQrCode = { appState.navController.navigateToQrDisplayScreen(it) },
callHelpline = { callHelpline() },
reviewTransfer = { transferPayload, transferType, transferDestination ->
logger.e("$transferPayload $transferType")
appState.navController.navigateToTransferProcessScreen(
transferPayload,
transferType,

View File

@ -22,7 +22,6 @@ import kotlinx.datetime.format.FormatStringsInDatetimeFormats
import kotlinx.datetime.format.byUnicodePattern
import kotlinx.datetime.minus
import kotlinx.datetime.toLocalDateTime
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import kotlin.time.Duration.Companion.days
@OptIn(FormatStringsInDatetimeFormats::class)
@ -56,7 +55,6 @@ object DateHelper {
* @return date in the format day month year (ex 14 Apr 2016)
*/
fun getDateAsString(integersOfDate: List<Int>): String {
logger.d { "ktorClient $integersOfDate" }
val stringBuilder = StringBuilder()
stringBuilder.append(integersOfDate[2])
.append(' ')
@ -133,7 +131,6 @@ object DateHelper {
val localDate = LocalDate(dateList[0], dateList[1], dateList[2])
localDate.atStartOfDayIn(TimeZone.UTC).toEpochMilliseconds()
} catch (e: Exception) {
logger.d { "Error parsing date: ${e.message}" }
null
}
}

View File

@ -10,7 +10,6 @@
package org.mifos.mobile.core.data.repository
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.model.entity.TransferResponse
import org.mifos.mobile.core.model.entity.payload.TransferPayload
import org.mifos.mobile.core.model.enums.TransferType
@ -19,5 +18,5 @@ interface TransferRepository {
suspend fun makeTransfer(
payload: TransferPayload,
transferType: TransferType?,
): DataState<TransferResponse>
): DataState<String>
}

View File

@ -17,6 +17,7 @@ import kotlinx.coroutines.withContext
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.common.asDataStateFlow
import org.mifos.mobile.core.data.repository.LoanRepository
import org.mifos.mobile.core.data.util.extractErrorMessage
import org.mifos.mobile.core.model.entity.accounts.loan.LoanWithAssociations
import org.mifos.mobile.core.model.entity.accounts.loan.LoanWithdraw
import org.mifos.mobile.core.model.entity.templates.loans.LoanTemplate
@ -27,21 +28,6 @@ class LoanRepositoryImp(
private val ioDispatcher: CoroutineDispatcher,
) : LoanRepository {
// override fun getLoanWithAssociations(
// associationType: String?,
// loanId: Long?,
// ): Flow<DataState<LoanWithAssociations?>> {
// return dataManager.loanAccountsListApi.getLoanWithAssociations(loanId!!, associationType)
// .map { response ->
// logger.d { "success Getting loan details from server repo $response" }
// DataState.Success(response)
// }.catch { exception ->
// logger.e { "Error fetching loan details: ${exception.message}" }
// DataState.Error(exception)
// }
// .flowOn(ioDispatcher)
// }
override fun getLoanWithAssociations(
associationType: String?,
loanId: Long?,
@ -60,13 +46,21 @@ class LoanRepositoryImp(
loanId: Long?,
loanWithdraw: LoanWithdraw?,
): DataState<String> {
return try {
withContext(ioDispatcher) {
dataManager.loanAccountsListApi.withdrawLoanAccount(loanId!!, loanWithdraw)
return withContext(ioDispatcher) {
try {
val response =
dataManager.loanAccountsListApi.withdrawLoanAccount(loanId!!, loanWithdraw)
if (response.status.value != 200) {
val errorMessage = extractErrorMessage(response)
return@withContext DataState.Error(
Exception(errorMessage),
null,
)
}
DataState.Success("withdraw successful")
} catch (e: Exception) {
DataState.Error(e, null)
}
DataState.Success("withdraw successful")
} catch (e: Exception) {
DataState.Error(e, null)
}
}

View File

@ -16,6 +16,7 @@ import kotlinx.coroutines.withContext
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.common.asDataStateFlow
import org.mifos.mobile.core.data.repository.SavingsAccountRepository
import org.mifos.mobile.core.data.util.extractErrorMessage
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountApplicationPayload
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountUpdatePayload
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountWithdrawPayload
@ -36,8 +37,7 @@ class SavingsAccountRepositoryImp(
return dataManager.savingAccountsListApi.getSavingsWithAssociations(
accountId!!,
associationType,
)
.asDataStateFlow().flowOn(ioDispatcher)
).asDataStateFlow().flowOn(ioDispatcher)
}
override fun getSavingAccountApplicationTemplate(
@ -50,13 +50,21 @@ class SavingsAccountRepositoryImp(
override suspend fun submitSavingAccountApplication(
payload: SavingsAccountApplicationPayload?,
): DataState<String> {
return try {
withContext(ioDispatcher) {
dataManager.savingAccountsListApi.submitSavingAccountApplication(payload)
return withContext(ioDispatcher) {
try {
val response =
dataManager.savingAccountsListApi.submitSavingAccountApplication(payload)
if (response.status.value != 200) {
val errorMessage = extractErrorMessage(response)
return@withContext DataState.Error(
Exception(errorMessage),
null,
)
}
DataState.Success("Submitted successfully")
} catch (e: Exception) {
DataState.Error(e, null)
}
DataState.Success("Submitted successfully")
} catch (e: Exception) {
DataState.Error(e, null)
}
}
@ -64,13 +72,21 @@ class SavingsAccountRepositoryImp(
accountId: Long?,
payload: SavingsAccountUpdatePayload?,
): DataState<String> {
return try {
withContext(ioDispatcher) {
dataManager.savingAccountsListApi.updateSavingsAccountUpdate(accountId!!, payload)
return withContext(ioDispatcher) {
try {
val response =
dataManager.savingAccountsListApi.updateSavingsAccountUpdate(accountId!!, payload)
if (response.status.value != 200) {
val errorMessage = extractErrorMessage(response)
return@withContext DataState.Error(
Exception(errorMessage),
null,
)
}
DataState.Success("Updated successfully")
} catch (e: Exception) {
DataState.Error(e, null)
}
DataState.Success("Updated successfully")
} catch (e: Exception) {
DataState.Error(e, null)
}
}
@ -78,13 +94,21 @@ class SavingsAccountRepositoryImp(
accountId: String?,
payload: SavingsAccountWithdrawPayload?,
): DataState<String> {
return try {
withContext(ioDispatcher) {
dataManager.savingAccountsListApi.submitWithdrawSavingsAccount(accountId!!, payload)
return withContext(ioDispatcher) {
try {
val response =
dataManager.savingAccountsListApi.submitWithdrawSavingsAccount(accountId!!, payload)
if (response.status.value != 200) {
val errorMessage = extractErrorMessage(response)
return@withContext DataState.Error(
Exception(errorMessage),
null,
)
}
DataState.Success("Submitted successfully")
} catch (e: Exception) {
DataState.Error(e, null)
}
DataState.Success("Submitted successfully")
} catch (e: Exception) {
DataState.Error(e, null)
}
}

View File

@ -9,10 +9,13 @@
*/
package org.mifos.mobile.core.data.repositoryImpl
import io.ktor.client.statement.bodyAsText
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.data.repository.TransferRepository
import org.mifos.mobile.core.data.util.extractErrorMessage
import org.mifos.mobile.core.model.entity.TransferResponse
import org.mifos.mobile.core.model.entity.payload.TransferPayload
import org.mifos.mobile.core.model.enums.TransferType
@ -25,18 +28,26 @@ class TransferRepositoryImp(
override suspend fun makeTransfer(
payload: TransferPayload,
transferType: TransferType?,
): DataState<TransferResponse> {
return try {
val response = withContext(ioDispatcher) {
when (transferType) {
): DataState<String> {
return withContext(ioDispatcher) {
try {
val response = when (transferType) {
TransferType.SELF -> dataManager.savingAccountsListApi.makeTransfer(payload)
else -> dataManager.thirdPartyTransferApi.makeTransfer(payload)
}
}
if (response.status.value != 200) {
val errorMessage = extractErrorMessage(response)
return@withContext DataState.Error(
Exception(errorMessage),
null,
)
}
DataState.Success(response)
} catch (e: Exception) {
DataState.Error(e)
val transferResponse = Json.decodeFromString<TransferResponse>(response.bodyAsText())
DataState.Success(transferResponse.resourceId.toString())
} catch (e: Exception) {
DataState.Error(e, null)
}
}
}
}

View File

@ -11,19 +11,8 @@ package org.mifos.mobile.core.data.util
import io.ktor.client.statement.HttpResponse
import io.ktor.client.statement.bodyAsText
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
@Serializable
data class ErrorResponse(
val defaultUserMessage: String? = null,
val errors: List<ErrorDetail>? = null,
)
@Serializable
data class ErrorDetail(
val defaultUserMessage: String? = null,
)
import org.mifos.mobile.core.model.entity.mifoserror.MifosError
/**
* Generic function to extract error messages from API responses
@ -32,8 +21,8 @@ suspend fun extractErrorMessage(response: HttpResponse): String {
val responseText = response.bodyAsText()
return try {
val json = Json { ignoreUnknownKeys = true }
val errorResponse = json.decodeFromString<ErrorResponse>(responseText)
errorResponse.errors?.firstOrNull()?.defaultUserMessage
val errorResponse = json.decodeFromString<MifosError>(responseText)
errorResponse.errors.firstOrNull()?.defaultUserMessage
?: errorResponse.defaultUserMessage
?: "Unknown error"
} catch (e: Exception) {

View File

@ -20,6 +20,6 @@ data class LoanWithdraw(
val note: String? = null,
val dateFormat: String = "dd-MM-yyyy",
val locale: String = "en",
val dateFormat: String? = null,
val locale: String? = null,
) : Parcelable

View File

@ -9,14 +9,13 @@
*/
package org.mifos.mobile.core.model.entity.accounts.savings
import org.mifos.mobile.core.model.Parcelable
import org.mifos.mobile.core.model.Parcelize
import kotlinx.serialization.Serializable
@Parcelize
@Serializable
data class SavingsAccountUpdatePayload(
val clientId: Long? = 0,
val productId: Long? = 0,
) : Parcelable
)

View File

@ -16,8 +16,8 @@ import org.mifos.mobile.core.model.Parcelize
@Serializable
@Parcelize
data class SavingsAccountWithdrawPayload(
val locale: String = "en",
val dateFormat: String = "dd MMMM yyyy",
val locale: String? = null,
val dateFormat: String? = null,
val withdrawnOnDate: String? = null,
val note: String? = null,
) : Parcelable

View File

@ -9,13 +9,12 @@
*/
package org.mifos.mobile.core.model.entity.mifoserror
import org.mifos.mobile.core.model.Parcelable
import org.mifos.mobile.core.model.Parcelize
import kotlinx.serialization.Serializable
@Parcelize
@Serializable
data class Errors(
val developerMessage: String? = null,
val defaultUserMessage: String? = null,
val userMessageGlobalisationCode: String? = null,
val parameterName: String? = null,
) : Parcelable
)

View File

@ -9,14 +9,13 @@
*/
package org.mifos.mobile.core.model.entity.mifoserror
import org.mifos.mobile.core.model.Parcelable
import org.mifos.mobile.core.model.Parcelize
import kotlinx.serialization.Serializable
@Parcelize
@Serializable
data class MifosError(
val developerMessage: String? = null,
val httpStatusCode: String? = null,
val defaultUserMessage: String? = null,
val userMessageGlobalisationCode: String? = null,
val errors: List<Errors> = emptyList(),
) : Parcelable
)

View File

@ -17,7 +17,6 @@ import de.jensklingenberg.ktorfit.http.Path
import de.jensklingenberg.ktorfit.http.Query
import io.ktor.client.statement.HttpResponse
import kotlinx.coroutines.flow.Flow
import org.mifos.mobile.core.model.entity.TransferResponse
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountApplicationPayload
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountUpdatePayload
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountWithdrawPayload
@ -41,7 +40,7 @@ interface SavingAccountsListService {
): Flow<AccountOptionsTemplate>
@POST(ApiEndPoints.ACCOUNT_TRANSFER)
suspend fun makeTransfer(@Body transferPayload: TransferPayload?): TransferResponse
suspend fun makeTransfer(@Body transferPayload: TransferPayload?): HttpResponse
@GET(ApiEndPoints.SAVINGS_ACCOUNTS + "/template")
fun getSavingsAccountApplicationTemplate(

View File

@ -12,8 +12,8 @@ package org.mifos.mobile.core.network.services
import de.jensklingenberg.ktorfit.http.Body
import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.POST
import io.ktor.client.statement.HttpResponse
import kotlinx.coroutines.flow.Flow
import org.mifos.mobile.core.model.entity.TransferResponse
import org.mifos.mobile.core.model.entity.payload.TransferPayload
import org.mifos.mobile.core.model.entity.templates.account.AccountOptionsTemplate
import org.mifos.mobile.core.network.utils.ApiEndPoints
@ -23,5 +23,5 @@ interface ThirdPartyTransferService {
fun accountTransferTemplate(): Flow<AccountOptionsTemplate>
@POST(ApiEndPoints.ACCOUNT_TRANSFER + "?type=tpt")
suspend fun makeTransfer(@Body transferPayload: TransferPayload?): TransferResponse
suspend fun makeTransfer(@Body transferPayload: TransferPayload?): HttpResponse
}

View File

@ -15,7 +15,6 @@ import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import org.mifos.mobile.core.data.repository.ClientRepository
import org.mifos.mobile.core.data.repository.UserAuthRepository
import org.mifos.mobile.core.datastore.UserPreferencesRepository
@ -103,9 +102,7 @@ class LoginViewModel(
it.copy(dialogState = null)
}
val user = action.loginResult.data
logger.d { "KtorClient getting before mapping $user" }
val userData = user.toUserData()
logger.d { "KtorClient getting after mapping $userData" }
viewModelScope.launch {
userPreferencesRepositoryImpl.updateUser(userData)
}

View File

@ -32,7 +32,6 @@ import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.getString
import org.mifos.mobile.core.common.Constants.BENEFICIARY_STATE
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import org.mifos.mobile.core.data.repository.BeneficiaryRepository
import org.mifos.mobile.core.data.util.NetworkMonitor
import org.mifos.mobile.core.model.IgnoredOnParcel
@ -130,10 +129,6 @@ internal class BeneficiaryApplicationViewModel(
beneficiaryRepositoryImp.beneficiaryList(),
beneficiaryRepositoryImp.beneficiaryTemplate(),
) { beneficiaryList, beneficiaryTemplate ->
logger.d {
"KtorClient getting in function ${beneficiaryList.data} and beneficiary " +
"${beneficiaryTemplate.data}"
}
updateStateFromResults(beneficiaryList, beneficiaryTemplate)
}.catch { error ->
updateState {
@ -159,7 +154,6 @@ internal class BeneficiaryApplicationViewModel(
val error = (beneficiaryList as? DataState.Error)?.exception?.message
?: (beneficiaryTemplate as? DataState.Error)?.exception?.message
?: "An error occurred"
logger.d { "KtorClient error $error" }
val errorMessage = "An error occurred"
updateState { it.copy(dialogState = BeneficiaryApplicationState.DialogState.Error(errorMessage)) }
}

View File

@ -14,7 +14,6 @@ import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import org.mifos.mobile.core.data.repository.BeneficiaryRepository
import org.mifos.mobile.core.data.util.NetworkMonitor
import org.mifos.mobile.core.model.IgnoredOnParcel
@ -51,7 +50,6 @@ internal class BeneficiaryListViewModel(
}
viewModelScope.launch {
beneficiaryRepositoryImp.beneficiaryList().catch { e ->
logger.d { "KtorClient in catch block ${e.message}" }
updateState {
it.copy(
dialogState = BeneficiaryListState.DialogState.Error(

View File

@ -34,7 +34,6 @@ import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.getString
import org.mifos.mobile.core.common.Constants
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import org.mifos.mobile.core.data.repository.ClientChargeRepository
import org.mifos.mobile.core.data.util.NetworkMonitor
import org.mifos.mobile.core.datastore.UserPreferencesRepository
@ -185,7 +184,6 @@ internal class ClientChargeViewModel(
}
private fun processLoanOrSavingsCharges(result: DataState<List<Charge>>) {
logger.d { "KtorClient getting in function ${result.data}" }
updateState {
when (result) {
DataState.Loading -> it.copy(chargeDialog = ClientChargeState.ChargeDialogState.Loading)

View File

@ -69,7 +69,7 @@ private fun LoanAccountListItem(
loanAccount.status?.active == true && loanAccount.inArrears == true -> {
Triple(
first = MaterialTheme.colorScheme.error,
second = stringResource(resource = Res.string.feature_account_in_arrears) +
second = stringResource(resource = Res.string.feature_account_in_arrears) + " " +
(
loanAccount.timeline?.actualDisbursementDate?.let {
DateHelper.getDateAsString(it)
@ -82,7 +82,7 @@ private fun LoanAccountListItem(
loanAccount.status?.active == true -> {
Triple(
first = MaterialTheme.colorScheme.primary,
second = stringResource(resource = Res.string.feature_account_active) +
second = stringResource(resource = Res.string.feature_account_active) + " " +
(
loanAccount.timeline?.actualDisbursementDate?.let {
DateHelper.getDateAsString(it)
@ -95,7 +95,7 @@ private fun LoanAccountListItem(
loanAccount.status?.waitingForDisbursal == true -> {
Triple(
first = MaterialTheme.colorScheme.secondary,
second = stringResource(resource = Res.string.feature_account_disburse) +
second = stringResource(resource = Res.string.feature_account_disburse) + " " +
(
loanAccount.timeline?.approvedOnDate?.let {
DateHelper.getDateAsString(
@ -111,7 +111,7 @@ private fun LoanAccountListItem(
loanAccount.status?.pendingApproval == true -> {
Triple(
first = MaterialTheme.colorScheme.tertiary,
second = stringResource(resource = Res.string.feature_account_approval_pending) +
second = stringResource(resource = Res.string.feature_account_approval_pending) + " " +
(
loanAccount.timeline?.submittedOnDate?.let {
DateHelper.getDateAsString(
@ -127,7 +127,7 @@ private fun LoanAccountListItem(
loanAccount.status?.overpaid == true -> {
Triple(
first = MaterialTheme.colorScheme.tertiaryContainer,
second = stringResource(resource = Res.string.feature_account_overpaid) +
second = stringResource(resource = Res.string.feature_account_overpaid) + " " +
(
loanAccount.timeline?.actualDisbursementDate?.let {
DateHelper.getDateAsString(it)
@ -140,7 +140,7 @@ private fun LoanAccountListItem(
loanAccount.status?.closed == true -> {
Triple(
first = MaterialTheme.colorScheme.onSurface,
second = stringResource(resource = Res.string.feature_account_closed) +
second = stringResource(resource = Res.string.feature_account_closed) + " " +
(
loanAccount.timeline?.closedOnDate?.let {
DateHelper.getDateAsString(
@ -156,7 +156,7 @@ private fun LoanAccountListItem(
else -> {
Triple(
first = MaterialTheme.colorScheme.outline,
second = stringResource(resource = Res.string.feature_account_withdrawn) +
second = stringResource(resource = Res.string.feature_account_withdrawn) + " " +
(
loanAccount.timeline?.withdrawnOnDate?.let {
DateHelper.getDateAsString(

View File

@ -22,7 +22,6 @@ import org.mifos.mobile.core.common.Constants
import org.mifos.mobile.core.common.Constants.LOAN_ID
import org.mifos.mobile.core.common.Constants.TRANSFER_PAY_TO
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import org.mifos.mobile.core.data.repository.LoanRepository
import org.mifos.mobile.core.data.util.NetworkMonitor
import org.mifos.mobile.core.datastore.UserPreferencesRepository
@ -159,7 +158,6 @@ internal class LoanAccountsDetailViewModel(
updateState { currentState ->
when (result) {
is DataState.Error -> {
logger.e { "KtorClient error in ViewModel: ${result.exception.message}" }
currentState.copy(
dialogState = LoanAccountsState.DialogState.Error(
result.exception.message ?: "An error occurred",

View File

@ -13,12 +13,11 @@ 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.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -39,8 +38,8 @@ import org.jetbrains.compose.resources.stringResource
import org.jetbrains.compose.ui.tooling.preview.Preview
import org.koin.compose.viewmodel.koinViewModel
import org.mifos.mobile.core.designsystem.component.MifosButton
import org.mifos.mobile.core.designsystem.component.MifosScaffold
import org.mifos.mobile.core.designsystem.component.MifosTextField
import org.mifos.mobile.core.designsystem.component.MifosTopAppBar
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
import org.mifos.mobile.core.model.entity.accounts.loan.LoanWithAssociations
import org.mifos.mobile.core.ui.component.MifosErrorComponent
@ -76,6 +75,7 @@ internal fun LoanAccountWithdrawScreen(
{ viewModel.trySendAction(it) }
},
modifier = modifier,
snackbarHostState = snackbarHostState,
)
}
@ -103,29 +103,26 @@ private fun LoanAccountWithDrawDialog(
private fun LoanAccountWithdrawScreen(
state: LoanAccountWithdrawState,
onAction: (LoanAccountWithdrawAction) -> Unit,
snackbarHostState: SnackbarHostState,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.background),
verticalArrangement = Arrangement.spacedBy(16.dp),
) {
MifosTopAppBar(
backPress = { onAction(LoanAccountWithdrawAction.BackPress) },
topBarTitle = stringResource(Res.string.withdraw_loan),
)
MifosScaffold(
backPress = { onAction(LoanAccountWithdrawAction.BackPress) },
topBarTitle = stringResource(Res.string.withdraw_loan),
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
content = {
Box(modifier = Modifier.padding(it)) {
Column(modifier = modifier.padding(16.dp)) {
LoanAccountWithdrawContent(
loanWithAssociations = state.loanWithAssociations,
state = state,
onAction = onAction,
)
}
}
},
)
Spacer(modifier = Modifier.height(8.dp))
Box(modifier = Modifier.weight(1f).padding(16.dp)) {
LoanAccountWithdrawContent(
loanWithAssociations = state.loanWithAssociations,
state = state,
onAction = onAction,
)
}
}
LoanAccountWithDrawDialog(
dialogState = state.dialogState,
)
@ -182,6 +179,7 @@ private fun LoanAccountWithdrawPreview() {
state = LoanAccountWithdrawState(dialogState = null),
modifier = Modifier,
onAction = {},
snackbarHostState = SnackbarHostState(),
)
}
}

View File

@ -11,6 +11,7 @@ package org.mifos.mobile.feature.loan.loanAccountWithdraw
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
@ -75,7 +76,7 @@ internal class LoanAccountWithdrawViewModel(
Clock.System.now().toEpochMilliseconds(),
),
note = state.loanReason,
dateFormat = "dd-MM-yyyy",
dateFormat = DateHelper.SHORT_MONTH,
locale = "en",
)
updateState {
@ -100,12 +101,18 @@ internal class LoanAccountWithdrawViewModel(
it.copy(dialogState = null)
}
sendEvent(LoanAccountWithdrawEvent.ShowToast(successMessage))
delay(1500)
sendEvent(LoanAccountWithdrawEvent.NavigateBack)
}
is DataState.Error -> {
updateState {
it.copy(dialogState = LoanAccountWithdrawState.DialogState.Error(errorMessage))
it.copy(dialogState = null)
}
sendEvent(
LoanAccountWithdrawEvent.ShowToast(
response.exception.message ?: errorMessage,
),
)
}
}
}

View File

@ -30,7 +30,6 @@ import kotlinx.coroutines.launch
import mifos_mobile.feature.qr.generated.resources.Res
import mifos_mobile.feature.qr.generated.resources.choose_option
import org.jetbrains.compose.resources.getString
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import org.mifos.mobile.core.model.IgnoredOnParcel
import org.mifos.mobile.core.model.Parcelable
import org.mifos.mobile.core.model.Parcelize
@ -76,7 +75,6 @@ internal class QrCodeDisplayViewModel(
QrCodeDisplayAction.DismissDialog -> setDialogState(null)
is QrCodeDisplayAction.ShareQrCode -> {
viewModelScope.launch {
logger.d { "Sharing QR Code: ${action.option}, size: ${action.qrBitmap.size} bytes" }
shareImage(
action.option,
action.qrBitmap,

View File

@ -24,7 +24,6 @@ import mifos_mobile.feature.savings_account.generated.resources.feature_account_
import mifos_mobile.feature.savings_account.generated.resources.feature_account_approved
import mifos_mobile.feature.savings_account.generated.resources.feature_account_closed
import mifos_mobile.feature.savings_account.generated.resources.feature_account_matured
import mifos_mobile.feature.savings_account.generated.resources.feature_account_string_and_string
import mifos_mobile.feature.savings_account.generated.resources.feature_account_submitted
import org.jetbrains.compose.resources.stringResource
import org.mifos.mobile.core.common.CurrencyFormatter
@ -69,7 +68,7 @@ private fun SavingsAccountListItem(
savingAccount.status?.active == true -> {
Triple(
first = MaterialTheme.colorScheme.primary,
second = stringResource(Res.string.feature_account_active) +
second = stringResource(Res.string.feature_account_active) + " " +
(
savingAccount.lastActiveTransactionDate?.let {
DateHelper.getDateAsString(
@ -84,7 +83,7 @@ private fun SavingsAccountListItem(
savingAccount.status?.approved == true -> {
Triple(
first = MaterialTheme.colorScheme.secondaryContainer,
second = stringResource(Res.string.feature_account_approved) +
second = stringResource(Res.string.feature_account_approved) + " " +
(
savingAccount.timeLine?.approvedOnDate?.let {
DateHelper.getDateAsString(
@ -99,7 +98,7 @@ private fun SavingsAccountListItem(
savingAccount.status?.submittedAndPendingApproval == true -> {
Triple(
first = MaterialTheme.colorScheme.tertiaryContainer,
second = stringResource(Res.string.feature_account_submitted) +
second = stringResource(Res.string.feature_account_submitted) + " " +
(
savingAccount.timeLine?.submittedOnDate?.let {
DateHelper.getDateAsString(
@ -114,7 +113,7 @@ private fun SavingsAccountListItem(
savingAccount.status?.matured == true -> {
Triple(
first = MaterialTheme.colorScheme.errorContainer,
second = stringResource(Res.string.feature_account_matured) +
second = stringResource(Res.string.feature_account_matured) + " " +
(
savingAccount.lastActiveTransactionDate?.let {
DateHelper.getDateAsString(
@ -129,38 +128,29 @@ private fun SavingsAccountListItem(
else -> {
Triple(
first = MaterialTheme.colorScheme.surfaceVariant,
second = stringResource(Res.string.feature_account_closed) + (
savingAccount.timeLine?.closedOnDate?.let {
DateHelper.getDateAsString(
it,
)
}
?: ""
),
second = stringResource(Res.string.feature_account_closed) + " " +
(
savingAccount.timeLine?.closedOnDate?.let {
DateHelper.getDateAsString(
it,
)
} ?: ""
),
third = null,
)
}
}
val currencySymbolOrCode =
savingAccount.currency?.displaySymbol ?: savingAccount.currency?.code ?: ""
val formattedBalance = CurrencyFormatter.format(
balance = savingAccount.accountBalance,
currencyCode = savingAccount.currency?.code,
maximumFractionDigits = 2,
)
val amountAndCurrency = stringResource(
Res.string.feature_account_string_and_string,
formattedBalance,
currencySymbolOrCode,
)
AccountCard(
savingAccount = savingAccount,
statusString = statusDescription,
balance = amountAndCurrency,
balance = formattedBalance,
indicatorColor = indicatorColor,
textColor = balanceTextColor,
onClick = {

View File

@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
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
@ -25,8 +26,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.launch
import mifos_mobile.feature.savings.generated.resources.Res
import mifos_mobile.feature.savings.generated.resources.apply_savings_account
import mifos_mobile.feature.savings.generated.resources.new_saving_account_created_successfully
import mifos_mobile.feature.savings.generated.resources.saving_account_updated_successfully
import mifos_mobile.feature.savings.generated.resources.update_savings_account
import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.stringResource
@ -44,13 +43,30 @@ internal fun SavingsAccountApplicationScreen(
viewModel: SavingsAccountApplicationViewModel = koinViewModel(),
) {
val uiState by viewModel.savingsAccountApplicationUiState.collectAsStateWithLifecycle()
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
SavingsAccountApplicationScreen(
uiState = uiState,
navigateBack = navigateBack,
submit = viewModel::onSubmit,
onRetry = viewModel::onRetry,
modifier = modifier,
snackbarHostState = snackbarHostState,
)
LaunchedEffect(Unit) {
viewModel.eventFlow.collect { event ->
when (event) {
is UiEvent.ShowSnackbar -> {
scope.launch {
snackbarHostState.showSnackbar(event.message)
}
}
UiEvent.NavigateBack -> navigateBack.invoke()
}
}
}
}
@Composable
@ -58,12 +74,13 @@ private fun SavingsAccountApplicationScreen(
uiState: SavingsAccountApplicationUiState,
navigateBack: () -> Unit,
submit: (Int, Int, showToast: (StringResource) -> Unit) -> Unit,
onRetry: () -> Unit,
snackbarHostState: SnackbarHostState,
modifier: Modifier = Modifier,
savingsWithAssociations: SavingsWithAssociations? = null,
) {
var topBarTitleText by rememberSaveable { mutableStateOf("") }
val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
MifosScaffold(
backPress = navigateBack,
@ -74,7 +91,9 @@ private fun SavingsAccountApplicationScreen(
Box(modifier = Modifier.padding(it)) {
when (uiState) {
is SavingsAccountApplicationUiState.Error -> {
MifosErrorComponent()
MifosErrorComponent(
onRetry = onRetry,
)
}
is SavingsAccountApplicationUiState.Loading -> {
@ -94,20 +113,6 @@ private fun SavingsAccountApplicationScreen(
savingsAccountTemplate = uiState.template,
)
}
is SavingsAccountApplicationUiState.Success -> {
val message = when (uiState.requestType) {
SavingsAccountState.CREATE ->
stringResource(Res.string.new_saving_account_created_successfully)
else ->
stringResource(Res.string.saving_account_updated_successfully)
}
scope.launch {
snackbarHostState.showSnackbar(message)
}
navigateBack.invoke()
}
}
}
},

View File

@ -13,23 +13,24 @@ import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import mifos_mobile.feature.savings.generated.resources.Res
import mifos_mobile.feature.savings.generated.resources.new_saving_account_created_successfully
import mifos_mobile.feature.savings.generated.resources.saving_account_updated_successfully
import mifos_mobile.feature.savings.generated.resources.select_product_id
import org.jetbrains.compose.resources.StringResource
import org.jetbrains.compose.resources.getString
import org.mifos.mobile.core.common.Constants
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.common.DateHelper
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import org.mifos.mobile.core.data.repository.SavingsAccountRepository
import org.mifos.mobile.core.datastore.UserPreferencesDataSource
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountApplicationPayload
@ -59,30 +60,43 @@ internal class SavingsAccountApplicationViewModel(
MutableStateFlow<SavingsAccountApplicationUiState>(Loading)
val savingsAccountApplicationUiState = _savingsAccountApplicationUiState.asStateFlow()
private val _savingsWithAssociations = MutableStateFlow<SavingsWithAssociations?>(null)
private val savingsWithAssociations = _savingsWithAssociations.asStateFlow()
init {
observeSavingsWithAssociations()
loadSavingsAccountApplicationTemplate()
}
private val _eventFlow = MutableSharedFlow<UiEvent>()
val eventFlow = _eventFlow.asSharedFlow()
@OptIn(ExperimentalCoroutinesApi::class)
private val savingsWithAssociations: StateFlow<SavingsWithAssociations?> = savingsId
.flatMapLatest { id ->
savingsAccountRepositoryImp.getSavingsWithAssociations(id, Constants.TRANSACTIONS)
.map { dataState ->
private fun observeSavingsWithAssociations() {
viewModelScope.launch {
savingsId
.flatMapLatest { id ->
savingsAccountRepositoryImp.getSavingsWithAssociations(id, Constants.TRANSACTIONS)
}
.collect { dataState ->
when (dataState) {
is DataState.Success -> dataState.data
else -> null
is DataState.Success -> {
_savingsWithAssociations.value = dataState.data
}
is DataState.Loading -> {
_savingsAccountApplicationUiState.value = Loading
}
is DataState.Error -> {
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.Error(dataState.exception.message)
}
}
}
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5000),
initialValue = null,
)
}
private fun loadSavingsAccountApplicationTemplate() {
viewModelScope.launch {
logger.d("_savingsAccountApplicationUiState: $_savingsAccountApplicationUiState")
_savingsAccountApplicationUiState.value = Loading
val clientIdValue = clientId.firstOrNull()
if (clientIdValue == null) {
@ -99,15 +113,21 @@ internal class SavingsAccountApplicationViewModel(
)
}
.collect { response ->
if (response.data != null) {
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.ShowUserInterface(
response.data!!,
savingsAccountState,
)
} else {
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.Error("Failed to load template. Data is null.")
when (response) {
is DataState.Error -> {
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.Error("Failed to load template. Data is null.")
}
DataState.Loading -> {
Loading
}
is DataState.Success -> {
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.ShowUserInterface(
response.data,
savingsAccountState,
)
}
}
}
}
@ -122,10 +142,16 @@ internal class SavingsAccountApplicationViewModel(
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.Error(response.message)
}
DataState.Loading -> TODO()
DataState.Loading -> Loading
is DataState.Success -> {
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.Success(savingsAccountState)
val messageRes = when (savingsAccountState) {
SavingsAccountState.CREATE -> Res.string.new_saving_account_created_successfully
else -> Res.string.saving_account_updated_successfully
}
_eventFlow.emit(UiEvent.ShowSnackbar(getString(messageRes)))
delay(1500)
_eventFlow.emit(UiEvent.NavigateBack)
}
}
}
@ -133,20 +159,28 @@ internal class SavingsAccountApplicationViewModel(
private fun updateSavingsAccount(accountId: Long?, payload: SavingsAccountUpdatePayload?) {
viewModelScope.launch {
_savingsAccountApplicationUiState.value = Loading
if (accountId == -1L) {
_eventFlow.emit(UiEvent.ShowSnackbar(getString(Res.string.select_product_id)))
return@launch
}
val response = savingsAccountRepositoryImp.updateSavingsAccount(accountId, payload)
when (response) {
is DataState.Error -> {
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.Error(response.message)
_eventFlow.emit(UiEvent.ShowSnackbar(response.exception.message ?: "Unknown error"))
}
DataState.Loading -> {
Loading
}
is DataState.Success -> {
_savingsAccountApplicationUiState.value =
SavingsAccountApplicationUiState.Success(savingsAccountState)
val messageRes = when (savingsAccountState) {
SavingsAccountState.CREATE -> Res.string.new_saving_account_created_successfully
else -> Res.string.saving_account_updated_successfully
}
_eventFlow.emit(UiEvent.ShowSnackbar(getString(messageRes)))
delay(1500)
_eventFlow.emit(UiEvent.NavigateBack)
}
}
}
@ -189,10 +223,14 @@ internal class SavingsAccountApplicationViewModel(
internal sealed class SavingsAccountApplicationUiState {
data object Loading : SavingsAccountApplicationUiState()
data class Error(val errorMessage: String?) : SavingsAccountApplicationUiState()
data class Success(val requestType: SavingsAccountState) : SavingsAccountApplicationUiState()
data class ShowUserInterface(
val template: SavingsAccountTemplate,
val requestType: SavingsAccountState,
) :
SavingsAccountApplicationUiState()
}
internal sealed class UiEvent {
data class ShowSnackbar(val message: String) : UiEvent()
data object NavigateBack : UiEvent()
}

View File

@ -35,7 +35,6 @@ import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import org.mifos.mobile.core.common.CurrencyFormatter
import org.mifos.mobile.core.common.DateHelper
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import org.mifos.mobile.core.model.entity.accounts.savings.Transactions
@Composable
@ -80,7 +79,6 @@ private fun SavingsAccountTransactionListItem(
transaction: Transactions,
modifier: Modifier = Modifier,
) {
logger.d { "ktorClient getting transactions in Ui $transaction" }
Row(
modifier = modifier
.fillMaxWidth()

View File

@ -15,10 +15,8 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -36,8 +34,8 @@ import mifos_mobile.feature.savings.generated.resources.account_number
import mifos_mobile.feature.savings.generated.resources.client_name
import mifos_mobile.feature.savings.generated.resources.error_validation_blank
import mifos_mobile.feature.savings.generated.resources.remark
import mifos_mobile.feature.savings.generated.resources.savings_account_withdraw_successful
import mifos_mobile.feature.savings.generated.resources.withdraw_savings_account
import mifos_mobile.feature.savings.generated.resources.withdrawal
import mifos_mobile.feature.savings.generated.resources.withdrawal_date
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel
@ -46,8 +44,10 @@ import org.mifos.mobile.core.designsystem.component.MifosButton
import org.mifos.mobile.core.designsystem.component.MifosOutlinedTextField
import org.mifos.mobile.core.designsystem.component.MifosScaffold
import org.mifos.mobile.core.designsystem.component.MifosTextFieldConfig
import org.mifos.mobile.core.designsystem.icon.MifosIcons
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations
import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay
import org.mifos.mobile.core.ui.component.EmptyDataView
import org.mifos.mobile.core.ui.component.MifosProgressIndicator
import org.mifos.mobile.core.ui.component.MifosTitleDescSingleLineEqual
@Composable
@ -58,25 +58,20 @@ internal fun SavingsAccountWithdrawScreen(
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val savingsWithAssociations by viewModel.savingsWithAssociations.collectAsStateWithLifecycle()
val message = stringResource(Res.string.savings_account_withdraw_successful)
val snackbarHostState = remember { SnackbarHostState() }
val scope = rememberCoroutineScope()
LaunchedEffect(uiState) {
if (uiState is SavingsAccountWithdrawUiState.Success) {
scope.launch {
val result = snackbarHostState.showSnackbar(
message = message,
duration = SnackbarDuration.Short,
)
if (result == SnackbarResult.Dismissed || result == SnackbarResult.ActionPerformed) {
navigateBack(true)
LaunchedEffect(Unit) {
viewModel.eventFlow.collect { event ->
when (event) {
is SavingsAccountWithdrawUiEvent.NavigateBack -> {
navigateBack.invoke(event.withDrawSuccess)
}
is SavingsAccountWithdrawUiEvent.ShowSnackbar -> {
scope.launch {
snackbarHostState.showSnackbar(event.message)
}
}
}
} else if (uiState is SavingsAccountWithdrawUiState.Error) {
scope.launch {
(uiState as SavingsAccountWithdrawUiState.Error).message?.let { snackbarHostState.showSnackbar(it) }
}
}
}
@ -84,7 +79,7 @@ internal fun SavingsAccountWithdrawScreen(
SavingsAccountWithdrawScreen(
uiState = uiState,
snackbarHostState = snackbarHostState,
savingsWithAssociations = savingsWithAssociations?.data,
savingsWithAssociations = savingsWithAssociations,
onBackPress = navigateBack,
withdraw = viewModel::submitWithdrawSavingsAccount,
modifier = modifier,
@ -105,17 +100,29 @@ private fun SavingsAccountWithdrawScreen(
backPress = { onBackPress(false) },
topBarTitle = stringResource(Res.string.withdraw_savings_account),
snackbarHost = { SnackbarHost(snackbarHostState) },
content = {
padding ->
content = { padding ->
Box(modifier = Modifier.padding(padding)) {
SavingsAccountWithdrawContent(
savingsWithAssociations = savingsWithAssociations,
withdraw = withdraw,
)
when (uiState) {
is SavingsAccountWithdrawUiState.Error -> EmptyDataView(
icon = MifosIcons.Error,
error = Res.string.withdrawal,
modifier = Modifier.fillMaxSize(),
)
SavingsAccountWithdrawUiState.Loading -> MifosProgressIndicator()
SavingsAccountWithdrawUiState.Ready,
SavingsAccountWithdrawUiState.Success,
-> {
SavingsAccountWithdrawContent(
savingsWithAssociations = savingsWithAssociations,
withdraw = withdraw,
)
}
if (uiState is SavingsAccountWithdrawUiState.Loading) {
MifosProgressIndicatorOverlay()
is SavingsAccountWithdrawUiState.Message -> SavingsAccountWithdrawContent(
savingsWithAssociations = savingsWithAssociations,
withdraw = withdraw,
)
}
}
},

View File

@ -12,82 +12,100 @@ package org.mifos.mobile.feature.savings.savingsAccountWithdraw
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import mifos_mobile.feature.savings.generated.resources.Res
import mifos_mobile.feature.savings.generated.resources.savings_account_withdraw_successful
import org.jetbrains.compose.resources.getString
import org.mifos.mobile.core.common.Constants
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.common.DateHelper
import org.mifos.mobile.core.data.repository.SavingsAccountRepository
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsAccountWithdrawPayload
import org.mifos.mobile.feature.savings.savingsAccountWithdraw.SavingsAccountWithdrawUiState.WithdrawUiReady
import org.mifos.mobile.core.model.entity.accounts.savings.SavingsWithAssociations
internal class SavingsAccountWithdrawViewModel(
private val savingsAccountRepositoryImp: SavingsAccountRepository,
savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val mUiState = MutableStateFlow<SavingsAccountWithdrawUiState>(WithdrawUiReady)
private val mUiState = MutableStateFlow<SavingsAccountWithdrawUiState>(SavingsAccountWithdrawUiState.Loading)
val uiState = mUiState.asStateFlow()
private val mSnackbar = MutableStateFlow<String>("")
val snackbarMessage = mSnackbar.asStateFlow()
private val savingsId: Long = savedStateHandle[Constants.SAVINGS_ID] ?: -1L
private val savingsId: StateFlow<Long> = savedStateHandle.getStateFlow(
key = Constants.SAVINGS_ID,
initialValue = -1L,
)
private val _savingsWithAssociations = MutableStateFlow<SavingsWithAssociations?>(null)
val savingsWithAssociations = _savingsWithAssociations.asStateFlow()
@OptIn(ExperimentalCoroutinesApi::class)
val savingsWithAssociations = savingsId
.flatMapLatest {
private val _eventFlow = MutableSharedFlow<SavingsAccountWithdrawUiEvent>()
val eventFlow = _eventFlow.asSharedFlow()
init {
fetchSavingsAccountWithAssociations()
}
private fun fetchSavingsAccountWithAssociations() {
viewModelScope.launch {
savingsAccountRepositoryImp.getSavingsWithAssociations(
savingsId.value,
savingsId,
Constants.TRANSACTIONS,
)
).collect { result ->
when (result) {
is DataState.Success -> {
_savingsWithAssociations.value = result.data
mUiState.value = SavingsAccountWithdrawUiState.Ready
}
is DataState.Error -> {
_savingsWithAssociations.value = null
mUiState.value = SavingsAccountWithdrawUiState.Error
}
is DataState.Loading -> {
mUiState.value = SavingsAccountWithdrawUiState.Loading
}
}
}
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = null,
)
}
fun submitWithdrawSavingsAccount(remark: String) {
val accountNo = savingsWithAssociations.value?.accountNo ?: return
val payload = SavingsAccountWithdrawPayload(
note = remark,
withdrawnOnDate = DateHelper.formattedFullDate,
dateFormat = "dd MMMM yyyy",
locale = "en",
)
viewModelScope.launch {
mUiState.value = SavingsAccountWithdrawUiState.Loading
val response = savingsAccountRepositoryImp.submitWithdrawSavingsAccount(
savingsWithAssociations.value?.data?.accountNo,
payload,
)
when (response) {
is DataState.Error -> {
mUiState.value =
SavingsAccountWithdrawUiState.Error(response.message)
}
DataState.Loading -> {
SavingsAccountWithdrawUiState.Loading
}
when (val response = savingsAccountRepositoryImp.submitWithdrawSavingsAccount(accountNo, payload)) {
is DataState.Success -> {
mUiState.value = SavingsAccountWithdrawUiState.Success
val message = getString(Res.string.savings_account_withdraw_successful)
_eventFlow.emit(SavingsAccountWithdrawUiEvent.ShowSnackbar(message))
delay(1500)
_eventFlow.emit(SavingsAccountWithdrawUiEvent.NavigateBack(true))
}
is DataState.Error -> mUiState.value = SavingsAccountWithdrawUiState.Message(response.message)
is DataState.Loading -> mUiState.value = SavingsAccountWithdrawUiState.Loading
}
}
}
}
internal sealed interface SavingsAccountWithdrawUiState {
data object WithdrawUiReady : SavingsAccountWithdrawUiState
data object Ready : SavingsAccountWithdrawUiState
data object Loading : SavingsAccountWithdrawUiState
data object Success : SavingsAccountWithdrawUiState
data class Error(val message: String?) : SavingsAccountWithdrawUiState
data object Error : SavingsAccountWithdrawUiState
data class Message(val message: String?) : SavingsAccountWithdrawUiState
}
internal sealed interface SavingsAccountWithdrawUiEvent {
data class ShowSnackbar(val message: String) : SavingsAccountWithdrawUiEvent
data class NavigateBack(val withDrawSuccess: Boolean) : SavingsAccountWithdrawUiEvent
}

View File

@ -18,7 +18,6 @@ import mifos_mobile.feature.third_party_transfer.generated.resources.Res
import mifos_mobile.feature.third_party_transfer.generated.resources.internet_not_connected
import org.jetbrains.compose.resources.getString
import org.mifos.mobile.core.common.DataState
import org.mifos.mobile.core.common.FileUtils.Companion.logger
import org.mifos.mobile.core.data.repository.BeneficiaryRepository
import org.mifos.mobile.core.data.repository.ThirdPartyTransferRepository
import org.mifos.mobile.core.data.util.NetworkMonitor
@ -81,10 +80,6 @@ internal class ThirdPartyTransferViewModel(
transferRepository.thirdPartyTransferTemplate(),
beneficiaryRepository.beneficiaryList(),
) { templateResult, beneficiariesResult ->
logger.d {
"KtorClient getting in function ${templateResult.data} and ben " +
"${beneficiariesResult.data}"
}
updateStateFromResults(templateResult, beneficiariesResult)
}.catch { error ->
updateState {
@ -105,7 +100,6 @@ internal class ThirdPartyTransferViewModel(
val error = (templateResult as? DataState.Error)?.exception?.message
?: (beneficiariesResult as? DataState.Error)?.exception?.message
?: "An error occurred"
logger.d { "KtorClient error $error" }
val errorMessage = "An error occurred"
updateState { it.copy(dialogState = ThirdPartyTransferState.DialogState.Error(errorMessage)) }
}

View File

@ -26,7 +26,6 @@ import org.mifos.mobile.core.data.repository.TransferRepository
import org.mifos.mobile.core.model.IgnoredOnParcel
import org.mifos.mobile.core.model.Parcelable
import org.mifos.mobile.core.model.Parcelize
import org.mifos.mobile.core.model.entity.TransferResponse
import org.mifos.mobile.core.model.entity.TransferSuccessDestination
import org.mifos.mobile.core.model.entity.payload.TransferPayload
import org.mifos.mobile.core.model.enums.TransferType
@ -57,7 +56,9 @@ internal class TransferProcessViewModel(
updateState {
it.copy(
transferPayload = state.transferPayloadString?.let { jsonString ->
jsonString.let { Json.decodeFromString<TransferPayload>(jsonString) }
jsonString.let {
Json.decodeFromString<TransferPayload>(it)
}
},
)
}
@ -97,21 +98,24 @@ internal class TransferProcessViewModel(
}
private fun processTransferResult(
response: DataState<TransferResponse>,
response: DataState<String>,
message: String,
) {
when (response) {
is DataState.Error -> {
updateState {
it.copy(dialogState = TransferProcessState.DialogState.Error(response.message))
}
updateState { it.copy(dialogState = null) }
sendEvent(
TransferProcessEvent.ShowToast(
response.message,
),
)
}
DataState.Loading -> TransferProcessState.DialogState.Loading
is DataState.Success -> {
updateState { it.copy(dialogState = null) }
sendEvent(
TransferProcessEvent.ShowToast(
message + "with ID ${response.data.resourceId}",
message + "with ID ${response.data}",
),
)
viewModelScope.launch {

View File

@ -87,7 +87,7 @@ private fun ReviewTransferPayload.convertToTransferPayloadString(): String {
fromClientId = this.payFromAccount?.clientId,
fromAccountType = this.payFromAccount?.accountType?.id,
fromOfficeId = this.payFromAccount?.officeId,
toOfficeId = this.payFromAccount?.officeId,
toOfficeId = this.payToAccount?.officeId,
toAccountId = this.payToAccount?.accountNo,
toClientId = this.payToAccount?.clientId,
toAccountType = this.payToAccount?.accountType?.id,

View File

@ -217,7 +217,6 @@ internal class UserDetailViewModel(
e.message ?: "An error occurred",
),
)
logger.d { "Notifications@@@ $e" }
}.collect { userDetail ->
when (userDetail) {
is DataState.Error -> {
@ -248,7 +247,6 @@ internal class UserDetailViewModel(
val result = userDetailRepositoryImp.updateRegisterNotification(id, payload)
when (result) {
is DataState.Error -> {
logger.d { "Notifications@@@ ${result.message}" }
setDialogState(
UserDetailState.DialogState.Error(
result.message,

View File

@ -10,7 +10,6 @@ androidxComposeBom = "2024.12.01"
androidxComposeCompiler = "1.5.15"
androidxCoreSplashscreen = "1.0.1"
androidxEspresso = "3.6.1"
androidxHilt = "1.2.0"
androidxLifecycle = "2.8.7"
androidxMetrics = "1.0.0-beta01"
androidxNavigation = "2.8.5"
@ -40,9 +39,6 @@ googleAppCodeScanner = "17.3.0"
googleMaps = "4.4.1"
googleOss = "17.1.0"
googleOssPlugin = "0.10.6"
gsonVersion = "2.10.1"
hilt = "2.54"
hiltExt = "1.2.0"
jacoco = "0.8.7"
junitVersion = "4.13.2"
ktlint = "12.1.1"
@ -56,7 +52,6 @@ multidexVersion = "2.0.1"
okHttp3Version = "4.12.0"
playServicesCodeScanner = "16.1.0"
playServicesVersion = "19.0.0"
retrofitVersion = "2.11.0"
roborazzi = "1.26.0"
room = "2.7.0-alpha12"
sqliteBundled = "2.5.0-alpha12"
@ -160,7 +155,6 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u
androidx-compose-ui-util = { group = "androidx.compose.ui", name = "ui-util" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidxCoreSplashscreen" }
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-livedata-ktx = { group = "androidx.lifecycle", name = "lifecycle-livedata-ktx", version.ref = "lifecycleLivedataKtxVersion" }
@ -199,13 +193,6 @@ google-map-compose = { group = "com.google.maps.android", name = "maps-compose",
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" }
gson = { group = "com.google.code.gson", name = "gson", version.ref = "gsonVersion" }
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-compiler", version.ref = "hilt" }
hilt-core = { group = "com.google.dagger", name = "hilt-core", version.ref = "hilt" }
hilt-ext-compiler = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "hiltExt" }
hilt-ext-work = { group = "androidx.hilt", name = "hilt-work", version.ref = "hiltExt" }
jetbrains-kotlin-jdk7 = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk7", version.ref = "kotlin" }
junit = { group = "junit", name = "junit", version.ref = "junitVersion" }
ktlint-gradlePlugin = { group = "org.jlleitschuh.gradle", name = "ktlint-gradle", version.ref = "ktlint" }
@ -222,9 +209,6 @@ slack-compose-lint = { group = "com.slack.lint.compose", name = "compose-lint-ch
spotless-gradlePlugin = { 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-rxjava2", 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" }
turbine = { group = "app.cash.turbine", name = "turbine", version.ref = "turbineVersion" }
twitter-detekt-compose = { group = "com.twitter.compose.rules", name = "detekt", version.ref = "twitter-detekt-compose" }
@ -343,11 +327,9 @@ android-library = { id = "com.android.library", version.ref = "androidGradlePlug
android-test = { id = "com.android.test", version.ref = "androidGradlePlugin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
# Hilt & Room Plugins
hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
# Room Plugins
room = { id = "androidx.room", version.ref = "room" }
mifos-android-hilt = { id = "mifos.android.hilt", version = "unspecified" }
mifos-kmp-room = { id = "mifos.kmp.room", version = "unspecified" }
mifos-android-application = { id = "mifos.android.application", version = "unspecified" }
mifos-android-application-compose = { id = "mifos.android.application.compose", version = "unspecified" }