Skip to content

Commit 6e118cc

Browse files
Bug Fix: Fix change passcode and logout functionality (#64)
* Integrate Koin for dependency injection and refactor PasscodeManager * Implement Koin dependency injection across Android, iOS, Desktop, and Web sample modules. * Introduce `passcodeModule` and `initKoin` to manage dependencies for `PasscodeManager`, `PasscodeStorageAdapter`, and ViewModels. * Refactor `SampleAppNavigation` and `App.kt` to use `koinInject()` and `koinViewModel()` instead of manual dependency passing. * Update `PasscodeManager` to use `MutableStateFlow.update` for thread-safe state mutations and ensure proper state clearing during initialization and deletion. * Enhance `PasscodeManager` to automatically save new passcodes to the adapter upon successful confirmation. * Update `libs.versions.toml` with Koin and KSP dependencies and apply necessary plugins in `build.gradle.kts`. * Initialize Koin in platform-specific entry points (`SampleApplication`, `MainViewController.kt`, `main.kt`). * Update passcode actions and handling in navigation and passcode manager * Refactor `PasscodeAction` by renaming `DeletePasscode` to `ForgetPasscode` and adding `LogOutErasePasscode`. * Update `PasscodeManager` to handle the new `LogOutErasePasscode` action by invoking `adapter.deletePasscode()` and handle `ForgetPasscode` instead of the former `DeletePasscode`. * Update `SampleAppNavigation` to inject `PasscodeStorageAdapter` and use `PasscodeAction.LogOutErasePasscode` for session clearing. * Update `PasscodeScreen` to use `PasscodeAction.ForgetPasscode` when the forgot button is clicked. * Clean up unused imports and update PasscodeModule header * Removed unused imports in `SampleAppNavigation.kt`, `SampleApplication.kt`, and `App.kt`. * Added license header to `PasscodeModule.kt`. * Applied minor formatting fixes, including trailing commas and whitespace cleanup in `SampleAppNavigation.kt`, `SampleApplication.kt`, `PasscodeModule.kt`, and `PasscodeManager.kt`. * Update dependency information in module READMEs * Updated the installation instructions in `mifos-authenticator-biometrics/README.md` to specify the full dependency notation `io.github.openmf:mifos-authenticator-passcode` and simplified the code examples. * Updated the prerequisites in `mifos-authenticator-passcode/README.md` to use the full Maven coordinate `io.github.openmf:mifos-authenticator-passcode`. * Rename authentication composition providers and locals * Renamed `LibraryLocalCompositionProvider` to `PlatformAuthenticatorLocalCompositionProvider` across all platforms (Android, iOS, Desktop, JS, WasmJS). * Renamed `libraryLocalPlatformAuthenticationProvider` to `platformAuthenticationProvider`. * Renamed `libraryPlatformAvailableAuthenticationOption` to `platformAvailableAuthenticationOption`. * Updated references in `App.kt`, `ChooseAuthOptionScreen.kt`, and `AuthenticationScreen.kt` to reflect the new names.
1 parent 81157b0 commit 6e118cc

25 files changed

Lines changed: 198 additions & 123 deletions

File tree

build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class KMPLibraryConventionPlugin : Plugin<Project> {
3838

3939
dependencies {
4040
add("commonMainImplementation", libs.findLibrary("kotlinx.coroutines.core").get())
41+
add("commonMainImplementation", libs.findLibrary("koin.core").get())
4142
}
4243
}
4344
}

build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ plugins {
1010
alias(libs.plugins.android.lint) apply false
1111
alias(libs.plugins.kotlin.android) apply false
1212

13+
alias(libs.plugins.ksp) apply false
1314
alias(libs.plugins.jetbrains.kotlin.serialization) apply false
1415
alias(libs.plugins.dependencyGuard) apply false
1516
alias(libs.plugins.detekt) apply false

cmp-sample-android/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ dependencies {
5555
testImplementation(libs.junit)
5656
androidTestImplementation(libs.androidx.junit)
5757
androidTestImplementation(libs.androidx.espresso.core)
58-
58+
implementation(libs.koin.android)
59+
implementation(libs.koin.androidx.compose)
60+
implementation(libs.koin.core)
5961
implementation(libs.androidx.activity.compose)
6062
}

cmp-sample-android/src/main/kotlin/cmp/sample/android/SampleApplication.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,17 @@
1010
package cmp.sample.android
1111

1212
import android.app.Application
13+
import cmp.sample.shared.di.passcodeModule
14+
import org.koin.android.ext.koin.androidContext
15+
import org.koin.core.context.startKoin
1316

14-
class SampleApplication : Application()
17+
class SampleApplication : Application() {
18+
19+
override fun onCreate() {
20+
super.onCreate()
21+
startKoin {
22+
androidContext(this@SampleApplication)
23+
modules(passcodeModule)
24+
}
25+
}
26+
}

cmp-sample-desktop/src/desktopMain/kotlin/cmp/sample/desktop/main.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ package cmp.sample.desktop
33
import androidx.compose.ui.window.Window
44
import androidx.compose.ui.window.application
55
import cmp.sample.shared.App
6+
import cmp.sample.shared.di.initKoin
67

78
fun main(vararg args: String) = application {
89

10+
initKoin()
11+
912
Window(
1013
onCloseRequest = ::exitApplication,
1114
title = "mifos-passcode-sample",

cmp-sample-ios/src/iosMain/kotlin/cmp/sample/ios/MainViewController.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package cmp.sample.ios
22

33
import androidx.compose.ui.window.ComposeUIViewController
44
import cmp.sample.shared.App
5+
import cmp.sample.shared.di.initKoin
56

67
fun MainViewController() = ComposeUIViewController {
8+
initKoin()
79
App()
810
}

cmp-sample-shared/build.gradle.kts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,22 @@ kotlin {
2020

2121

2222
sourceSets {
23-
2423
commonMain.dependencies {
2524
implementation(projects.mifosAuthenticatorBiometrics)
2625
implementation(projects.mifosAuthenticatorPasscode)
2726

27+
implementation(libs.koin.core)
28+
implementation(libs.koin.compose)
29+
implementation(libs.koin.compose.viewmodel)
30+
2831
implementation(libs.multiplatform.settings.no.arg)
2932
implementation(libs.multiplatform.settings.serialization)
3033
implementation(libs.multiplatform.settings.coroutines)
3134
}
35+
androidMain.dependencies {
36+
implementation(libs.koin.android)
37+
implementation(libs.koin.androidx.compose)
38+
}
3239
}
3340

3441
}

cmp-sample-shared/src/commonMain/kotlin/cmp/sample/shared/App.kt

Lines changed: 3 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,36 +11,14 @@ package cmp.sample.shared
1111

1212
import androidx.compose.material3.MaterialTheme
1313
import androidx.compose.runtime.Composable
14-
import cmp.sample.shared.chooseAuthOption.ChooseAuthOptionRepository
15-
import cmp.sample.shared.chooseAuthOption.ChooseAuthOptionScreenViewmodel
1614
import cmp.sample.shared.navigation.SampleAppNavigation
17-
import cmp.sample.shared.platformAuthentication.AuthenticationScreenViewModel
18-
import com.russhwolf.settings.Settings
19-
import org.mifos.authenticator.biometrics.LibraryLocalCompositionProvider
15+
import org.mifos.authenticator.biometrics.PlatformAuthenticatorLocalCompositionProvider
2016

2117
@Composable
2218
fun App() {
23-
LibraryLocalCompositionProvider {
19+
PlatformAuthenticatorLocalCompositionProvider {
2420
MaterialTheme {
25-
val settings = Settings()
26-
27-
val chooseAuthOptionRepository = ChooseAuthOptionRepository(settings)
28-
val chooseAuthOptionScreenViewmodel = ChooseAuthOptionScreenViewmodel(
29-
chooseAuthOptionRepository,
30-
)
31-
32-
val platformAuthOptionScreenViewmodel = AuthenticationScreenViewModel(
33-
chooseAuthOptionRepository = chooseAuthOptionRepository,
34-
settings = settings,
35-
)
36-
37-
val passcodeStorageAdapter = PasscodeStorageAdapterImpl(settings)
38-
39-
SampleAppNavigation(
40-
passcodeStorageAdapter,
41-
chooseAuthOptionScreenViewmodel,
42-
platformAuthOptionScreenViewmodel,
43-
)
21+
SampleAppNavigation()
4422
}
4523
}
4624
}

cmp-sample-shared/src/commonMain/kotlin/cmp/sample/shared/chooseAuthOption/ChooseAuthOptionScreen.kt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,17 @@ import cmp.sample.shared.chooseAuthOption.components.AuthOptionCard
4949
import cmp.sample.shared.navigation.Route
5050
import cmp.sample.shared.theme.blueTint
5151
import kotlinx.coroutines.launch
52-
import org.mifos.authenticator.biometrics.libraryLocalPlatformAuthenticationProvider
52+
import org.koin.compose.koinInject
53+
import org.koin.compose.viewmodel.koinViewModel
54+
import org.mifos.authenticator.biometrics.platformAuthenticationProvider
5355
import org.mifos.authenticator.biometrics.platformAuthenticator.RegistrationResult
56+
import org.mifos.authenticator.passcode.PasscodeManager
5457

5558
@OptIn(ExperimentalMaterial3Api::class)
5659
@Composable
5760
fun ChooseAuthOptionScreen(
58-
chooseAuthOptionScreenViewmodel: ChooseAuthOptionScreenViewmodel,
61+
chooseAuthOptionScreenViewmodel: ChooseAuthOptionScreenViewmodel = koinViewModel(),
62+
passcodeManager: PasscodeManager = koinInject(),
5963
navController: NavController,
6064
) {
6165
val registrationResult by chooseAuthOptionScreenViewmodel.registrationResult.collectAsState()
@@ -64,7 +68,7 @@ fun ChooseAuthOptionScreen(
6468
mutableStateOf(AppLockOption.None)
6569
}
6670

67-
val platformAuthenticationProvider = libraryLocalPlatformAuthenticationProvider.current
71+
val platformAuthenticationProvider = platformAuthenticationProvider.current
6872

6973
var dialogBoxType by rememberSaveable {
7074
mutableStateOf(DialogBoxType.None)
@@ -187,6 +191,7 @@ fun ChooseAuthOptionScreen(
187191
whenPasscodeSelected = {
188192
platformAuthenticationProvider.updateAuthenticatorStatus()
189193
chooseAuthOptionScreenViewmodel.saveAppLockOption(AppLockOption.MifosPasscode)
194+
passcodeManager.initialize()
190195
navController.popBackStack()
191196
navController.navigate(Route.PasscodeScreen) {
192197
popUpTo(0)
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2026 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mifos-passcode-cmp/blob/development/LICENSE
9+
*/
10+
package cmp.sample.shared.di
11+
12+
import cmp.sample.shared.PasscodeStorageAdapterImpl
13+
import cmp.sample.shared.chooseAuthOption.ChooseAuthOptionRepository
14+
import cmp.sample.shared.chooseAuthOption.ChooseAuthOptionScreenViewmodel
15+
import cmp.sample.shared.platformAuthentication.AuthenticationScreenViewModel
16+
import com.russhwolf.settings.Settings
17+
import kotlinx.coroutines.MainScope
18+
import org.koin.core.context.startKoin
19+
import org.koin.core.module.dsl.singleOf
20+
import org.koin.core.module.dsl.viewModelOf
21+
import org.koin.dsl.KoinAppDeclaration
22+
import org.koin.dsl.bind
23+
import org.koin.dsl.module
24+
import org.mifos.authenticator.passcode.PasscodeManager
25+
import org.mifos.authenticator.passcode.PasscodeStorageAdapter
26+
27+
val passcodeModule = module {
28+
singleOf(::PasscodeStorageAdapterImpl).bind<PasscodeStorageAdapter>()
29+
single {
30+
PasscodeManager(get(), MainScope()).initialize()
31+
}
32+
single { Settings() }
33+
single { ChooseAuthOptionRepository(get()) }
34+
viewModelOf(::ChooseAuthOptionScreenViewmodel)
35+
viewModelOf(::AuthenticationScreenViewModel)
36+
}
37+
38+
fun initKoin(config: KoinAppDeclaration? = null) {
39+
startKoin {
40+
config?.invoke(this)
41+
modules(passcodeModule)
42+
}
43+
}

0 commit comments

Comments
 (0)