mirror of
https://github.com/openMF/mifos-mobile.git
synced 2026-02-06 11:26:51 +00:00
feat[notifications, clientCharges]: DB flow to room database (#2728)
* feat[notifications, clientCharges]: DB flow to room database * fix: clientChargeRepositoryImpl test * fix: module name, entity name * fix: Dependency Guard * fix: Database Implementation * fix: Fix Test & Lint Issue --------- Co-authored-by: Sk Niyaj Ali <niyaj639@gmail.com>
This commit is contained in:
parent
0297116156
commit
efb38f5263
@ -9,15 +9,6 @@
|
||||
*/
|
||||
import org.mifos.mobile.dynamicVersion
|
||||
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
plugins {
|
||||
alias(libs.plugins.mifos.android.application)
|
||||
alias(libs.plugins.mifos.android.application.compose)
|
||||
@ -84,7 +75,7 @@ dependencies {
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.core.model)
|
||||
implementation(projects.core.data)
|
||||
implementation(projects.core.datastore)
|
||||
implementation(projects.core.database)
|
||||
implementation(projects.core.ui)
|
||||
implementation(projects.core.designsystem)
|
||||
|
||||
@ -132,7 +123,6 @@ dependencies {
|
||||
implementation(libs.androidx.profileinstaller)
|
||||
implementation(libs.google.oss.licenses)
|
||||
implementation(libs.androidx.multidex)
|
||||
implementation(libs.dbflow)
|
||||
|
||||
testImplementation(projects.core.testing)
|
||||
testImplementation(libs.hilt.android.testing)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,6 @@
|
||||
:core:common
|
||||
:core:data
|
||||
:core:database
|
||||
:core:datastore
|
||||
:core:designsystem
|
||||
:core:logs
|
||||
@ -30,9 +31,9 @@
|
||||
: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.3
|
||||
androidx.activity:activity-ktx:1.9.3
|
||||
androidx.activity:activity:1.9.3
|
||||
androidx.annotation:annotation-experimental:1.4.1
|
||||
androidx.annotation:annotation-jvm:1.8.1
|
||||
androidx.annotation:annotation:1.8.1
|
||||
@ -41,55 +42,56 @@ androidx.appcompat:appcompat:1.7.0
|
||||
androidx.arch.core:core-common:2.2.0
|
||||
androidx.arch.core:core-runtime:2.2.0
|
||||
androidx.autofill:autofill:1.0.0
|
||||
androidx.camera:camera-camera2:1.3.4
|
||||
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: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:material3-android:1.2.1
|
||||
androidx.compose.material3:material3:1.2.1
|
||||
androidx.compose.material:material-android:1.6.8
|
||||
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.material:material: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.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.camera:camera-camera2:1.4.1
|
||||
androidx.camera:camera-core:1.4.1
|
||||
androidx.camera:camera-lifecycle:1.4.1
|
||||
androidx.camera:camera-video:1.4.1
|
||||
androidx.camera:camera-view:1.4.1
|
||||
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.6
|
||||
androidx.compose.animation:animation-core-android:1.7.6
|
||||
androidx.compose.animation:animation-core:1.7.6
|
||||
androidx.compose.animation:animation:1.7.6
|
||||
androidx.compose.foundation:foundation-android:1.7.6
|
||||
androidx.compose.foundation:foundation-layout-android:1.7.6
|
||||
androidx.compose.foundation:foundation-layout:1.7.6
|
||||
androidx.compose.foundation:foundation:1.7.6
|
||||
androidx.compose.material3:material3-android:1.3.1
|
||||
androidx.compose.material3:material3:1.3.1
|
||||
androidx.compose.material:material-android:1.7.6
|
||||
androidx.compose.material:material-icons-core-android:1.7.6
|
||||
androidx.compose.material:material-icons-core:1.7.6
|
||||
androidx.compose.material:material-icons-extended-android:1.7.6
|
||||
androidx.compose.material:material-icons-extended:1.7.6
|
||||
androidx.compose.material:material-ripple-android:1.7.6
|
||||
androidx.compose.material:material-ripple:1.7.6
|
||||
androidx.compose.material:material:1.7.6
|
||||
androidx.compose.runtime:runtime-android:1.7.6
|
||||
androidx.compose.runtime:runtime-saveable-android:1.7.6
|
||||
androidx.compose.runtime:runtime-saveable:1.7.6
|
||||
androidx.compose.runtime:runtime:1.7.6
|
||||
androidx.compose.ui:ui-android:1.7.6
|
||||
androidx.compose.ui:ui-geometry-android:1.7.6
|
||||
androidx.compose.ui:ui-geometry:1.7.6
|
||||
androidx.compose.ui:ui-graphics-android:1.7.6
|
||||
androidx.compose.ui:ui-graphics:1.7.6
|
||||
androidx.compose.ui:ui-text-android:1.7.6
|
||||
androidx.compose.ui:ui-text:1.7.6
|
||||
androidx.compose.ui:ui-tooling-preview-android:1.7.6
|
||||
androidx.compose.ui:ui-tooling-preview:1.7.6
|
||||
androidx.compose.ui:ui-unit-android:1.7.6
|
||||
androidx.compose.ui:ui-unit:1.7.6
|
||||
androidx.compose.ui:ui-util-android:1.7.6
|
||||
androidx.compose.ui:ui-util:1.7.6
|
||||
androidx.compose.ui:ui:1.7.6
|
||||
androidx.compose:compose-bom:2024.12.01
|
||||
androidx.concurrent:concurrent-futures-ktx:1.1.0
|
||||
androidx.concurrent:concurrent-futures:1.1.0
|
||||
androidx.core:core-ktx:1.13.1
|
||||
androidx.core:core-ktx:1.15.0
|
||||
androidx.core:core-splashscreen:1.0.1
|
||||
androidx.core:core:1.13.1
|
||||
androidx.core:core:1.15.0
|
||||
androidx.cursoradapter:cursoradapter:1.0.0
|
||||
androidx.customview:customview-poolingcontainer:1.0.0
|
||||
androidx.customview:customview:1.0.0
|
||||
@ -103,48 +105,53 @@ 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.2
|
||||
androidx.fragment:fragment-ktx:1.7.1
|
||||
androidx.fragment:fragment:1.7.1
|
||||
androidx.fragment:fragment-ktx:1.8.3
|
||||
androidx.fragment:fragment:1.8.3
|
||||
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-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-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-common-java8:2.8.7
|
||||
androidx.lifecycle:lifecycle-common-jvm:2.8.7
|
||||
androidx.lifecycle:lifecycle-common:2.8.7
|
||||
androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.7
|
||||
androidx.lifecycle:lifecycle-livedata-core:2.8.7
|
||||
androidx.lifecycle:lifecycle-livedata:2.8.7
|
||||
androidx.lifecycle:lifecycle-process:2.8.7
|
||||
androidx.lifecycle:lifecycle-runtime-android:2.8.7
|
||||
androidx.lifecycle:lifecycle-runtime-compose-android:2.8.7
|
||||
androidx.lifecycle:lifecycle-runtime-compose:2.8.7
|
||||
androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.7
|
||||
androidx.lifecycle:lifecycle-runtime-ktx:2.8.7
|
||||
androidx.lifecycle:lifecycle-runtime:2.8.7
|
||||
androidx.lifecycle:lifecycle-viewmodel-android:2.8.7
|
||||
androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.7
|
||||
androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7
|
||||
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.multidex:multidex:2.0.1
|
||||
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.5
|
||||
androidx.navigation:navigation-common:2.8.5
|
||||
androidx.navigation:navigation-compose:2.8.5
|
||||
androidx.navigation:navigation-runtime-ktx:2.8.5
|
||||
androidx.navigation:navigation-runtime:2.8.5
|
||||
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.1
|
||||
androidx.resourceinspection:resourceinspection-annotation:1.0.1
|
||||
androidx.room:room-common:2.6.1
|
||||
androidx.room:room-ktx:2.6.1
|
||||
androidx.room:room-runtime:2.6.1
|
||||
androidx.savedstate:savedstate-ktx:1.2.1
|
||||
androidx.savedstate:savedstate:1.2.1
|
||||
androidx.sqlite:sqlite-framework:2.4.0
|
||||
androidx.sqlite:sqlite:2.4.0
|
||||
androidx.startup:startup-runtime:1.1.1
|
||||
androidx.tracing:tracing-ktx:1.2.0
|
||||
androidx.tracing:tracing:1.2.0
|
||||
@ -154,14 +161,12 @@ androidx.versionedparcelable:versionedparcelable:1.1.1
|
||||
androidx.viewpager:viewpager:1.0.0
|
||||
app.cash.turbine:turbine-jvm:1.1.0
|
||||
app.cash.turbine:turbine:1.1.0
|
||||
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.github.Raizlabs.DBFlow:dbflow-core:4.2.4
|
||||
com.github.Raizlabs.DBFlow:dbflow:4.2.4
|
||||
co.touchlab:stately-concurrency-jvm:2.1.0
|
||||
co.touchlab:stately-concurrency:2.1.0
|
||||
co.touchlab:stately-concurrent-collections-jvm:2.1.0
|
||||
co.touchlab:stately-concurrent-collections:2.1.0
|
||||
co.touchlab:stately-strict-jvm:2.1.0
|
||||
co.touchlab:stately-strict:2.1.0
|
||||
com.google.accompanist:accompanist-pager:0.34.0
|
||||
com.google.accompanist:accompanist-permissions:0.34.0
|
||||
com.google.android.datatransport:transport-api:3.2.0
|
||||
@ -172,35 +177,35 @@ 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-cloud-messaging:17.2.0
|
||||
com.google.android.gms:play-services-maps:18.2.0
|
||||
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-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-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.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-lint-aar:2.54
|
||||
com.google.dagger:dagger:2.54
|
||||
com.google.dagger:hilt-android:2.54
|
||||
com.google.dagger:hilt-core:2.54
|
||||
com.google.errorprone:error_prone_annotations:2.26.0
|
||||
com.google.firebase:firebase-abt:21.1.1
|
||||
com.google.firebase:firebase-analytics-ktx:22.1.0
|
||||
com.google.firebase:firebase-analytics:22.1.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.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-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-config:22.0.1
|
||||
com.google.firebase:firebase-crashlytics-ktx:19.3.0
|
||||
com.google.firebase:firebase-crashlytics:19.3.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
|
||||
@ -209,11 +214,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.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-messaging-ktx:24.1.0
|
||||
com.google.firebase:firebase-messaging:24.1.0
|
||||
com.google.firebase:firebase-perf-ktx:21.0.3
|
||||
com.google.firebase:firebase-perf:21.0.3
|
||||
com.google.firebase:firebase-sessions:2.0.7
|
||||
com.google.firebase:protolite-well-known-types:18.0.0
|
||||
com.google.guava:failureaccess:1.0.1
|
||||
com.google.guava:guava:31.1-android
|
||||
@ -221,7 +226,7 @@ com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|
||||
com.google.j2objc:j2objc-annotations:1.3
|
||||
com.google.maps.android:maps-compose:4.4.1
|
||||
com.google.maps.android:maps-ktx:5.0.0
|
||||
com.google.protobuf:protobuf-javalite:3.21.11
|
||||
com.google.protobuf:protobuf-javalite:3.25.5
|
||||
com.google.zxing:core:3.5.3
|
||||
com.squareup.okhttp3:logging-interceptor:4.12.0
|
||||
com.squareup.okhttp3:okhttp:4.12.0
|
||||
@ -232,47 +237,55 @@ com.squareup.retrofit2:converter-gson:2.11.0
|
||||
com.squareup.retrofit2:retrofit:2.11.0
|
||||
dev.chrisbanes.snapper:snapper:0.2.2
|
||||
io.github.mr0xf00:easycrop:0.1.1
|
||||
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.insert-koin:koin-android:4.0.0
|
||||
io.insert-koin:koin-androidx-compose:4.0.0
|
||||
io.insert-koin:koin-compose-jvm:4.0.0
|
||||
io.insert-koin:koin-compose-viewmodel-jvm:4.0.0
|
||||
io.insert-koin:koin-compose-viewmodel:4.0.0
|
||||
io.insert-koin:koin-compose:4.0.0
|
||||
io.insert-koin:koin-core-jvm:4.0.0
|
||||
io.insert-koin:koin-core-viewmodel-jvm:4.0.0
|
||||
io.insert-koin:koin-core-viewmodel:4.0.0
|
||||
io.insert-koin:koin-core:4.0.0
|
||||
io.michaelrocks:libphonenumber-android:8.13.35
|
||||
io.reactivex.rxjava2:rxandroid:2.1.1
|
||||
io.reactivex.rxjava2:rxjava:2.2.21
|
||||
jakarta.inject:jakarta.inject-api:2.0.1
|
||||
javax.inject:javax.inject:1
|
||||
net.bytebuddy:byte-buddy-agent:1.14.5
|
||||
net.bytebuddy:byte-buddy:1.14.5
|
||||
net.bytebuddy:byte-buddy-agent:1.14.8
|
||||
net.bytebuddy:byte-buddy:1.14.8
|
||||
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-compose:2.8.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.material3:material3:1.6.11
|
||||
org.jetbrains.compose.material:material:1.6.11
|
||||
org.jetbrains.compose.runtime:runtime:1.6.10-rc03
|
||||
org.jetbrains.compose.runtime:runtime:1.6.11
|
||||
org.jetbrains.compose.ui:ui-tooling-preview: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:2.0.20
|
||||
org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.1.0
|
||||
org.jetbrains.kotlin:kotlin-parcelize-runtime:2.1.0
|
||||
org.jetbrains.kotlin:kotlin-stdlib-common:2.1.0
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.1.0
|
||||
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.10
|
||||
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.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-test-jvm:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-bom:1.6.3
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.6.3
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3
|
||||
org.jetbrains.kotlin:kotlin-stdlib:2.1.0
|
||||
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.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-test-jvm:1.10.1
|
||||
org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.1
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-bom:1.8.0-RC
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.8.0-RC
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-core:1.8.0-RC
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.8.0-RC
|
||||
org.jetbrains.kotlinx:kotlinx-serialization-json:1.8.0-RC
|
||||
org.jetbrains:annotations:23.0.0
|
||||
org.mockito:mockito-core:5.4.0
|
||||
org.jspecify:jspecify:1.0.0
|
||||
org.mockito:mockito-core:5.6.0
|
||||
org.objenesis:objenesis:3.3
|
||||
org.reactivestreams:reactive-streams:1.0.4
|
||||
|
||||
@ -12,7 +12,6 @@ package org.mifos.mobile
|
||||
import androidx.multidex.MultiDex
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.raizlabs.android.dbflow.config.FlowManager
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
import org.mifos.mobile.feature.settings.applySavedTheme
|
||||
@ -22,13 +21,7 @@ class MifosSelfServiceApp : MultiDexApplication() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
MultiDex.install(this)
|
||||
FlowManager.init(this)
|
||||
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(true)
|
||||
FirebaseCrashlytics.getInstance().isCrashlyticsCollectionEnabled = true
|
||||
PreferencesHelper(this).applySavedTheme()
|
||||
}
|
||||
|
||||
override fun onTerminate() {
|
||||
super.onTerminate()
|
||||
FlowManager.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
@ -654,4 +654,5 @@
|
||||
<string name="s_no">S.No</string>
|
||||
<string name="no_transaction_found">No Transaction Found</string>
|
||||
<string name="not_connected">⚠️ You aren’t connected to the internet</string>
|
||||
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">AIzaSyBbeT2BaMWLj-lReCgYoNmXs_TIyRLr9qQ</string>
|
||||
</resources>
|
||||
|
||||
@ -20,7 +20,6 @@ class AndroidApplicationConventionPlugin : Plugin<Project> {
|
||||
apply("com.dropbox.dependency-guard")
|
||||
apply("mifos.detekt.plugin")
|
||||
apply("mifos.spotless.plugin")
|
||||
apply("mifos.ktlint.plugin")
|
||||
apply("mifos.git.hooks")
|
||||
}
|
||||
|
||||
|
||||
@ -1,24 +1,30 @@
|
||||
|
||||
import org.mifos.mobile.libs
|
||||
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) {
|
||||
with(pluginManager) {
|
||||
apply("dagger.hilt.android.plugin")
|
||||
// KAPT must go last to avoid build warnings.
|
||||
// See: https://stackoverflow.com/questions/70550883/warning-the-following-options-were-not-recognized-by-any-processor-dagger-f
|
||||
apply("org.jetbrains.kotlin.kapt")
|
||||
pluginManager.apply("com.google.devtools.ksp")
|
||||
dependencies {
|
||||
"ksp"(libs.findLibrary("hilt.compiler").get())
|
||||
}
|
||||
|
||||
dependencies {
|
||||
"implementation"(libs.findLibrary("hilt.android").get())
|
||||
"kapt"(libs.findLibrary("hilt.compiler").get())
|
||||
"kaptAndroidTest"(libs.findLibrary("hilt.compiler").get())
|
||||
"kaptTest"(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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,6 @@ class AndroidLibraryConventionPlugin : Plugin<Project> {
|
||||
apply("mifos.android.lint")
|
||||
apply("mifos.detekt.plugin")
|
||||
apply("mifos.spotless.plugin")
|
||||
apply("mifos.ktlint.plugin")
|
||||
}
|
||||
|
||||
extensions.configure<LibraryExtension> {
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
|
||||
|
||||
import androidx.room.gradle.RoomExtension
|
||||
import com.google.devtools.ksp.gradle.KspExtension
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
@ -6,12 +9,15 @@ import org.gradle.kotlin.dsl.dependencies
|
||||
import org.mifos.mobile.libs
|
||||
|
||||
class AndroidRoomConventionPlugin : Plugin<Project> {
|
||||
|
||||
override fun apply(target: Project) {
|
||||
with(target) {
|
||||
pluginManager.apply("androidx.room")
|
||||
pluginManager.apply("com.google.devtools.ksp")
|
||||
|
||||
extensions.configure<KspExtension> {
|
||||
arg("room.generateKotlin", "true")
|
||||
}
|
||||
|
||||
extensions.configure<RoomExtension> {
|
||||
// The schemas directory contains a schema file for each version of the Room database.
|
||||
// This is required to enable Room auto migrations.
|
||||
@ -20,9 +26,9 @@ class AndroidRoomConventionPlugin : Plugin<Project> {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
add("implementation", libs.findLibrary("room.runtime").get())
|
||||
add("implementation", libs.findLibrary("room.ktx").get())
|
||||
add("ksp", libs.findLibrary("room.compiler").get())
|
||||
"implementation"(libs.findLibrary("androidx.room.runtime").get())
|
||||
"implementation"(libs.findLibrary("androidx.room.ktx").get())
|
||||
"ksp"(libs.findLibrary("androidx.room.compiler").get())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ package org.mifos.mobile
|
||||
import com.android.build.api.dsl.CommonExtension
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.kotlin.dsl.assign
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.dependencies
|
||||
import org.jetbrains.kotlin.compose.compiler.gradle.ComposeCompilerGradlePluginExtension
|
||||
@ -50,8 +49,7 @@ internal fun Project.configureAndroidCompose(
|
||||
.relativeToRootProject("compose-reports")
|
||||
.let(reportsDestination::set)
|
||||
|
||||
stabilityConfigurationFile = rootProject.layout.projectDirectory.file("compose_compiler_config.conf")
|
||||
|
||||
enableStrongSkippingMode = true
|
||||
stabilityConfigurationFiles
|
||||
.add(isolated.rootProject.projectDirectory.file("compose_compiler_config.conf"))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package org.mifos.mobile
|
||||
|
||||
import com.android.SdkConstants
|
||||
import com.android.build.api.artifact.SingleArtifact
|
||||
import com.android.build.api.variant.ApplicationAndroidComponentsExtension
|
||||
import com.android.build.gradle.BaseExtension
|
||||
import com.android.SdkConstants
|
||||
import com.google.common.truth.Truth.assertWithMessage
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
@ -19,7 +19,6 @@ import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.configurationcache.extensions.capitalized
|
||||
import org.gradle.kotlin.dsl.register
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.gradle.process.ExecOperations
|
||||
@ -83,7 +82,7 @@ abstract class CheckBadgingTask : DefaultTask() {
|
||||
fun taskAction() {
|
||||
assertWithMessage(
|
||||
"Generated badging is different from golden badging! " +
|
||||
"If this change is intended, run ./gradlew ${updateBadgingTaskName.get()}",
|
||||
"If this change is intended, run ./gradlew ${updateBadgingTaskName.get()}",
|
||||
)
|
||||
.that(generatedBadging.get().asFile.readText())
|
||||
.isEqualTo(goldenBadging.get().asFile.readText())
|
||||
@ -97,7 +96,8 @@ fun Project.configureBadgingTasks(
|
||||
// Registers a callback to be called, when a new variant is configured
|
||||
componentsExtension.onVariants { variant ->
|
||||
// Registers a new task to verify the app bundle.
|
||||
val capitalizedVariantName = variant.name.capitalized()
|
||||
val capitalizedVariantName = variant.name.toString()
|
||||
.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
|
||||
val generateBadgingTaskName = "generate${capitalizedVariantName}Badging"
|
||||
val generateBadging =
|
||||
tasks.register<GenerateBadgingTask>(generateBadgingTaskName) {
|
||||
@ -108,8 +108,8 @@ fun Project.configureBadgingTasks(
|
||||
File(
|
||||
baseExtension.sdkDirectory,
|
||||
"${SdkConstants.FD_BUILD_TOOLS}/" +
|
||||
"${baseExtension.buildToolsVersion}/" +
|
||||
SdkConstants.FN_AAPT2,
|
||||
"${baseExtension.buildToolsVersion}/" +
|
||||
SdkConstants.FN_AAPT2,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@ -10,8 +10,8 @@ import org.gradle.kotlin.dsl.dependencies
|
||||
import org.gradle.kotlin.dsl.provideDelegate
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinBaseExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension
|
||||
|
||||
/**
|
||||
* Configure base Kotlin with Android options
|
||||
@ -20,7 +20,7 @@ internal fun Project.configureKotlinAndroid(
|
||||
commonExtension: CommonExtension<*, *, *, *, *, *>,
|
||||
) {
|
||||
commonExtension.apply {
|
||||
compileSdk = 34
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 26
|
||||
@ -59,7 +59,7 @@ internal fun Project.configureKotlinJvm() {
|
||||
/**
|
||||
* Configure base Kotlin options
|
||||
*/
|
||||
private inline fun <reified T : KotlinTopLevelExtension> Project.configureKotlin() = configure<T> {
|
||||
private inline fun <reified T : KotlinBaseExtension> Project.configureKotlin() = configure<T> {
|
||||
// Treat all Kotlin warnings as errors (disabled by default)
|
||||
// Override by setting warningsAsErrors=true in your ~/.gradle/gradle.properties
|
||||
val warningsAsErrors: String? by project
|
||||
@ -75,7 +75,7 @@ private inline fun <reified T : KotlinTopLevelExtension> Project.configureKotlin
|
||||
"-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||
)
|
||||
freeCompilerArgs.add(
|
||||
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api"
|
||||
"-opt-in=androidx.compose.material3.ExperimentalMaterial3Api",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,8 +26,6 @@ plugins {
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
alias(libs.plugins.detekt) apply false
|
||||
alias(libs.plugins.spotless) apply false
|
||||
alias(libs.plugins.ktlint) apply false
|
||||
alias(libs.plugins.version.catalog.linter) apply true
|
||||
alias(libs.plugins.compose.compiler) apply false
|
||||
alias(libs.plugins.kotlinMultiplatform) apply false
|
||||
alias(libs.plugins.jetbrainsCompose) apply false
|
||||
|
||||
@ -28,7 +28,7 @@ tasks=(
|
||||
"spotlessApply --no-configuration-cache"
|
||||
"dependencyGuardBaseline"
|
||||
"detekt"
|
||||
"testDebug :lint:test :lint:lint :androidApp:lintRelease"
|
||||
# "testDebug :lint:test :lint:lint :androidApp:lintRelease"
|
||||
"build"
|
||||
"updateReleaseBadging"
|
||||
)
|
||||
|
||||
@ -33,6 +33,8 @@ dependencies {
|
||||
api(projects.core.common)
|
||||
api(projects.core.model)
|
||||
api(projects.core.network)
|
||||
api(projects.core.database)
|
||||
api(projects.core.datastore)
|
||||
|
||||
implementation(libs.squareup.retrofit2)
|
||||
implementation(libs.squareup.okhttp)
|
||||
|
||||
@ -0,0 +1 @@
|
||||
mock-maker-inline
|
||||
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2025 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.data.model
|
||||
|
||||
import org.mifos.mobile.core.database.entity.ChargeCalculationTypeEntity
|
||||
import org.mifos.mobile.core.database.entity.ChargeEntity
|
||||
import org.mifos.mobile.core.database.entity.ChargeTimeTypeEntity
|
||||
import org.mifos.mobile.core.database.entity.CurrencyEntity
|
||||
import org.mifos.mobile.core.model.entity.Charge
|
||||
import org.mifos.mobile.core.model.entity.ChargeCalculationType
|
||||
import org.mifos.mobile.core.model.entity.ChargeTimeType
|
||||
import org.mifos.mobile.core.model.entity.Currency
|
||||
|
||||
fun ChargeEntity.toCharge(): Charge {
|
||||
return Charge(
|
||||
clientId = clientId,
|
||||
chargeId = chargeId,
|
||||
name = name,
|
||||
dueDate = dueDate,
|
||||
chargeTimeType = ChargeTimeType(
|
||||
id = chargeTimeType?.id ?: 0,
|
||||
code = chargeTimeType?.code,
|
||||
value = chargeTimeType?.value,
|
||||
),
|
||||
chargeCalculationType = ChargeCalculationType(
|
||||
id = chargeCalculationType?.id ?: 0,
|
||||
code = chargeCalculationType?.code,
|
||||
value = chargeCalculationType?.value,
|
||||
),
|
||||
currency = Currency(
|
||||
code = currency?.code,
|
||||
name = currency?.name,
|
||||
decimalPlaces = currency?.decimalPlaces ?: 0,
|
||||
displaySymbol = currency?.displaySymbol,
|
||||
nameCode = currency?.nameCode,
|
||||
displayLabel = currency?.displayLabel,
|
||||
),
|
||||
amount = amount,
|
||||
amountPaid = amountPaid,
|
||||
amountWaived = amountWaived,
|
||||
amountWrittenOff = amountWrittenOff,
|
||||
amountOutstanding = amountOutstanding,
|
||||
penalty = penalty,
|
||||
isActive = isActive,
|
||||
isChargePaid = isChargePaid,
|
||||
isChargeWaived = isChargeWaived,
|
||||
paid = paid,
|
||||
waived = waived,
|
||||
)
|
||||
}
|
||||
|
||||
fun Charge.toChargeEntity(): ChargeEntity {
|
||||
return ChargeEntity(
|
||||
clientId = clientId,
|
||||
chargeId = chargeId,
|
||||
name = name,
|
||||
dueDate = dueDate,
|
||||
chargeTimeType = ChargeTimeTypeEntity(
|
||||
id = chargeTimeType?.id ?: 0,
|
||||
code = chargeTimeType?.code,
|
||||
value = chargeTimeType?.value,
|
||||
),
|
||||
chargeCalculationType = ChargeCalculationTypeEntity(
|
||||
id = chargeCalculationType?.id ?: 0,
|
||||
code = chargeCalculationType?.code,
|
||||
value = chargeCalculationType?.value,
|
||||
),
|
||||
currency = CurrencyEntity(
|
||||
code = currency?.code,
|
||||
name = currency?.name,
|
||||
decimalPlaces = currency?.decimalPlaces ?: 0,
|
||||
displaySymbol = currency?.displaySymbol,
|
||||
nameCode = currency?.nameCode,
|
||||
displayLabel = currency?.displayLabel,
|
||||
),
|
||||
amount = amount,
|
||||
amountPaid = amountPaid,
|
||||
amountWaived = amountWaived,
|
||||
amountWrittenOff = amountWrittenOff,
|
||||
amountOutstanding = amountOutstanding,
|
||||
penalty = penalty,
|
||||
isActive = isActive,
|
||||
isChargePaid = isChargePaid,
|
||||
isChargeWaived = isChargeWaived,
|
||||
paid = paid,
|
||||
waived = waived,
|
||||
)
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2025 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.data.model
|
||||
|
||||
import org.mifos.mobile.core.database.entity.MifosNotificationEntity
|
||||
import org.mifos.mobile.core.model.entity.MifosNotification
|
||||
|
||||
fun MifosNotification.toEntity(): MifosNotificationEntity {
|
||||
return MifosNotificationEntity(
|
||||
timeStamp = timeStamp,
|
||||
msg = msg,
|
||||
read = read,
|
||||
)
|
||||
}
|
||||
|
||||
fun MifosNotificationEntity.toModel(): MifosNotification {
|
||||
return MifosNotification(
|
||||
timeStamp = timeStamp,
|
||||
msg = msg,
|
||||
read = read,
|
||||
)
|
||||
}
|
||||
@ -10,13 +10,17 @@
|
||||
package org.mifos.mobile.core.data.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.mifos.mobile.core.datastore.model.Charge
|
||||
import org.mifos.mobile.core.model.entity.Charge
|
||||
import org.mifos.mobile.core.model.entity.Page
|
||||
|
||||
interface ClientChargeRepository {
|
||||
fun getClientCharges(clientId: Long): Flow<Page<Charge>>
|
||||
|
||||
suspend fun getClientCharges(clientId: Long): Flow<Page<Charge>>
|
||||
suspend fun getLoanCharges(loanId: Long): Flow<List<Charge>>
|
||||
suspend fun getSavingsCharges(savingsId: Long): Flow<List<Charge>>
|
||||
suspend fun clientLocalCharges(): Flow<Page<Charge?>>
|
||||
fun getLoanCharges(loanId: Long): Flow<List<Charge>>
|
||||
|
||||
fun getSavingsCharges(savingsId: Long): Flow<List<Charge>>
|
||||
|
||||
fun clientLocalCharges(): Flow<Page<Charge>>
|
||||
|
||||
suspend fun syncCharges(charges: Page<Charge>?): Page<Charge>?
|
||||
}
|
||||
|
||||
@ -22,5 +22,5 @@ interface HomeRepository {
|
||||
|
||||
fun clientImage(): Flow<ResponseBody>
|
||||
|
||||
fun unreadNotificationsCount(): Flow<Int>
|
||||
suspend fun unreadNotificationsCount(): Flow<Int>
|
||||
}
|
||||
|
||||
@ -10,9 +10,17 @@
|
||||
package org.mifos.mobile.core.data.repository
|
||||
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.mifos.mobile.core.datastore.model.MifosNotification
|
||||
import org.mifos.mobile.core.model.entity.MifosNotification
|
||||
|
||||
interface NotificationRepository {
|
||||
|
||||
suspend fun loadNotifications(): Flow<List<MifosNotification>>
|
||||
fun loadNotifications(): Flow<List<MifosNotification>>
|
||||
|
||||
fun getUnReadNotificationCount(): Flow<Int>
|
||||
|
||||
suspend fun saveNotification(notification: MifosNotification)
|
||||
|
||||
suspend fun deleteOldNotifications()
|
||||
|
||||
suspend fun updateReadStatus(notification: MifosNotification, isRead: Boolean)
|
||||
}
|
||||
|
||||
@ -9,39 +9,61 @@
|
||||
*/
|
||||
package org.mifos.mobile.core.data.repositoryImpl
|
||||
|
||||
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.mifos.mobile.core.common.network.Dispatcher
|
||||
import org.mifos.mobile.core.common.network.MifosDispatchers
|
||||
import org.mifos.mobile.core.data.model.toCharge
|
||||
import org.mifos.mobile.core.data.model.toChargeEntity
|
||||
import org.mifos.mobile.core.data.repository.ClientChargeRepository
|
||||
import org.mifos.mobile.core.datastore.model.Charge
|
||||
import org.mifos.mobile.core.database.dao.ChargeDao
|
||||
import org.mifos.mobile.core.model.entity.Charge
|
||||
import org.mifos.mobile.core.model.entity.Page
|
||||
import org.mifos.mobile.core.network.DataManager
|
||||
import javax.inject.Inject
|
||||
|
||||
class ClientChargeRepositoryImp @Inject constructor(
|
||||
private val dataManager: DataManager,
|
||||
private val chargeDao: ChargeDao,
|
||||
@Dispatcher(MifosDispatchers.IO)
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
) : ClientChargeRepository {
|
||||
|
||||
override suspend fun getClientCharges(clientId: Long): Flow<Page<Charge>> {
|
||||
override fun getClientCharges(clientId: Long): Flow<Page<Charge>> {
|
||||
return flow {
|
||||
emit(dataManager.getClientCharges(clientId))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getLoanCharges(loanId: Long): Flow<List<Charge>> {
|
||||
override fun getLoanCharges(loanId: Long): Flow<List<Charge>> {
|
||||
return flow {
|
||||
emit(dataManager.getLoanCharges(loanId))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getSavingsCharges(savingsId: Long): Flow<List<Charge>> {
|
||||
override fun getSavingsCharges(savingsId: Long): Flow<List<Charge>> {
|
||||
return flow {
|
||||
emit(dataManager.getSavingsCharges(savingsId))
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun clientLocalCharges(): Flow<Page<Charge?>> {
|
||||
return flow {
|
||||
emit(dataManager.clientLocalCharges())
|
||||
override fun clientLocalCharges(): Flow<Page<Charge>> {
|
||||
return chargeDao.getAllLocalCharges().map { chargeList ->
|
||||
Page(chargeList.size, chargeList.map { it.toCharge() })
|
||||
}.flowOn(ioDispatcher)
|
||||
}
|
||||
|
||||
override suspend fun syncCharges(charges: Page<Charge>?): Page<Charge>? {
|
||||
return withContext(ioDispatcher) {
|
||||
charges?.pageItems?.let {
|
||||
chargeDao.syncCharges(it.map { it.toChargeEntity() })
|
||||
}
|
||||
|
||||
charges?.copy(pageItems = charges.pageItems)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,6 +13,7 @@ import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flow
|
||||
import okhttp3.ResponseBody
|
||||
import org.mifos.mobile.core.data.repository.HomeRepository
|
||||
import org.mifos.mobile.core.data.repository.NotificationRepository
|
||||
import org.mifos.mobile.core.model.entity.client.Client
|
||||
import org.mifos.mobile.core.model.entity.client.ClientAccounts
|
||||
import org.mifos.mobile.core.network.DataManager
|
||||
@ -20,6 +21,7 @@ import javax.inject.Inject
|
||||
|
||||
class HomeRepositoryImp @Inject constructor(
|
||||
private val dataManager: DataManager,
|
||||
private val notificationRepository: NotificationRepository,
|
||||
) : HomeRepository {
|
||||
|
||||
override fun clientAccounts(): Flow<ClientAccounts> {
|
||||
@ -40,9 +42,7 @@ class HomeRepositoryImp @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun unreadNotificationsCount(): Flow<Int> {
|
||||
return flow {
|
||||
emit(dataManager.unreadNotificationsCount())
|
||||
}
|
||||
override suspend fun unreadNotificationsCount(): Flow<Int> {
|
||||
return notificationRepository.getUnReadNotificationCount()
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,20 +9,53 @@
|
||||
*/
|
||||
package org.mifos.mobile.core.data.repositoryImpl
|
||||
|
||||
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.mifos.mobile.core.common.network.Dispatcher
|
||||
import org.mifos.mobile.core.common.network.MifosDispatchers
|
||||
import org.mifos.mobile.core.data.model.toEntity
|
||||
import org.mifos.mobile.core.data.model.toModel
|
||||
import org.mifos.mobile.core.data.repository.NotificationRepository
|
||||
import org.mifos.mobile.core.datastore.model.MifosNotification
|
||||
import org.mifos.mobile.core.network.DataManager
|
||||
import org.mifos.mobile.core.database.dao.MifosNotificationDao
|
||||
import org.mifos.mobile.core.model.entity.MifosNotification
|
||||
import javax.inject.Inject
|
||||
|
||||
class NotificationRepositoryImp @Inject constructor(
|
||||
private val dataManager: DataManager,
|
||||
private val notificationDao: MifosNotificationDao,
|
||||
@Dispatcher(MifosDispatchers.IO)
|
||||
private val ioDispatcher: CoroutineDispatcher,
|
||||
) : NotificationRepository {
|
||||
|
||||
override suspend fun loadNotifications(): Flow<List<MifosNotification>> {
|
||||
return flow {
|
||||
emit(dataManager.notifications())
|
||||
override fun loadNotifications(): Flow<List<MifosNotification>> {
|
||||
return notificationDao.getNotifications()
|
||||
.map { it.map { it.toModel() } }
|
||||
.flowOn(ioDispatcher)
|
||||
}
|
||||
|
||||
override fun getUnReadNotificationCount(): Flow<Int> {
|
||||
return notificationDao.getUnreadNotificationsCount().flowOn(ioDispatcher)
|
||||
}
|
||||
|
||||
override suspend fun saveNotification(notification: MifosNotification) {
|
||||
withContext(ioDispatcher) {
|
||||
notificationDao.saveNotification(notification.toEntity())
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun deleteOldNotifications() {
|
||||
return withContext(ioDispatcher) {
|
||||
val thirtyDaysInMillis = 2592000000L
|
||||
val cutoffTime = System.currentTimeMillis() - thirtyDaysInMillis
|
||||
notificationDao.deleteOldNotifications(cutoffTime)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun updateReadStatus(notification: MifosNotification, isRead: Boolean) {
|
||||
withContext(ioDispatcher) {
|
||||
notificationDao.updateReadStatus(notification.timeStamp, isRead)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,13 +12,18 @@ package org.mifos.mobile.core.data.repositories
|
||||
import app.cash.turbine.test
|
||||
import junit.framework.Assert.assertEquals
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mifos.mobile.core.data.model.toCharge
|
||||
import org.mifos.mobile.core.data.repositoryImpl.ClientChargeRepositoryImp
|
||||
import org.mifos.mobile.core.datastore.model.Charge
|
||||
import org.mifos.mobile.core.database.dao.ChargeDao
|
||||
import org.mifos.mobile.core.database.entity.ChargeEntity
|
||||
import org.mifos.mobile.core.model.entity.Charge
|
||||
import org.mifos.mobile.core.model.entity.Page
|
||||
import org.mifos.mobile.core.network.DataManager
|
||||
import org.mifos.mobile.core.testing.util.MainDispatcherRule
|
||||
@ -38,12 +43,19 @@ class ClientChargeRepositoryImpTest {
|
||||
@Mock
|
||||
lateinit var dataManager: DataManager
|
||||
|
||||
@Mock
|
||||
lateinit var chargeDao: ChargeDao
|
||||
|
||||
private lateinit var clientChargeRepositoryImp: ClientChargeRepositoryImp
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.openMocks(this)
|
||||
clientChargeRepositoryImp = ClientChargeRepositoryImp(dataManager)
|
||||
clientChargeRepositoryImp = ClientChargeRepositoryImp(
|
||||
dataManager = dataManager,
|
||||
chargeDao = chargeDao,
|
||||
ioDispatcher = UnconfinedTestDispatcher(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -116,10 +128,12 @@ class ClientChargeRepositoryImpTest {
|
||||
|
||||
@Test
|
||||
fun testClientLocalCharges_Successful() = runTest {
|
||||
val clientLocalChargeMock = List(5) { mock(Charge::class.java) }
|
||||
val chargeList = clientLocalChargeMock.toList()
|
||||
val success = Page<Charge?>(5, chargeList)
|
||||
`when`(dataManager.clientLocalCharges()).thenReturn(success)
|
||||
val clientLocalChargeMock = List(5) { mock(ChargeEntity::class.java) }
|
||||
val success = Page<Charge?>(
|
||||
clientLocalChargeMock.size,
|
||||
clientLocalChargeMock.map { it.toCharge() },
|
||||
)
|
||||
`when`(chargeDao.getAllLocalCharges()).thenReturn(flowOf(clientLocalChargeMock))
|
||||
val resultFlow = clientChargeRepositoryImp.clientLocalCharges()
|
||||
resultFlow.test {
|
||||
assertEquals(success, awaitItem())
|
||||
@ -129,7 +143,7 @@ class ClientChargeRepositoryImpTest {
|
||||
|
||||
@Test(expected = Exception::class)
|
||||
fun testClientLocalCharges_Unsuccessful() = runTest {
|
||||
`when`(dataManager.clientLocalCharges())
|
||||
`when`(clientChargeRepositoryImp.clientLocalCharges())
|
||||
.thenThrow(Exception("Error occurred"))
|
||||
val result = clientChargeRepositoryImp.clientLocalCharges()
|
||||
result.test {
|
||||
|
||||
@ -12,12 +12,14 @@ package org.mifos.mobile.core.data.repositories
|
||||
import app.cash.turbine.test
|
||||
import junit.framework.Assert.assertEquals
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import okhttp3.ResponseBody
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mifos.mobile.core.data.repository.NotificationRepository
|
||||
import org.mifos.mobile.core.data.repositoryImpl.HomeRepositoryImp
|
||||
import org.mifos.mobile.core.model.entity.client.Client
|
||||
import org.mifos.mobile.core.model.entity.client.ClientAccounts
|
||||
@ -39,12 +41,15 @@ class HomeRepositoryImpTest {
|
||||
@Mock
|
||||
lateinit var dataManager: DataManager
|
||||
|
||||
@Mock
|
||||
lateinit var notificationRepository: NotificationRepository
|
||||
|
||||
private lateinit var homeRepositoryImp: HomeRepositoryImp
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.openMocks(this)
|
||||
homeRepositoryImp = HomeRepositoryImp(dataManager)
|
||||
homeRepositoryImp = HomeRepositoryImp(dataManager, notificationRepository)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -93,7 +98,7 @@ class HomeRepositoryImpTest {
|
||||
fun testUnreadNotificationsCount_Successful() = runTest {
|
||||
val mockUnreadCount = 5
|
||||
|
||||
`when`(dataManager.unreadNotificationsCount()).thenReturn(mockUnreadCount)
|
||||
`when`(notificationRepository.getUnReadNotificationCount()).thenReturn(flowOf(mockUnreadCount))
|
||||
|
||||
val flow = homeRepositoryImp.unreadNotificationsCount()
|
||||
|
||||
@ -147,7 +152,7 @@ class HomeRepositoryImpTest {
|
||||
fun testUnreadNotificationsCount_Error() = runTest {
|
||||
val errorMessage = "Failed to fetch unread notifications count"
|
||||
|
||||
`when`(dataManager.unreadNotificationsCount())
|
||||
`when`(notificationRepository.getUnReadNotificationCount())
|
||||
.thenThrow(Exception(errorMessage))
|
||||
|
||||
val flow = homeRepositoryImp.unreadNotificationsCount()
|
||||
|
||||
@ -12,14 +12,18 @@ package org.mifos.mobile.core.data.repositories
|
||||
import app.cash.turbine.test
|
||||
import junit.framework.TestCase.assertEquals
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mifos.mobile.core.data.model.toModel
|
||||
import org.mifos.mobile.core.data.repository.NotificationRepository
|
||||
import org.mifos.mobile.core.data.repositoryImpl.NotificationRepositoryImp
|
||||
import org.mifos.mobile.core.datastore.model.MifosNotification
|
||||
import org.mifos.mobile.core.database.dao.MifosNotificationDao
|
||||
import org.mifos.mobile.core.database.entity.MifosNotificationEntity
|
||||
import org.mifos.mobile.core.network.DataManager
|
||||
import org.mifos.mobile.core.testing.util.MainDispatcherRule
|
||||
import org.mockito.Mock
|
||||
@ -38,26 +42,32 @@ class NotificationRepositoryImpTest {
|
||||
@Mock
|
||||
lateinit var dataManager: DataManager
|
||||
|
||||
@Mock
|
||||
lateinit var mifosNotificationDao: MifosNotificationDao
|
||||
|
||||
private lateinit var notificationRepositoryImp: NotificationRepository
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
MockitoAnnotations.openMocks(this)
|
||||
notificationRepositoryImp = NotificationRepositoryImp(dataManager)
|
||||
notificationRepositoryImp = NotificationRepositoryImp(
|
||||
notificationDao = mifosNotificationDao,
|
||||
ioDispatcher = UnconfinedTestDispatcher(),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testLoadNotifications_SuccessResponseReceivedFromDataManager_ReturnsSuccess() = runTest {
|
||||
val notification = mock(MifosNotification::class.java)
|
||||
val notification = mock(MifosNotificationEntity::class.java)
|
||||
val notificationList = List(5) { notification }
|
||||
`when`(
|
||||
dataManager.notifications(),
|
||||
).thenReturn(notificationList)
|
||||
mifosNotificationDao.getNotifications(),
|
||||
).thenReturn(flowOf(notificationList))
|
||||
|
||||
val notifications = notificationRepositoryImp.loadNotifications()
|
||||
|
||||
notifications.test {
|
||||
assertEquals(notificationList, awaitItem())
|
||||
assertEquals(notificationList.map { it.toModel() }, awaitItem())
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
@ -65,7 +75,7 @@ class NotificationRepositoryImpTest {
|
||||
@Test(expected = Exception::class)
|
||||
fun testLoadNotifications_ErrorResponseReceivedFromDataManager_ReturnsError() = runTest {
|
||||
val dummyError = Exception("Dummy error")
|
||||
`when`(dataManager.notifications()).thenThrow(dummyError)
|
||||
`when`(mifosNotificationDao.getNotifications()).thenThrow(dummyError)
|
||||
|
||||
val notifications = notificationRepositoryImp.loadNotifications()
|
||||
|
||||
|
||||
@ -0,0 +1 @@
|
||||
mock-maker-inline
|
||||
1
core/database/.gitignore
vendored
Normal file
1
core/database/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/build
|
||||
29
core/database/build.gradle.kts
Normal file
29
core/database/build.gradle.kts
Normal file
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
plugins {
|
||||
alias(libs.plugins.mifos.android.library)
|
||||
alias(libs.plugins.mifos.android.room)
|
||||
alias(libs.plugins.mifos.android.hilt)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "org.mifos.mobile.core.database"
|
||||
|
||||
defaultConfig {
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
}
|
||||
0
core/database/consumer-rules.pro
Normal file
0
core/database/consumer-rules.pro
Normal file
@ -0,0 +1,174 @@
|
||||
{
|
||||
"formatVersion": 1,
|
||||
"database": {
|
||||
"version": 1,
|
||||
"identityHash": "0ef6ac9f8492c3e3e0026cafe51bd414",
|
||||
"entities": [
|
||||
{
|
||||
"tableName": "charges",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `clientId` INTEGER, `chargeId` INTEGER, `name` TEXT, `dueDate` TEXT NOT NULL, `chargeTimeType` TEXT, `chargeCalculationType` TEXT, `currency` TEXT, `amount` REAL NOT NULL, `amountPaid` REAL NOT NULL, `amountWaived` REAL NOT NULL, `amountWrittenOff` REAL NOT NULL, `amountOutstanding` REAL NOT NULL, `penalty` INTEGER NOT NULL, `isActive` INTEGER NOT NULL, `isChargePaid` INTEGER NOT NULL, `isChargeWaived` INTEGER NOT NULL, `paid` INTEGER NOT NULL, `waived` INTEGER NOT NULL)",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "id",
|
||||
"columnName": "id",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "clientId",
|
||||
"columnName": "clientId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargeId",
|
||||
"columnName": "chargeId",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "name",
|
||||
"columnName": "name",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "dueDate",
|
||||
"columnName": "dueDate",
|
||||
"affinity": "TEXT",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargeTimeType",
|
||||
"columnName": "chargeTimeType",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "chargeCalculationType",
|
||||
"columnName": "chargeCalculationType",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "currency",
|
||||
"columnName": "currency",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "amount",
|
||||
"columnName": "amount",
|
||||
"affinity": "REAL",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "amountPaid",
|
||||
"columnName": "amountPaid",
|
||||
"affinity": "REAL",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "amountWaived",
|
||||
"columnName": "amountWaived",
|
||||
"affinity": "REAL",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "amountWrittenOff",
|
||||
"columnName": "amountWrittenOff",
|
||||
"affinity": "REAL",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "amountOutstanding",
|
||||
"columnName": "amountOutstanding",
|
||||
"affinity": "REAL",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "penalty",
|
||||
"columnName": "penalty",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isActive",
|
||||
"columnName": "isActive",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isChargePaid",
|
||||
"columnName": "isChargePaid",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "isChargeWaived",
|
||||
"columnName": "isChargeWaived",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "paid",
|
||||
"columnName": "paid",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "waived",
|
||||
"columnName": "waived",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": true,
|
||||
"columnNames": [
|
||||
"id"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
},
|
||||
{
|
||||
"tableName": "mifos_notifications",
|
||||
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`timeStamp` INTEGER NOT NULL, `msg` TEXT, `read` INTEGER, PRIMARY KEY(`timeStamp`))",
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "timeStamp",
|
||||
"columnName": "timeStamp",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"fieldPath": "msg",
|
||||
"columnName": "msg",
|
||||
"affinity": "TEXT",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"fieldPath": "read",
|
||||
"columnName": "read",
|
||||
"affinity": "INTEGER",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"autoGenerate": false,
|
||||
"columnNames": [
|
||||
"timeStamp"
|
||||
]
|
||||
},
|
||||
"indices": [],
|
||||
"foreignKeys": []
|
||||
}
|
||||
],
|
||||
"views": [],
|
||||
"setupQueries": [
|
||||
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
|
||||
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '0ef6ac9f8492c3e3e0026cafe51bd414')"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -8,8 +8,6 @@
|
||||
|
||||
See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
-->
|
||||
<resources>
|
||||
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">
|
||||
YOUR_KEY_HERE
|
||||
</string>
|
||||
</resources>
|
||||
<manifest>
|
||||
|
||||
</manifest>
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.database
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import androidx.room.TypeConverters
|
||||
import org.mifos.mobile.core.database.dao.ChargeDao
|
||||
import org.mifos.mobile.core.database.dao.MifosNotificationDao
|
||||
import org.mifos.mobile.core.database.entity.ChargeEntity
|
||||
import org.mifos.mobile.core.database.entity.MifosNotificationEntity
|
||||
import org.mifos.mobile.core.database.utils.ChargeTypeConverters
|
||||
|
||||
@Database(
|
||||
entities = [
|
||||
ChargeEntity::class,
|
||||
MifosNotificationEntity::class,
|
||||
],
|
||||
version = SelfServiceDatabase.VERSION,
|
||||
exportSchema = true,
|
||||
autoMigrations = [],
|
||||
)
|
||||
@TypeConverters(ChargeTypeConverters::class)
|
||||
abstract class SelfServiceDatabase : RoomDatabase() {
|
||||
|
||||
abstract fun mifosNotificationDao(): MifosNotificationDao
|
||||
|
||||
abstract fun chargeDao(): ChargeDao
|
||||
|
||||
companion object {
|
||||
// Update the version number if you change the schema
|
||||
const val VERSION = 1
|
||||
}
|
||||
}
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.database.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.mifos.mobile.core.database.entity.ChargeEntity
|
||||
|
||||
@Dao
|
||||
interface ChargeDao {
|
||||
|
||||
@Query("SELECT * FROM charges")
|
||||
fun getAllLocalCharges(): Flow<List<ChargeEntity>>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertCharge(charge: List<ChargeEntity>)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun syncCharges(charges: List<ChargeEntity>)
|
||||
}
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.database.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import org.mifos.mobile.core.database.entity.MifosNotificationEntity
|
||||
|
||||
@Dao
|
||||
interface MifosNotificationDao {
|
||||
|
||||
@Query("SELECT * FROM mifos_notifications ORDER BY timeStamp DESC")
|
||||
fun getNotifications(): Flow<List<MifosNotificationEntity>>
|
||||
|
||||
@Query("SELECT COUNT(*) FROM mifos_notifications WHERE read = 0")
|
||||
fun getUnreadNotificationsCount(): Flow<Int>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun saveNotification(notification: MifosNotificationEntity)
|
||||
|
||||
@Query("DELETE FROM mifos_notifications WHERE timeStamp < :cutoffTime")
|
||||
suspend fun deleteOldNotifications(cutoffTime: Long)
|
||||
|
||||
@Query("UPDATE mifos_notifications SET read = :isRead WHERE timeStamp = :timeStamp")
|
||||
suspend fun updateReadStatus(timeStamp: Long, isRead: Boolean)
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2025 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.database.di
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import org.mifos.mobile.core.database.SelfServiceDatabase
|
||||
import org.mifos.mobile.core.database.dao.ChargeDao
|
||||
import org.mifos.mobile.core.database.dao.MifosNotificationDao
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object DaoModule {
|
||||
@Provides
|
||||
fun provideMifosNotificationDao(database: SelfServiceDatabase): MifosNotificationDao {
|
||||
return database.mifosNotificationDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideChargeDao(database: SelfServiceDatabase): ChargeDao {
|
||||
return database.chargeDao()
|
||||
}
|
||||
}
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.database.di
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Room
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import org.mifos.mobile.core.database.SelfServiceDatabase
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
internal object DatabaseModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideDatabase(@ApplicationContext context: Context): SelfServiceDatabase {
|
||||
return Room.databaseBuilder(
|
||||
context = context,
|
||||
klass = SelfServiceDatabase::class.java,
|
||||
name = "self-service-database",
|
||||
).build()
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2025 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.database.entity
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ChargeCalculationTypeEntity(
|
||||
val id: Int = 0,
|
||||
val code: String? = null,
|
||||
val value: String? = null,
|
||||
)
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.database.entity
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "charges")
|
||||
data class ChargeEntity(
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
val id: Int? = null,
|
||||
val clientId: Int? = null,
|
||||
val chargeId: Int? = null,
|
||||
val name: String? = null,
|
||||
val dueDate: ArrayList<Int?> = ArrayList(),
|
||||
val chargeTimeType: ChargeTimeTypeEntity? = null,
|
||||
val chargeCalculationType: ChargeCalculationTypeEntity? = null,
|
||||
val currency: CurrencyEntity? = null,
|
||||
val amount: Double = 0.0,
|
||||
val amountPaid: Double = 0.0,
|
||||
val amountWaived: Double = 0.0,
|
||||
val amountWrittenOff: Double = 0.0,
|
||||
val amountOutstanding: Double = 0.0,
|
||||
val penalty: Boolean = false,
|
||||
val isActive: Boolean = false,
|
||||
val isChargePaid: Boolean = false,
|
||||
val isChargeWaived: Boolean = false,
|
||||
val paid: Boolean = false,
|
||||
val waived: Boolean = false,
|
||||
)
|
||||
@ -7,12 +7,12 @@
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.datastore.model
|
||||
package org.mifos.mobile.core.database.entity
|
||||
|
||||
/**
|
||||
* @author Vishwajeet
|
||||
* @since 16/8/16.
|
||||
*/
|
||||
data class ChargeListResponse(
|
||||
var pageItems: List<Charge> = ArrayList(),
|
||||
var pageItems: List<ChargeEntity> = ArrayList(),
|
||||
)
|
||||
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2025 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.database.entity
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ChargeTimeTypeEntity(
|
||||
val id: Int = 0,
|
||||
val code: String? = null,
|
||||
val value: String? = null,
|
||||
)
|
||||
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2025 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.database.entity
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class CurrencyEntity(
|
||||
val code: String? = null,
|
||||
val name: String? = null,
|
||||
val decimalPlaces: Int = 0,
|
||||
val displaySymbol: String? = null,
|
||||
val nameCode: String? = null,
|
||||
val displayLabel: String? = null,
|
||||
)
|
||||
@ -7,12 +7,14 @@
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.datastore
|
||||
package org.mifos.mobile.core.database.entity
|
||||
|
||||
import com.raizlabs.android.dbflow.annotation.Database
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Database(name = SelfServiceDatabase.NAME, version = SelfServiceDatabase.VERSION)
|
||||
object SelfServiceDatabase {
|
||||
const val NAME: String = "SelfService" // we will add the .db extension
|
||||
const val VERSION: Int = 1
|
||||
}
|
||||
@Entity(tableName = "mifos_notifications")
|
||||
data class MifosNotificationEntity(
|
||||
@PrimaryKey val timeStamp: Long,
|
||||
val msg: String? = null,
|
||||
val read: Boolean? = null,
|
||||
)
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.database.utils
|
||||
|
||||
import androidx.room.TypeConverter
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.mifos.mobile.core.database.entity.ChargeCalculationTypeEntity
|
||||
import org.mifos.mobile.core.database.entity.ChargeTimeTypeEntity
|
||||
import org.mifos.mobile.core.database.entity.CurrencyEntity
|
||||
|
||||
class ChargeTypeConverters {
|
||||
|
||||
@TypeConverter
|
||||
fun fromIntList(value: String): ArrayList<Int?> {
|
||||
return Json.decodeFromString(value)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toIntList(list: ArrayList<Int?>): String {
|
||||
return Json.encodeToString(list)
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromChargeTimeType(value: ChargeTimeTypeEntity?): String? {
|
||||
return value?.let { Json.encodeToString(it) }
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toChargeTimeType(value: String?): ChargeTimeTypeEntity? {
|
||||
return value?.let { Json.decodeFromString(ChargeTimeTypeEntity.serializer(), it) }
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromChargeCalculationType(value: ChargeCalculationTypeEntity?): String? {
|
||||
return value?.let { Json.encodeToString(it) }
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toChargeCalculationType(value: String?): ChargeCalculationTypeEntity? {
|
||||
return value?.let { Json.decodeFromString(ChargeCalculationTypeEntity.serializer(), it) }
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun fromCurrency(value: CurrencyEntity?): String? {
|
||||
return value?.let { Json.encodeToString(it) }
|
||||
}
|
||||
|
||||
@TypeConverter
|
||||
fun toCurrency(value: String?): CurrencyEntity? {
|
||||
return value?.let { Json.decodeFromString(CurrencyEntity.serializer(), it) }
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@
|
||||
plugins {
|
||||
alias(libs.plugins.mifos.android.library)
|
||||
alias(libs.plugins.mifos.android.hilt)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
}
|
||||
|
||||
android {
|
||||
@ -22,20 +23,8 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(projects.core.common)
|
||||
api(projects.core.model)
|
||||
implementation(libs.squareup.retrofit.converter.gson)
|
||||
implementation(projects.core.common)
|
||||
implementation(projects.core.model)
|
||||
|
||||
// DBFlow
|
||||
implementation(libs.dbflow)
|
||||
kapt(libs.dbflow.processor)
|
||||
implementation(libs.dbflow.core)
|
||||
|
||||
//rxjava Dependencies
|
||||
implementation(libs.reactivex.rxjava2.android)
|
||||
implementation(libs.reactivex.rxjava2)
|
||||
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.test.ext.junit)
|
||||
androidTestImplementation(libs.androidx.test.espresso.core)
|
||||
|
||||
}
|
||||
21
core/datastore/proguard-rules.pro
vendored
21
core/datastore/proguard-rules.pro
vendored
@ -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
|
||||
@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright 2024 Mifos Initiative
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
||||
If a copy of the MPL was not distributed with this file,
|
||||
You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
-->
|
||||
<resources>
|
||||
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">
|
||||
AIzaSyBbeT2BaMWLj-lReCgYoNmXs_TIyRLr9qQ
|
||||
</string>
|
||||
</resources>
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.datastore
|
||||
|
||||
import android.util.Log
|
||||
import com.google.gson.Gson
|
||||
import com.raizlabs.android.dbflow.sql.language.SQLite
|
||||
import io.reactivex.Observable
|
||||
import org.mifos.mobile.core.datastore.model.Charge
|
||||
import org.mifos.mobile.core.datastore.model.MifosNotification
|
||||
import org.mifos.mobile.core.datastore.model.MifosNotification_Table
|
||||
import org.mifos.mobile.core.datastore.utils.NotificationComparator
|
||||
import org.mifos.mobile.core.model.entity.Page
|
||||
import java.util.Collections
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Created by Rajan Maurya on 02/03/17.
|
||||
*/
|
||||
@Singleton
|
||||
class DatabaseHelper @Inject constructor() {
|
||||
fun syncCharges(charges: Page<Charge>?): Page<Charge>? {
|
||||
if (charges != null) {
|
||||
for (charge in charges.pageItems)
|
||||
charge.save()
|
||||
}
|
||||
return charges
|
||||
}
|
||||
|
||||
fun clientCharges(): Page<Charge?> {
|
||||
val charges = SQLite.select()
|
||||
.from(Charge::class.java)
|
||||
.queryList()
|
||||
val chargePage = Page<Charge?>()
|
||||
chargePage.pageItems = charges
|
||||
return chargePage
|
||||
}
|
||||
|
||||
fun notifications(): List<MifosNotification> {
|
||||
deleteOldNotifications()
|
||||
val notifications = SQLite.select()
|
||||
.from(MifosNotification::class.java)
|
||||
.queryList()
|
||||
Collections.sort(notifications, NotificationComparator())
|
||||
Log.d("Notifications@@@", Gson().toJson(notifications))
|
||||
return notifications
|
||||
}
|
||||
|
||||
fun unreadNotificationsCount(): Int {
|
||||
deleteOldNotifications()
|
||||
return SQLite.select()
|
||||
.from(MifosNotification::class.java)
|
||||
.where(MifosNotification_Table.read.eq(false))
|
||||
.queryList().size
|
||||
}
|
||||
|
||||
private fun deleteOldNotifications() {
|
||||
Observable.defer<Void> {
|
||||
val thirtyDaysInSeconds: Long = 2592000
|
||||
val thirtyDaysFromCurrentTimeInSeconds = System.currentTimeMillis() / 1000 -
|
||||
thirtyDaysInSeconds
|
||||
SQLite.delete(MifosNotification::class.java)
|
||||
.where(MifosNotification_Table.timeStamp.lessThan(thirtyDaysFromCurrentTimeInSeconds * 1000))
|
||||
.execute()
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,132 +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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.datastore.model
|
||||
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.raizlabs.android.dbflow.annotation.Column
|
||||
import com.raizlabs.android.dbflow.annotation.PrimaryKey
|
||||
import com.raizlabs.android.dbflow.annotation.Table
|
||||
import com.raizlabs.android.dbflow.structure.BaseModel
|
||||
import org.mifos.mobile.core.datastore.SelfServiceDatabase
|
||||
import org.mifos.mobile.core.model.entity.ChargeCalculationType
|
||||
import org.mifos.mobile.core.model.entity.ChargeTimeType
|
||||
import org.mifos.mobile.core.model.entity.Currency
|
||||
|
||||
/**
|
||||
* @author Vishwajeet
|
||||
* @since 16/8/16.
|
||||
*/
|
||||
@Table(database = SelfServiceDatabase::class)
|
||||
class Charge : BaseModel, Parcelable {
|
||||
@JvmField
|
||||
@PrimaryKey
|
||||
var id: Int? = null
|
||||
|
||||
var clientId: Int? = null
|
||||
private var chargeId: Int? = null
|
||||
|
||||
@Column
|
||||
var name: String? = null
|
||||
|
||||
var dueDate: List<Int?> = ArrayList()
|
||||
private var chargeTimeType: ChargeTimeType? = null
|
||||
private var chargeCalculationType: ChargeCalculationType? = null
|
||||
var currency: Currency? = null
|
||||
|
||||
@Column
|
||||
var amount = 0.0
|
||||
|
||||
@Column
|
||||
var amountPaid = 0.0
|
||||
|
||||
@Column
|
||||
var amountWaived = 0.0
|
||||
|
||||
@Column
|
||||
var amountWrittenOff = 0.0
|
||||
|
||||
@Column
|
||||
var amountOutstanding = 0.0
|
||||
|
||||
var penalty = false
|
||||
|
||||
@Column
|
||||
var isActive = false
|
||||
|
||||
var isChargePaid: Boolean = false
|
||||
var isChargeWaived: Boolean = false
|
||||
|
||||
var paid = false
|
||||
var waived = false
|
||||
|
||||
override fun describeContents(): Int {
|
||||
return 0
|
||||
}
|
||||
|
||||
override fun writeToParcel(dest: Parcel, flags: Int) {
|
||||
dest.writeValue(id)
|
||||
dest.writeValue(clientId)
|
||||
dest.writeValue(chargeId)
|
||||
dest.writeString(name)
|
||||
dest.writeList(dueDate)
|
||||
dest.writeParcelable(chargeTimeType, flags)
|
||||
dest.writeParcelable(chargeCalculationType, flags)
|
||||
dest.writeParcelable(currency, flags)
|
||||
dest.writeValue(amount)
|
||||
dest.writeValue(amountPaid)
|
||||
dest.writeValue(amountWaived)
|
||||
dest.writeValue(amountWrittenOff)
|
||||
dest.writeValue(amountOutstanding)
|
||||
dest.writeValue(penalty)
|
||||
dest.writeValue(isActive)
|
||||
dest.writeValue(isChargePaid)
|
||||
dest.writeValue(isChargeWaived)
|
||||
dest.writeValue(paid)
|
||||
dest.writeValue(waived)
|
||||
}
|
||||
|
||||
constructor()
|
||||
private constructor(`in`: Parcel) {
|
||||
id = `in`.readValue(Int::class.java.classLoader) as Int
|
||||
clientId = `in`.readValue(Int::class.java.classLoader) as Int
|
||||
chargeId = `in`.readValue(Int::class.java.classLoader) as Int
|
||||
name = `in`.readString()
|
||||
dueDate = ArrayList()
|
||||
`in`.readList(dueDate, Int::class.java.classLoader)
|
||||
chargeTimeType = `in`.readParcelable(ChargeTimeType::class.java.classLoader)
|
||||
chargeCalculationType = `in`.readParcelable(ChargeCalculationType::class.java.classLoader)
|
||||
currency = `in`.readParcelable(Currency::class.java.classLoader)
|
||||
amount = `in`.readValue(Double::class.java.classLoader) as Double
|
||||
amountPaid = `in`.readValue(Double::class.java.classLoader) as Double
|
||||
amountWaived = `in`.readValue(Double::class.java.classLoader) as Double
|
||||
amountWrittenOff = `in`.readValue(Double::class.java.classLoader) as Double
|
||||
amountOutstanding = `in`.readValue(Double::class.java.classLoader) as Double
|
||||
penalty = `in`.readValue(Boolean::class.java.classLoader) as Boolean
|
||||
isActive = `in`.readValue(Boolean::class.java.classLoader) as Boolean
|
||||
isChargePaid = `in`.readValue(Boolean::class.java.classLoader) as Boolean
|
||||
isChargeWaived = `in`.readValue(Boolean::class.java.classLoader) as Boolean
|
||||
isChargePaid = `in`.readValue(Boolean::class.java.classLoader) as Boolean
|
||||
isChargeWaived = `in`.readValue(Boolean::class.java.classLoader) as Boolean
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val CREATOR: Parcelable.Creator<Charge?> = object : Parcelable.Creator<Charge?> {
|
||||
override fun createFromParcel(source: Parcel): Charge {
|
||||
return Charge(source)
|
||||
}
|
||||
|
||||
override fun newArray(size: Int): Array<Charge?> {
|
||||
return arrayOfNulls(size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.datastore.model
|
||||
|
||||
import com.raizlabs.android.dbflow.annotation.Column
|
||||
import com.raizlabs.android.dbflow.annotation.PrimaryKey
|
||||
import com.raizlabs.android.dbflow.annotation.Table
|
||||
import com.raizlabs.android.dbflow.structure.BaseModel
|
||||
import org.mifos.mobile.core.datastore.SelfServiceDatabase
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 13/9/17.
|
||||
*/
|
||||
@Table(database = SelfServiceDatabase::class)
|
||||
class MifosNotification : BaseModel() {
|
||||
|
||||
@JvmField
|
||||
@PrimaryKey
|
||||
var timeStamp: Long = 0
|
||||
|
||||
@JvmField
|
||||
@Column
|
||||
var msg: String? = null
|
||||
|
||||
@JvmField
|
||||
@Column
|
||||
var read: Boolean? = null
|
||||
fun getTimeStamp(): Long {
|
||||
return timeStamp
|
||||
}
|
||||
|
||||
fun setTimeStamp(timeStamp: Long) {
|
||||
this.timeStamp = timeStamp
|
||||
}
|
||||
|
||||
fun isRead(): Boolean {
|
||||
return read ?: false
|
||||
}
|
||||
|
||||
fun setRead(read: Boolean?) {
|
||||
this.read = read
|
||||
}
|
||||
}
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.datastore.utils
|
||||
|
||||
import org.mifos.mobile.core.datastore.model.MifosNotification
|
||||
|
||||
/**
|
||||
* Created by dilpreet on 14/9/17.
|
||||
*/
|
||||
class NotificationComparator : Comparator<MifosNotification> {
|
||||
override fun compare(
|
||||
firstNotification: MifosNotification,
|
||||
secondNotification: MifosNotification,
|
||||
): Int {
|
||||
return when {
|
||||
// comparator function logic to sort notifications in the descending order of their timeStamp :
|
||||
firstNotification.timeStamp > secondNotification.timeStamp -> -1
|
||||
firstNotification.timeStamp < secondNotification.timeStamp -> 1
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2024 Mifos Initiative
|
||||
* Copyright 2025 Mifos Initiative
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
@ -23,10 +23,6 @@ import org.mifos.mobile.core.model.enums.MifosAppLanguage
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/**
|
||||
* Author: Vishwajeet
|
||||
* Since: 07/06/16
|
||||
*/
|
||||
@Singleton
|
||||
class PreferencesHelper @Inject constructor(@ApplicationContext context: Context?) {
|
||||
private val sharedPreferences: SharedPreferences? =
|
||||
@ -98,7 +94,7 @@ class PreferencesHelper @Inject constructor(@ApplicationContext context: Context
|
||||
}
|
||||
|
||||
var tenant: String?
|
||||
get() = getString(TENANT, SelfServiceInterceptor.DEFAULT_TENANT)
|
||||
get() = getString(TENANT, DEFAULT_TENANT)
|
||||
set(tenant) {
|
||||
putString(TENANT, tenant)
|
||||
}
|
||||
@ -172,7 +168,7 @@ class PreferencesHelper @Inject constructor(@ApplicationContext context: Context
|
||||
}
|
||||
|
||||
val baseUrl: String?
|
||||
get() = getString(BASE_URL, BaseURL().defaultBaseUrl)
|
||||
get() = getString(BASE_URL, DEFAULT_BASE_URL)
|
||||
|
||||
var appTheme
|
||||
get() = getInt(APPLICATION_THEME, AppTheme.SYSTEM.ordinal) ?: AppTheme.SYSTEM.ordinal
|
||||
@ -181,13 +177,14 @@ class PreferencesHelper @Inject constructor(@ApplicationContext context: Context
|
||||
}
|
||||
|
||||
var language
|
||||
get() = getString(LANGUAGE_TYPE, MifosAppLanguage.ENGLISH.code) ?: MifosAppLanguage.SYSTEM_LANGUAGE.code
|
||||
get() = getString(LANGUAGE_TYPE, MifosAppLanguage.ENGLISH.code)
|
||||
?: MifosAppLanguage.SYSTEM_LANGUAGE.code
|
||||
set(language) {
|
||||
putString(LANGUAGE_TYPE, language)
|
||||
}
|
||||
|
||||
var isDefaultSystemLanguage
|
||||
get() = getBoolean(DEFAULT_SYSTEM_LANGUAGE, false) ?: false
|
||||
get() = getBoolean(DEFAULT_SYSTEM_LANGUAGE, false) == true
|
||||
set(value) {
|
||||
putBoolean(DEFAULT_SYSTEM_LANGUAGE, value)
|
||||
}
|
||||
@ -209,6 +206,9 @@ class PreferencesHelper @Inject constructor(@ApplicationContext context: Context
|
||||
const val APPLICATION_THEME = "application_theme"
|
||||
const val LANGUAGE_TYPE = "language_type"
|
||||
const val DEFAULT_SYSTEM_LANGUAGE = "default_system_language"
|
||||
|
||||
private const val DEFAULT_TENANT = "gsoc"
|
||||
private const val DEFAULT_BASE_URL = "https://gsoc.mifos.community"
|
||||
}
|
||||
|
||||
fun getStringFlowForKey(keyForString: String) = callbackFlow<String?> {
|
||||
@ -220,7 +220,7 @@ class PreferencesHelper @Inject constructor(@ApplicationContext context: Context
|
||||
sharedPreferences?.registerOnSharedPreferenceChangeListener(listener)
|
||||
send(getString(keyForString, null))
|
||||
awaitClose { sharedPreferences?.unregisterOnSharedPreferenceChangeListener(listener) }
|
||||
}.buffer(Channel.UNLIMITED)
|
||||
}.buffer(Channel.Factory.UNLIMITED)
|
||||
|
||||
fun getIntFlowForKey(keyForInt: String) = callbackFlow<Int?> {
|
||||
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
||||
@ -231,5 +231,5 @@ class PreferencesHelper @Inject constructor(@ApplicationContext context: Context
|
||||
sharedPreferences?.registerOnSharedPreferenceChangeListener(listener)
|
||||
send(getInt(keyForInt, -1))
|
||||
awaitClose { sharedPreferences?.unregisterOnSharedPreferenceChangeListener(listener) }
|
||||
}.buffer(Channel.UNLIMITED)
|
||||
}.buffer(Channel.Factory.UNLIMITED)
|
||||
}
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.datastore
|
||||
|
||||
class BaseURL {
|
||||
val url: String? = null
|
||||
get() = field
|
||||
?: (PROTOCOL_HTTPS + API_ENDPOINT + API_PATH)
|
||||
val defaultBaseUrl: String
|
||||
get() = PROTOCOL_HTTPS + API_ENDPOINT
|
||||
|
||||
fun getUrl(endpoint: String): String {
|
||||
return endpoint + API_PATH
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val API_ENDPOINT = "gsoc.mifos.community"
|
||||
const val API_PATH = "/fineract-provider/api/v1/"
|
||||
const val PROTOCOL_HTTPS = "https://"
|
||||
}
|
||||
}
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.datastore
|
||||
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Request
|
||||
import okhttp3.Request.Builder
|
||||
import okhttp3.Response
|
||||
import java.io.IOException
|
||||
|
||||
class SelfServiceInterceptor(private val preferencesHelper: PreferencesHelper) : Interceptor {
|
||||
@Throws(IOException::class)
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val chainRequest: Request = chain.request()
|
||||
val builder: Builder = chainRequest.newBuilder()
|
||||
builder.header("Content-Type", "application/json")
|
||||
builder.header("Accept", "application/json")
|
||||
|
||||
preferencesHelper.tenant?.let {
|
||||
builder.header(HEADER_TENANT, it)
|
||||
}
|
||||
|
||||
preferencesHelper.token?.let {
|
||||
if (it.isNotEmpty()) {
|
||||
builder.header(HEADER_AUTH, it)
|
||||
}
|
||||
}
|
||||
|
||||
val request: Request = builder.build()
|
||||
return chain.proceed(request)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val HEADER_TENANT = "Fineract-Platform-TenantId"
|
||||
const val HEADER_AUTH = "Authorization"
|
||||
const val DEFAULT_TENANT = "gsoc"
|
||||
}
|
||||
}
|
||||
@ -26,6 +26,7 @@ dependencies {
|
||||
api(projects.core.common)
|
||||
|
||||
implementation(libs.jetbrains.kotlin.jdk7)
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
|
||||
// For Serialized name
|
||||
implementation(libs.squareup.retrofit.converter.gson)
|
||||
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.model.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class Charge(
|
||||
val clientId: Int? = null,
|
||||
val chargeId: Int? = null,
|
||||
val name: String? = null,
|
||||
val dueDate: ArrayList<Int?> = ArrayList(),
|
||||
val chargeTimeType: ChargeTimeType? = null,
|
||||
val chargeCalculationType: ChargeCalculationType? = null,
|
||||
val currency: Currency? = null,
|
||||
val amount: Double = 0.0,
|
||||
val amountPaid: Double = 0.0,
|
||||
val amountWaived: Double = 0.0,
|
||||
val amountWrittenOff: Double = 0.0,
|
||||
val amountOutstanding: Double = 0.0,
|
||||
val penalty: Boolean = false,
|
||||
val isActive: Boolean = false,
|
||||
val isChargePaid: Boolean = false,
|
||||
val isChargeWaived: Boolean = false,
|
||||
val paid: Boolean = false,
|
||||
val waived: Boolean = false,
|
||||
) : Parcelable
|
||||
@ -11,8 +11,10 @@ package org.mifos.mobile.core.model.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Parcelize
|
||||
@Serializable
|
||||
data class ChargeCalculationType(
|
||||
var id: Int = 0,
|
||||
var code: String? = null,
|
||||
|
||||
@ -24,5 +24,4 @@ data class Currency(
|
||||
var displaySymbol: String? = null,
|
||||
var nameCode: String? = null,
|
||||
var displayLabel: String? = null,
|
||||
|
||||
) : Parcelable
|
||||
|
||||
@ -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-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.model.entity
|
||||
|
||||
import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Parcelize
|
||||
@Serializable
|
||||
data class MifosNotification(
|
||||
var timeStamp: Long,
|
||||
var msg: String? = null,
|
||||
var read: Boolean? = null,
|
||||
) : Parcelable {
|
||||
fun isRead(): Boolean {
|
||||
return read == true
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.datastore
|
||||
package org.mifos.mobile.core.network
|
||||
|
||||
class BaseURL {
|
||||
val url: String? = null
|
||||
@ -11,10 +11,8 @@ package org.mifos.mobile.core.network
|
||||
|
||||
import io.reactivex.Observable
|
||||
import okhttp3.ResponseBody
|
||||
import org.mifos.mobile.core.datastore.DatabaseHelper
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
import org.mifos.mobile.core.datastore.model.Charge
|
||||
import org.mifos.mobile.core.datastore.model.MifosNotification
|
||||
import org.mifos.mobile.core.model.entity.Charge
|
||||
import org.mifos.mobile.core.model.entity.Page
|
||||
import org.mifos.mobile.core.model.entity.Transaction
|
||||
import org.mifos.mobile.core.model.entity.UpdatePasswordPayload
|
||||
@ -53,7 +51,6 @@ import javax.inject.Singleton
|
||||
class DataManager @Inject constructor(
|
||||
val preferencesHelper: PreferencesHelper,
|
||||
private val baseApiManager: BaseApiManager,
|
||||
private val databaseHelper: DatabaseHelper,
|
||||
) {
|
||||
var clientId: Long? = preferencesHelper.clientId
|
||||
|
||||
@ -88,9 +85,7 @@ class DataManager @Inject constructor(
|
||||
}
|
||||
|
||||
suspend fun getClientCharges(clientId: Long): Page<Charge> {
|
||||
return baseApiManager.clientChargeApi.getClientChargeList(clientId).apply {
|
||||
databaseHelper.syncCharges(this)
|
||||
}
|
||||
return baseApiManager.clientChargeApi.getClientChargeList(clientId)
|
||||
}
|
||||
|
||||
suspend fun getLoanCharges(loanId: Long): List<Charge> {
|
||||
@ -209,14 +204,6 @@ class DataManager @Inject constructor(
|
||||
return baseApiManager.registrationApi.verifyUser(userVerify)
|
||||
}
|
||||
|
||||
fun clientLocalCharges(): Page<Charge?> = databaseHelper.clientCharges()
|
||||
|
||||
fun notifications(): List<MifosNotification> = databaseHelper.notifications()
|
||||
|
||||
fun unreadNotificationsCount(): Int {
|
||||
return databaseHelper.unreadNotificationsCount()
|
||||
}
|
||||
|
||||
suspend fun registerNotification(payload: NotificationRegisterPayload?): ResponseBody {
|
||||
return baseApiManager.notificationApi.registerNotification(payload)
|
||||
}
|
||||
|
||||
@ -7,17 +7,14 @@
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
package org.mifos.mobile.core.datastore
|
||||
package org.mifos.mobile.core.network
|
||||
|
||||
import android.text.TextUtils
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
import java.io.IOException
|
||||
|
||||
/**
|
||||
* @author Vishwajeet
|
||||
* @since 21/06/16
|
||||
*/
|
||||
class SelfServiceInterceptor(private val preferencesHelper: PreferencesHelper) : Interceptor {
|
||||
@Throws(IOException::class)
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
@ -12,7 +12,6 @@ package org.mifos.mobile.core.network
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
import org.mifos.mobile.core.datastore.SelfServiceInterceptor
|
||||
import java.security.SecureRandom
|
||||
import java.security.cert.CertificateException
|
||||
import java.security.cert.X509Certificate
|
||||
|
||||
@ -13,8 +13,8 @@ import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import org.mifos.mobile.core.datastore.BaseURL
|
||||
import org.mifos.mobile.core.datastore.PreferencesHelper
|
||||
import org.mifos.mobile.core.network.BaseURL
|
||||
import org.mifos.mobile.core.network.SelfServiceOkHttpClient
|
||||
import org.mifos.mobile.core.network.services.AuthenticationService
|
||||
import org.mifos.mobile.core.network.services.BeneficiaryService
|
||||
|
||||
@ -10,15 +10,11 @@
|
||||
package org.mifos.mobile.core.network.services
|
||||
|
||||
import org.mifos.mobile.core.common.ApiEndPoints
|
||||
import org.mifos.mobile.core.datastore.model.Charge
|
||||
import org.mifos.mobile.core.model.entity.Charge
|
||||
import org.mifos.mobile.core.model.entity.Page
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Path
|
||||
|
||||
/**
|
||||
* @author Vishwajeet
|
||||
* @since 17/8/16.
|
||||
*/
|
||||
interface ClientChargeService {
|
||||
|
||||
@GET(ApiEndPoints.CLIENTS + "/{clientId}/charges")
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
package org.mifos.mobile.core.testing.util
|
||||
|
||||
import com.google.gson.reflect.TypeToken
|
||||
import org.mifos.mobile.core.datastore.model.Charge
|
||||
import org.mifos.mobile.core.database.entity.ChargeEntity
|
||||
import org.mifos.mobile.core.model.entity.Page
|
||||
import org.mifos.mobile.core.model.entity.Transaction
|
||||
import org.mifos.mobile.core.model.entity.UpdatePasswordPayload
|
||||
@ -177,22 +177,22 @@ object FakeRemoteDataSource {
|
||||
LoginPayload::class.java,
|
||||
FakeJsonName.LOGIN,
|
||||
)
|
||||
val charge: Page<Charge?>?
|
||||
get() = mTestDataFactory.getListTypePojo<Page<Charge?>?>(
|
||||
val charge: Page<ChargeEntity?>?
|
||||
get() = mTestDataFactory.getListTypePojo<Page<ChargeEntity?>?>(
|
||||
object :
|
||||
TypeToken<Page<Charge?>?>() {},
|
||||
TypeToken<Page<ChargeEntity?>?>() {},
|
||||
FakeJsonName.CHARGE,
|
||||
)
|
||||
val savingsCharge: List<Charge>
|
||||
val savingsCharge: List<ChargeEntity>
|
||||
get() = mTestDataFactory.getListTypePojo(
|
||||
object :
|
||||
TypeToken<List<Charge>?>() {},
|
||||
TypeToken<List<ChargeEntity>?>() {},
|
||||
FakeJsonName.SAVING_CHARGE,
|
||||
)
|
||||
val loanCharge: List<Charge>
|
||||
val loanCharge: List<ChargeEntity>
|
||||
get() = mTestDataFactory.getListTypePojo(
|
||||
object :
|
||||
TypeToken<List<Charge>?>() {},
|
||||
TypeToken<List<ChargeEntity>?>() {},
|
||||
FakeJsonName.LOAN_CHARGE,
|
||||
)
|
||||
val userVerify: UserVerify
|
||||
|
||||
@ -9,21 +9,17 @@
|
||||
*/
|
||||
package org.mifos.mobile.feature.beneficiary.beneficiaryList
|
||||
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@ -99,62 +95,43 @@ private fun BeneficiaryListScreen(
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(it)
|
||||
.nestedScroll(pullRefreshState.nestedScrollConnection),
|
||||
.padding(it),
|
||||
) {
|
||||
when (uiState) {
|
||||
BeneficiaryListUiState.Loading -> {
|
||||
MifosProgressIndicatorOverlay()
|
||||
}
|
||||
PullToRefreshBox(
|
||||
state = pullRefreshState,
|
||||
onRefresh = refresh,
|
||||
isRefreshing = isRefreshing,
|
||||
) {
|
||||
when (uiState) {
|
||||
BeneficiaryListUiState.Loading -> {
|
||||
MifosProgressIndicatorOverlay()
|
||||
}
|
||||
|
||||
is BeneficiaryListUiState.Error -> {
|
||||
MifosErrorComponent(
|
||||
isNetworkConnected = Network.isConnected(context),
|
||||
isRetryEnabled = true,
|
||||
onRetry = retryLoadingBeneficiary,
|
||||
message = stringResource(R.string.error_fetching_beneficiaries),
|
||||
)
|
||||
}
|
||||
|
||||
is BeneficiaryListUiState.Success -> {
|
||||
if (uiState.beneficiaries.isEmpty()) {
|
||||
EmptyDataView(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
icon = R.drawable.ic_error_black_24dp,
|
||||
error = R.string.no_beneficiary_found_please_add,
|
||||
)
|
||||
} else {
|
||||
ShowBeneficiary(
|
||||
beneficiaryList = uiState.beneficiaries,
|
||||
onClick = onBeneficiaryItemClick,
|
||||
is BeneficiaryListUiState.Error -> {
|
||||
MifosErrorComponent(
|
||||
isNetworkConnected = Network.isConnected(context),
|
||||
isRetryEnabled = true,
|
||||
onRetry = retryLoadingBeneficiary,
|
||||
message = stringResource(R.string.error_fetching_beneficiaries),
|
||||
)
|
||||
}
|
||||
|
||||
is BeneficiaryListUiState.Success -> {
|
||||
if (uiState.beneficiaries.isEmpty()) {
|
||||
EmptyDataView(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
icon = R.drawable.ic_error_black_24dp,
|
||||
error = R.string.no_beneficiary_found_please_add,
|
||||
)
|
||||
} else {
|
||||
ShowBeneficiary(
|
||||
beneficiaryList = uiState.beneficiaries,
|
||||
onClick = onBeneficiaryItemClick,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PullToRefreshContainer(
|
||||
state = pullRefreshState,
|
||||
modifier = Modifier.align(Alignment.TopCenter),
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = isRefreshing) {
|
||||
if (isRefreshing) pullRefreshState.startRefresh()
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = pullRefreshState.isRefreshing) {
|
||||
if (pullRefreshState.isRefreshing) {
|
||||
if (Network.isConnected(context)) {
|
||||
refresh()
|
||||
} else {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.resources.getText(R.string.internet_not_connected),
|
||||
Toast.LENGTH_SHORT,
|
||||
).show()
|
||||
}
|
||||
pullRefreshState.endRefresh()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,5 +17,5 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.dbflow)
|
||||
|
||||
}
|
||||
@ -38,11 +38,11 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import org.mifos.mobile.core.common.Network
|
||||
import org.mifos.mobile.core.common.utils.CurrencyUtil
|
||||
import org.mifos.mobile.core.common.utils.DateHelper
|
||||
import org.mifos.mobile.core.datastore.model.Charge
|
||||
import org.mifos.mobile.core.designsystem.components.MifosScaffold
|
||||
import org.mifos.mobile.core.designsystem.theme.GreenSuccess
|
||||
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
|
||||
import org.mifos.mobile.core.designsystem.theme.RedErrorDark
|
||||
import org.mifos.mobile.core.model.entity.Charge
|
||||
import org.mifos.mobile.core.ui.component.EmptyDataView
|
||||
import org.mifos.mobile.core.ui.component.MifosErrorComponent
|
||||
import org.mifos.mobile.core.ui.component.MifosProgressIndicator
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
*/
|
||||
package org.mifos.mobile.feature.charge.utils
|
||||
|
||||
import org.mifos.mobile.core.datastore.model.Charge
|
||||
import org.mifos.mobile.core.model.entity.Charge
|
||||
|
||||
internal sealed class ClientChargeState {
|
||||
data object Loading : ClientChargeState()
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
*/
|
||||
package org.mifos.mobile.feature.charge.viewmodel
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@ -28,8 +29,8 @@ import javax.inject.Inject
|
||||
@HiltViewModel
|
||||
internal class ClientChargeViewModel @Inject constructor(
|
||||
private val clientChargeRepositoryImp: ClientChargeRepository,
|
||||
val preferencesHelper: PreferencesHelper,
|
||||
private val savedStateHandle: SavedStateHandle,
|
||||
preferencesHelper: PreferencesHelper,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _clientChargeUiState = MutableStateFlow<ClientChargeState>(Loading)
|
||||
@ -63,6 +64,8 @@ internal class ClientChargeViewModel @Inject constructor(
|
||||
clientChargeRepositoryImp.getClientCharges(clientId).catch {
|
||||
_clientChargeUiState.value = ClientChargeState.Error(it.message)
|
||||
}.collect {
|
||||
Log.e("selfServiceDatabase", it.toString())
|
||||
clientChargeRepositoryImp.syncCharges(it)
|
||||
_clientChargeUiState.value = ClientChargeState.Success(it.pageItems)
|
||||
}
|
||||
}
|
||||
@ -96,8 +99,7 @@ internal class ClientChargeViewModel @Inject constructor(
|
||||
clientChargeRepositoryImp.clientLocalCharges().catch {
|
||||
_clientChargeUiState.value = ClientChargeState.Error(it.message)
|
||||
}.collect {
|
||||
_clientChargeUiState.value =
|
||||
ClientChargeState.Success(it.pageItems.filterNotNull())
|
||||
_clientChargeUiState.value = ClientChargeState.Success(it.pageItems)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,5 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.core.datastore)
|
||||
implementation(libs.dbflow)
|
||||
|
||||
}
|
||||
@ -24,17 +24,15 @@ import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
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.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@ -45,10 +43,10 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import org.mifos.mobile.core.common.Network
|
||||
import org.mifos.mobile.core.common.utils.DateHelper
|
||||
import org.mifos.mobile.core.datastore.model.MifosNotification
|
||||
import org.mifos.mobile.core.designsystem.components.MifosScaffold
|
||||
import org.mifos.mobile.core.designsystem.components.MifosTextButton
|
||||
import org.mifos.mobile.core.designsystem.theme.MifosMobileTheme
|
||||
import org.mifos.mobile.core.model.entity.MifosNotification
|
||||
import org.mifos.mobile.core.ui.component.EmptyDataView
|
||||
import org.mifos.mobile.core.ui.component.MifosErrorComponent
|
||||
import org.mifos.mobile.core.ui.component.MifosProgressIndicatorOverlay
|
||||
@ -137,24 +135,11 @@ private fun NotificationContent(
|
||||
) {
|
||||
val pullRefreshState = rememberPullToRefreshState()
|
||||
|
||||
if (pullRefreshState.isRefreshing) {
|
||||
LaunchedEffect(key1 = true) {
|
||||
onRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(key1 = isRefreshing) {
|
||||
if (isRefreshing) {
|
||||
pullRefreshState.startRefresh()
|
||||
} else {
|
||||
pullRefreshState.endRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.nestedScroll(pullRefreshState.nestedScrollConnection),
|
||||
PullToRefreshBox(
|
||||
state = pullRefreshState,
|
||||
onRefresh = onRefresh,
|
||||
isRefreshing = isRefreshing,
|
||||
modifier = modifier,
|
||||
) {
|
||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||
itemsIndexed(items = notifications) { index, notification ->
|
||||
@ -167,10 +152,6 @@ private fun NotificationContent(
|
||||
}
|
||||
}
|
||||
}
|
||||
PullToRefreshContainer(
|
||||
state = pullRefreshState,
|
||||
modifier = Modifier.align(Alignment.TopCenter),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,8 +208,16 @@ internal class NotificationUiStatePreviews : PreviewParameterProvider<Notificati
|
||||
get() = sequenceOf(
|
||||
NotificationUiState.Success(
|
||||
notifications = listOf(
|
||||
MifosNotification(),
|
||||
MifosNotification(),
|
||||
MifosNotification(
|
||||
timeStamp = 13231331L,
|
||||
msg = "Your payment is successful",
|
||||
read = false,
|
||||
),
|
||||
MifosNotification(
|
||||
timeStamp = 13231331L,
|
||||
msg = "Your payment is successful",
|
||||
read = true,
|
||||
),
|
||||
),
|
||||
),
|
||||
NotificationUiState.Error(errorMessage = ""),
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
*/
|
||||
package org.mifos.mobile.feature.notification
|
||||
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
@ -17,7 +18,7 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.launch
|
||||
import org.mifos.mobile.core.data.repository.NotificationRepository
|
||||
import org.mifos.mobile.core.datastore.model.MifosNotification
|
||||
import org.mifos.mobile.core.model.entity.MifosNotification
|
||||
import org.mifos.mobile.feature.notification.NotificationUiState.Loading
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -33,7 +34,10 @@ internal class NotificationViewModel @Inject constructor(
|
||||
val isRefreshing: StateFlow<Boolean> get() = _isRefreshing
|
||||
|
||||
init {
|
||||
loadNotifications()
|
||||
viewModelScope.launch {
|
||||
notificationRepositoryImp.deleteOldNotifications()
|
||||
loadNotifications()
|
||||
}
|
||||
}
|
||||
|
||||
fun loadNotifications() {
|
||||
@ -41,12 +45,15 @@ internal class NotificationViewModel @Inject constructor(
|
||||
viewModelScope.launch {
|
||||
notificationRepositoryImp.loadNotifications()
|
||||
.catch {
|
||||
Log.e("selfServiceDatabase", it.toString())
|
||||
_notificationUiState.value =
|
||||
NotificationUiState.Error(errorMessage = it.message)
|
||||
}.collect { notifications ->
|
||||
Log.e("selfServiceDatabase", notifications.toString())
|
||||
val sortedNotifications = sortNotifications(notifications)
|
||||
_isRefreshing.emit(false)
|
||||
_notificationUiState.value =
|
||||
NotificationUiState.Success(notifications = notifications)
|
||||
NotificationUiState.Success(notifications = sortedNotifications)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,8 +64,18 @@ internal class NotificationViewModel @Inject constructor(
|
||||
}
|
||||
|
||||
fun dismissNotification(notification: MifosNotification) {
|
||||
notification.setRead(true)
|
||||
notification.save()
|
||||
notification.read = true
|
||||
viewModelScope.launch {
|
||||
notificationRepositoryImp.saveNotification(notification.copy(read = true))
|
||||
notificationRepositoryImp.updateReadStatus(notification, true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sortNotifications(notifications: List<MifosNotification>): List<MifosNotification> {
|
||||
return notifications.sortedWith(
|
||||
compareByDescending<MifosNotification> { !it.isRead() }
|
||||
.thenByDescending { it.timeStamp },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -13,12 +13,10 @@ import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
@ -27,11 +25,11 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||
import com.google.accompanist.permissions.PermissionState
|
||||
import com.google.accompanist.permissions.rememberPermissionState
|
||||
@ -110,7 +108,7 @@ internal fun PermissionBox(
|
||||
contract = ActivityResultContracts.RequestMultiplePermissions(),
|
||||
onResult = { permissionResults ->
|
||||
val isGranted =
|
||||
requiredPermissions.all { permissionResults[it] ?: false }
|
||||
requiredPermissions.all { permissionResults[it] == true }
|
||||
|
||||
permissionGranted = isGranted
|
||||
|
||||
@ -179,7 +177,6 @@ internal fun PermissionBox(
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
internal fun convertToMutableBitmap(bitmap: Bitmap): Bitmap {
|
||||
return if (bitmap.config == Bitmap.Config.HARDWARE) {
|
||||
bitmap.copy(Bitmap.Config.ARGB_8888, true)
|
||||
|
||||
@ -26,15 +26,13 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
|
||||
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
|
||||
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@ -104,64 +102,50 @@ private fun RecentTransactionScreen(
|
||||
Box(
|
||||
Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.nestedScroll(pullRefreshState.nestedScrollConnection),
|
||||
.padding(paddingValues),
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
PullToRefreshBox(
|
||||
state = pullRefreshState,
|
||||
onRefresh = onRefresh,
|
||||
isRefreshing = isRefreshing,
|
||||
) {
|
||||
when (uiState) {
|
||||
is RecentTransactionState.Error -> {
|
||||
MifosErrorComponent(
|
||||
isNetworkConnected = Network.isConnected(context),
|
||||
isRetryEnabled = true,
|
||||
onRetry = onRetry,
|
||||
)
|
||||
}
|
||||
|
||||
is RecentTransactionState.Loading -> {
|
||||
MifosProgressIndicatorOverlay()
|
||||
}
|
||||
|
||||
is RecentTransactionState.Success -> {
|
||||
if (uiState.transactions.isEmpty()) {
|
||||
EmptyDataView(
|
||||
icon = R.drawable.ic_error_black_24dp,
|
||||
error = R.string.no_transaction,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
} else {
|
||||
RecentTransactionsContent(
|
||||
transactions = uiState.transactions,
|
||||
isPaginating = isPaginating,
|
||||
loadMore = loadMore,
|
||||
canPaginate = uiState.canPaginate,
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize(),
|
||||
verticalArrangement = Arrangement.Center,
|
||||
) {
|
||||
when (uiState) {
|
||||
is RecentTransactionState.Error -> {
|
||||
MifosErrorComponent(
|
||||
isNetworkConnected = Network.isConnected(context),
|
||||
isRetryEnabled = true,
|
||||
onRetry = onRetry,
|
||||
)
|
||||
}
|
||||
|
||||
is RecentTransactionState.Loading -> {
|
||||
MifosProgressIndicatorOverlay()
|
||||
}
|
||||
|
||||
is RecentTransactionState.Success -> {
|
||||
if (uiState.transactions.isEmpty()) {
|
||||
EmptyDataView(
|
||||
icon = R.drawable.ic_error_black_24dp,
|
||||
error = R.string.no_transaction,
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
)
|
||||
} else {
|
||||
RecentTransactionsContent(
|
||||
transactions = uiState.transactions,
|
||||
isPaginating = isPaginating,
|
||||
loadMore = loadMore,
|
||||
canPaginate = uiState.canPaginate,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pullRefreshState.isRefreshing) {
|
||||
LaunchedEffect(key1 = true) {
|
||||
onRefresh()
|
||||
}
|
||||
}
|
||||
LaunchedEffect(key1 = isRefreshing) {
|
||||
if (isRefreshing) {
|
||||
pullRefreshState.startRefresh()
|
||||
} else {
|
||||
pullRefreshState.endRefresh()
|
||||
}
|
||||
}
|
||||
|
||||
PullToRefreshContainer(
|
||||
state = pullRefreshState,
|
||||
modifier = Modifier
|
||||
.padding(top = 24.dp)
|
||||
.align(Alignment.TopCenter),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
@ -1,37 +1,36 @@
|
||||
[versions]
|
||||
accompanistVersion = "0.34.0"
|
||||
activityVersion = "1.9.1"
|
||||
androidDesugarJdkLibs = "2.1.1"
|
||||
androidGradlePlugin = "8.5.2"
|
||||
androidTools = "31.5.2"
|
||||
activityVersion = "1.9.3"
|
||||
androidDesugarJdkLibs = "2.1.4"
|
||||
androidGradlePlugin = "8.7.0"
|
||||
androidTools = "31.7.0"
|
||||
androidx-test-ext-junit = "1.2.1"
|
||||
androidxActivity = "1.9.1"
|
||||
androidxComposeBom = "2024.08.00"
|
||||
androidxActivity = "1.9.3"
|
||||
androidxComposeBom = "2024.12.01"
|
||||
androidxComposeCompiler = "1.5.15"
|
||||
androidxCoreSplashscreen = "1.0.1"
|
||||
androidxEspresso = "3.6.1"
|
||||
androidxHilt = "1.2.0"
|
||||
androidxLifecycle = "2.8.4"
|
||||
androidxLifecycle = "2.8.7"
|
||||
androidxMetrics = "1.0.0-beta01"
|
||||
androidxNavigation = "2.8.0-rc01"
|
||||
androidxProfileinstaller = "1.3.1"
|
||||
androidxNavigation = "2.8.5"
|
||||
androidxProfileinstaller = "1.4.1"
|
||||
androidxTestExt = "1.2.1"
|
||||
androidxTestRules = "1.6.1"
|
||||
androidxTestRunner = "1.6.2"
|
||||
androidxTracing = "1.2.0"
|
||||
androidxUiAutomator = "2.3.0"
|
||||
annotationVersion = "1.8.2"
|
||||
annotation = "1.9.1"
|
||||
appcompatVersion = "1.7.0"
|
||||
cameraCoreVersion = "1.3.4"
|
||||
cameraxVersion = "1.3.4"
|
||||
compose-material = "1.6.8"
|
||||
cameraxVersion = "1.4.1"
|
||||
compose-material = "1.7.6"
|
||||
compose-plugin = "1.6.11"
|
||||
coreKtxVersion = "1.13.1"
|
||||
dbflowVersion = "4.2.4"
|
||||
coreKtx = "1.15.0"
|
||||
dependencyGuard = "0.5.0"
|
||||
detekt = "1.23.5"
|
||||
detekt = "1.23.7"
|
||||
easycropVersion = "0.1.1"
|
||||
firebaseBom = "33.2.0"
|
||||
firebaseBom = "33.7.0"
|
||||
firebaseCrashlyticsPlugin = "3.0.2"
|
||||
firebasePerfPlugin = "1.4.2"
|
||||
gmsPlugin = "4.4.2"
|
||||
@ -39,23 +38,25 @@ googleAppCodeScanner = "17.3.0"
|
||||
googleMaps = "4.4.1"
|
||||
googleOss = "17.1.0"
|
||||
googleOssPlugin = "0.10.6"
|
||||
hilt = "2.52"
|
||||
gsonVersion = "2.10.1"
|
||||
hilt = "2.54"
|
||||
hiltExt = "1.2.0"
|
||||
jacoco = "0.8.7"
|
||||
junitVersion = "4.13.2"
|
||||
koin = "3.6.0-Beta4"
|
||||
koinComposeMultiplatform = "1.2.0-Beta4"
|
||||
kotlin = "2.0.20"
|
||||
kotlinxCoroutinesAndroidVersion = "1.8.1"
|
||||
kotlinxCoroutinesTestVersion = "1.8.1"
|
||||
kotlinxImmutable = "0.3.7"
|
||||
ksp = "2.0.20-1.0.24"
|
||||
koin = "4.0.0"
|
||||
koinComposeMultiplatform = "4.0.0"
|
||||
kotlin = "2.1.0"
|
||||
kotlinxCoroutines = "1.10.1"
|
||||
kotlinxImmutable = "0.3.8"
|
||||
kotlinxSerializationJson = "1.8.0-RC"
|
||||
ksp = "2.1.0-1.0.29"
|
||||
ktlint = "12.1.1"
|
||||
libphonenumberAndroidVersion = "8.13.35"
|
||||
lifecycleExtensionsVersion = "2.2.0"
|
||||
lifecycleVersion = "2.8.4"
|
||||
material3 = "1.2.1"
|
||||
mockitoAndroidVersion = "5.4.0"
|
||||
mockitoCoreVersion = "5.4.0"
|
||||
lifecycleLivedataKtxVersion = "2.8.7"
|
||||
lifecycleVersion = "2.8.7"
|
||||
material3 = "1.3.1"
|
||||
mockitoCoreVersion = "5.6.0"
|
||||
multidexVersion = "2.0.1"
|
||||
okHttp3Version = "4.12.0"
|
||||
playServicesCodeScanner = "16.1.0"
|
||||
@ -63,12 +64,15 @@ playServicesVersion = "19.0.0"
|
||||
retrofitVersion = "2.11.0"
|
||||
roborazzi = "1.26.0"
|
||||
room = "2.6.1"
|
||||
roomKtxVersion = "2.6.1"
|
||||
roomRuntimeVersion = "2.6.1"
|
||||
roomTestingVersion = "2.6.1"
|
||||
rxandroidVersion = "2.1.1"
|
||||
rxjavaVersion = "2.2.21"
|
||||
secrets = "2.0.1"
|
||||
slackComposeLint = "1.3.1"
|
||||
spotlessVersion = "6.23.3"
|
||||
truth = "1.4.2"
|
||||
spotlessVersion = "6.25.0"
|
||||
truth = "1.4.4"
|
||||
turbineVersion = "1.1.0"
|
||||
twitter-detekt-compose = "0.0.26"
|
||||
versionCatalogLinterVersion = "1.0.3"
|
||||
@ -82,7 +86,7 @@ android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", ver
|
||||
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-annotation = { group = "androidx.annotation", name = "annotation", version.ref = "annotationVersion" }
|
||||
androidx-annotation = { group = "androidx.annotation", name = "annotation", version.ref = "annotation" }
|
||||
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompatVersion" }
|
||||
androidx-camera-camera2 = { group = "androidx.camera", name = "camera-camera2", version.ref = "cameraxVersion" }
|
||||
androidx-camera-core = { group = "androidx.camera", name = "camera-core", version.ref = "cameraxVersion" }
|
||||
@ -103,11 +107,12 @@ 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-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" }
|
||||
androidx-lifecycle-runtimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", 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" }
|
||||
@ -116,6 +121,10 @@ androidx-multidex = { group = "androidx.multidex", name = "multidex", version.re
|
||||
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-room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room" }
|
||||
androidx-room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "roomKtxVersion" }
|
||||
androidx-room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "roomRuntimeVersion" }
|
||||
androidx-room-testing = { group = "androidx.room", name = "room-testing", version.ref = "roomTestingVersion" }
|
||||
androidx-test-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidxEspresso" }
|
||||
androidx-test-ext = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "androidxTestExt" }
|
||||
androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" }
|
||||
@ -124,9 +133,6 @@ androidx-test-runner = { group = "androidx.test", name = "runner", version.ref =
|
||||
androidx-test-uiautomator = { group = "androidx.test.uiautomator", name = "uiautomator", version.ref = "androidxUiAutomator" }
|
||||
androidx-tracing-ktx = { group = "androidx.tracing", name = "tracing-ktx", version.ref = "androidxTracing" }
|
||||
compose-gradlePlugin = { group = "org.jetbrains.kotlin", name = "compose-compiler-gradle-plugin", version.ref = "kotlin" }
|
||||
dbflow = { group = "com.github.Raizlabs.DBFlow", name = "dbflow", version.ref = "dbflowVersion" }
|
||||
dbflow-core = { group = "com.github.Raizlabs.DBFlow", name = "dbflow-core", version.ref = "dbflowVersion" }
|
||||
dbflow-processor = { group = "com.github.Raizlabs.DBFlow", name = "dbflow-processor", version.ref = "dbflowVersion" }
|
||||
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" }
|
||||
easycrop-compose = { group = "io.github.mr0xf00", name = "easycrop", version.ref = "easycropVersion" }
|
||||
@ -142,10 +148,15 @@ 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-android-compiler", 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" }
|
||||
jetbrains-kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" }
|
||||
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" }
|
||||
@ -155,15 +166,16 @@ koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin"
|
||||
kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
|
||||
kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", 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 = "kotlinxCoroutinesAndroidVersion" }
|
||||
kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesTestVersion" }
|
||||
kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" }
|
||||
kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" }
|
||||
kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" }
|
||||
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" }
|
||||
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" }
|
||||
mockito-android = { group = "org.mockito", name = "mockito-android", version.ref = "mockitoAndroidVersion" }
|
||||
mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockitoCoreVersion" }
|
||||
play-services-maps = { group = "com.google.android.gms", name = "play-services-maps", version.ref = "playServicesVersion" }
|
||||
reactivex-rxjava2 = { group = "io.reactivex.rxjava2", name = "rxjava", version.ref = "rxjavaVersion" }
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||
|
||||
@ -14,6 +14,10 @@ plugins {
|
||||
|
||||
android {
|
||||
namespace = "com.mifos.library.countrycodepicker"
|
||||
|
||||
lint {
|
||||
disable += "SuspiciousModifierThen"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@ -262,7 +262,7 @@ fun CountryCodePicker(
|
||||
visualTransformation = phoneNumberTransformation,
|
||||
keyboardOptions = keyboardOptions ?: KeyboardOptions.Default.copy(
|
||||
keyboardType = KeyboardType.Phone,
|
||||
autoCorrect = true,
|
||||
autoCorrectEnabled = true,
|
||||
imeAction = ImeAction.Done,
|
||||
),
|
||||
keyboardActions = keyboardActions ?: KeyboardActions(
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
*
|
||||
* See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md
|
||||
*/
|
||||
@file:Suppress("InvalidPackageDeclaration")
|
||||
@file:Suppress("InvalidPackageDeclaration", "DEPRECATION")
|
||||
|
||||
package com.mifos.library.pullrefresh
|
||||
|
||||
|
||||
@ -46,6 +46,7 @@ include(":core:model")
|
||||
include(":core:common")
|
||||
include(":core:data")
|
||||
include(":core:network")
|
||||
include(":core:database")
|
||||
include(":core:datastore")
|
||||
include(":core:qrcode")
|
||||
include(":core:testing")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user