diff --git a/.github/workflows/feature_branch_ci.yml b/.github/workflows/feature_branch_ci.yml deleted file mode 100644 index 64dffd00a..000000000 --- a/.github/workflows/feature_branch_ci.yml +++ /dev/null @@ -1,32 +0,0 @@ -name: Mobile-Wallet CI[Feature] - -on: - push: - branches: - - '*' - - '!dev' - - '!master' -jobs: - build: - name: Build APK - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - # Set up JDK - - name: Set Up JDK 17 - uses: actions/setup-java@v1 - with: - java-version: 17 - - # Install NDK - - name: Install NDK - run: echo "y" | sudo ${ANDROID_HOME}/tools/bin/sdkmanager --install "ndk;20.0.5594570" --sdk_root=${ANDROID_SDK_ROOT} - - # Update Gradle Permission - - name: Change gradlew Permission - run: chmod +x gradlew - - # Build App - - name: Build with Gradle - run: ./gradlew assemble diff --git a/.github/workflows/master_dev_ci.yml b/.github/workflows/master_dev_ci.yml index 88fe178ef..ba41c9883 100644 --- a/.github/workflows/master_dev_ci.yml +++ b/.github/workflows/master_dev_ci.yml @@ -75,7 +75,7 @@ jobs: - name: Check Dependency Guard id: dependencyguard_verify continue-on-error: true - run: ./gradlew dependencyGuard + run: ./gradlew :mifospay-android:dependencyGuard - name: Prevent updating Dependency Guard baselines if this is a fork id: checkfork_dependencyguard @@ -88,7 +88,7 @@ jobs: id: dependencyguard_baseline if: steps.dependencyguard_verify.outcome == 'failure' && github.event_name == 'pull_request' run: | - ./gradlew dependencyGuardBaseline + ./gradlew :mifospay-android:dependencyGuardBaseline - name: Push new Dependency Guard baselines if available uses: stefanzweifel/git-auto-commit-action@v5 @@ -109,7 +109,8 @@ jobs: java-version: 17 - name: Run tests run: | - ./gradlew testDemoDebug :lint:test :mifospay:lintProdRelease :lint:lint + ./gradlew :mifospay-android:testDemoDebug +# ./gradlew testDemoDebug :lint:test :mifospay-android:lintProdRelease :lint:lint - name: Upload reports if: always() uses: actions/upload-artifact@v4 @@ -130,12 +131,12 @@ jobs: java-version: 17 - name: Build APKs - run: ./gradlew :mifospay:assembleDemoDebug + run: ./gradlew :mifospay-android:assembleDemoDebug - name: Check badging # This step is allowed to fail, as it's not critical for the build continue-on-error: true - run: ./gradlew :mifospay:checkProdReleaseBadging + run: ./gradlew :mifospay-android:checkProdReleaseBadging - name: Upload APKs uses: actions/upload-artifact@v4 diff --git a/.run/mifospay-android.run.xml b/.run/mifospay-android.run.xml new file mode 100644 index 000000000..2b81165ce --- /dev/null +++ b/.run/mifospay-android.run.xml @@ -0,0 +1,70 @@ + + + + + \ No newline at end of file diff --git a/.run/mifospay-desktop.run.xml b/.run/mifospay-desktop.run.xml new file mode 100644 index 000000000..6044007fa --- /dev/null +++ b/.run/mifospay-desktop.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/mifospay-web-js.run.xml b/.run/mifospay-web-js.run.xml new file mode 100644 index 000000000..d6b902502 --- /dev/null +++ b/.run/mifospay-web-js.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/.run/mifospay-web-wasm.run.xml b/.run/mifospay-web-wasm.run.xml new file mode 100644 index 000000000..6bdae484b --- /dev/null +++ b/.run/mifospay-web-wasm.run.xml @@ -0,0 +1,24 @@ + + + + + + + true + true + false + false + + + \ No newline at end of file diff --git a/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt b/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt index c57ee23b3..f4f34d30a 100644 --- a/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/CMPFeatureConventionPlugin.kt @@ -9,7 +9,7 @@ class CMPFeatureConventionPlugin : Plugin { with(target) { pluginManager.apply { apply("mifospay.kmp.library") - apply("mifospay.kmp.inject") + apply("mifospay.kmp.koin") apply("org.jetbrains.kotlin.plugin.compose") apply("org.jetbrains.compose") } @@ -18,11 +18,15 @@ class CMPFeatureConventionPlugin : Plugin { add("commonMainImplementation", project(":core:ui")) add("commonMainImplementation", project(":core:designsystem")) add("commonMainImplementation", project(":core:data")) - add("commonMainImplementation", libs.findLibrary("jetbrains.compose.viewmodel").get()) - add("commonMainImplementation", libs.findLibrary("jetbrains.compose.navigation").get()) - add("commonMainImplementation", libs.findLibrary("kotlinx.collections.immutable").get()) - add("androidMainImplementation", project(":libs:material3-navigation")) + add("commonMainImplementation", libs.findLibrary("jb.composeRuntime").get()) + add("commonMainImplementation", libs.findLibrary("jb.composeViewmodel").get()) + add("commonMainImplementation", libs.findLibrary("jb.lifecycleViewmodel").get()) + add("commonMainImplementation", libs.findLibrary("jb.lifecycleViewmodelSavedState").get()) + add("commonMainImplementation", libs.findLibrary("jb.savedstate").get()) + add("commonMainImplementation", libs.findLibrary("jb.bundle").get()) + add("commonMainImplementation", libs.findLibrary("jb.composeNavigation").get()) + add("commonMainImplementation", libs.findLibrary("kotlinx.collections.immutable").get()) add("androidMainImplementation", libs.findLibrary("androidx.lifecycle.runtimeCompose").get()) add("androidMainImplementation", libs.findLibrary("androidx.lifecycle.viewModelCompose").get()) @@ -39,15 +43,9 @@ class CMPFeatureConventionPlugin : Plugin { add("androidTestImplementation", libs.findLibrary("koin.test.junit4").get()) - add("androidDebugImplementation", libs.findLibrary("androidx.compose.ui.test.manifest").get()) add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.navigation.testing").get()) add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.compose.ui.test").get()) add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.lifecycle.runtimeTesting").get()) - add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.core").get()) - add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.ext").get()) - add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.junit").get()) - add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.runner").get()) - add("androidInstrumentedTestImplementation", libs.findLibrary("androidx.test.espresso.core").get()) } } } diff --git a/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt index ca6cf9a78..f529f6e72 100644 --- a/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KMPKoinConventionPlugin.kt @@ -20,7 +20,7 @@ class KMPKoinConventionPlugin : Plugin { add("commonMainImplementation", libs.findLibrary("koin.annotations").get()) add("kspCommonMainMetadata", libs.findLibrary("koin.ksp.compiler").get()) - add("ksp", libs.findLibrary("koin.ksp.compiler").get()) +// add("kspAndroid", libs.findLibrary("koin.ksp.compiler").get()) // add("kspWasmJs", libs.findLibrary("koin.ksp.compiler").get()) // add("kspJvm", libs.findLibrary("koin.ksp.compiler").get()) // add("kspIosX64", libs.findLibrary("koin.ksp.compiler").get()) @@ -32,8 +32,6 @@ class KMPKoinConventionPlugin : Plugin { extensions.configure { arg("KOIN_CONFIG_CHECK","true") - arg("USE_COMPOSE_VIEWMODEL", "false") - arg("KOIN_USE_COMPOSE_VIEWMODEL", "true") } } } diff --git a/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt index 8f2e00185..23d0a8913 100644 --- a/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KMPLibraryConventionPlugin.kt @@ -28,7 +28,11 @@ class KMPLibraryConventionPlugin: Plugin { configureFlavors(this) // The resource prefix is derived from the module name, // so resources inside ":core:module1" must be prefixed with "core_module1_" - resourcePrefix = path.split("""\W""".toRegex()).drop(1).distinct().joinToString(separator = "_").lowercase() + "_" + resourcePrefix = path + .split("""\W""".toRegex()) + .drop(1).distinct() + .joinToString(separator = "_") + .lowercase() + "_" } dependencies { diff --git a/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt b/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt index cb89515b6..8d7583134 100644 --- a/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt +++ b/build-logic/convention/src/main/kotlin/KotlinInjectConventionPlugin.kt @@ -20,7 +20,7 @@ class KotlinInjectConventionPlugin: Plugin { add("kspIosSimulatorArm64", libs.findLibrary("kotlin.inject.compiler.ksp").get()) // add("kspWasmJs", libs.findLibrary("kotlin.inject.compiler.ksp").get()) add("kspAndroid", libs.findLibrary("kotlin.inject.compiler.ksp").get()) - add("kspJvm", libs.findLibrary("kotlin.inject.compiler.ksp").get()) + add("kspDesktop", libs.findLibrary("kotlin.inject.compiler.ksp").get()) } } } diff --git a/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt b/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt index 9d6ee74bf..755cc0009 100644 --- a/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt +++ b/build-logic/convention/src/main/kotlin/org/mifospay/KotlinMultiplatform.kt @@ -9,12 +9,19 @@ internal fun Project.configureKotlinMultiplatform() { extensions.configure { applyDefaultHierarchyTemplate() - jvm() + jvm("desktop") androidTarget() iosSimulatorArm64() iosX64() iosArm64() - + js(IR) { + this.nodejs() + binaries.executable() + } + wasmJs() { + browser() + nodejs() + } // Suppress 'expect'/'actual' classes are in Beta. targets.configureEach { compilations.configureEach { diff --git a/ci-prepush.bat b/ci-prepush.bat index 60ffba915..49298e3e7 100644 --- a/ci-prepush.bat +++ b/ci-prepush.bat @@ -12,11 +12,9 @@ echo Starting all checks and tests... call :run_gradle_task "check -p build-logic" call :run_gradle_task "spotlessApply --no-configuration-cache" call :run_gradle_task "dependencyGuardBaseline" -call :run_gradle_task "formatVersionCatalog" call :run_gradle_task "detekt" -call :run_gradle_task "testDemoDebug :lint:test :mifospay:lintProdRelease :lint:lint" -call :run_gradle_task "build" -call :run_gradle_task "updateProdReleaseBadging" +call :run_gradle_task ":mifospay-android:build" +call :run_gradle_task ":mifospay-android:updateProdReleaseBadging" echo All checks and tests completed successfully. exit /b 0 diff --git a/ci-prepush.sh b/ci-prepush.sh index 95cc04913..6689fd494 100644 --- a/ci-prepush.sh +++ b/ci-prepush.sh @@ -28,10 +28,8 @@ tasks=( "spotlessApply --no-configuration-cache" "dependencyGuardBaseline" "detekt" - "formatVersionCatalog" - "testDemoDebug :lint:test :lint:lint :mifospay:lintProdRelease" - "build" - "updateProdReleaseBadging" + ":mifospay-android:build" + ":mifospay-android:updateProdReleaseBadging" ) for task in "${tasks[@]}"; do diff --git a/core/common/build.gradle.kts b/core/common/build.gradle.kts index bc93c368a..58ae08079 100644 --- a/core/common/build.gradle.kts +++ b/core/common/build.gradle.kts @@ -9,6 +9,7 @@ */ plugins { alias(libs.plugins.mifospay.kmp.library) + alias(libs.plugins.kotlin.parcelize) } android { @@ -20,7 +21,7 @@ kotlin { listOf( iosX64(), iosArm64(), - iosSimulatorArm64() + iosSimulatorArm64(), ).forEach { it.binaries.framework { isStatic = false @@ -37,7 +38,9 @@ kotlin { api(libs.coil.network.ktor) api(libs.kermit.logging) api(libs.squareup.okio) + api(libs.jb.kotlin.stdlib) } + androidMain.dependencies { implementation(libs.kotlinx.coroutines.android) } @@ -47,5 +50,13 @@ kotlin { iosMain.dependencies { api(libs.kermit.simple) } + desktopMain.dependencies { + implementation(libs.kotlinx.coroutines.swing) + implementation(libs.kotlin.reflect) + } + jsMain.dependencies { + api(libs.jb.kotlin.stdlib.js) + api(libs.jb.kotlin.dom) + } } } \ No newline at end of file diff --git a/core/common/src/androidMain/kotlin/org/mifospay/core/common/Parcelize.kt b/core/common/src/androidMain/kotlin/org/mifospay/core/common/Parcelize.kt new file mode 100644 index 000000000..d76561bc8 --- /dev/null +++ b/core/common/src/androidMain/kotlin/org/mifospay/core/common/Parcelize.kt @@ -0,0 +1,29 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.common + +import android.os.Parcel +import android.os.Parcelable +import kotlinx.parcelize.IgnoredOnParcel +import kotlinx.parcelize.Parceler +import kotlinx.parcelize.Parcelize +import kotlinx.parcelize.TypeParceler + +actual typealias Parcelize = Parcelize + +actual typealias Parcelable = Parcelable + +actual typealias IgnoredOnParcel = IgnoredOnParcel + +actual typealias Parceler

= Parceler

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

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

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

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

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

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

= mutableListOf() - private val activationDate: String = DateHelper.formattedDate - val submittedOnDate: String = activationDate - val savingsProductId: Int = mifosSavingsProductId ?: 0 - val externalId: String = "$userName@mifos" - - init { - address.add( - Address( - addressLine1 = addressLine1, - addressLine2 = addressLine2, - street = city, - postalCode = postalCode, - stateProvinceId = stateProvinceId, - countryId = countryId, - ), - ) - } - - data class Address( - val addressLine1: String?, - val addressLine2: String?, - val street: String?, - val postalCode: String?, - val stateProvinceId: String?, - val countryId: String?, - ) - - data class CustomDataTable( - val registeredTableName: String = "client_info", - val data: HashMap = hashMapOf( - "locale" to "en", - "info_id" to 1, - ), + constructor( + firstname: String, + lastname: String, + externalId: String, + mobileNo: String, + address: Address, + savingsProductId: Int, + ) : this( + firstname = firstname, + lastname = lastname, + externalId = externalId, + mobileNo = mobileNo, + address = address, + savingsProductId = savingsProductId, + officeId = 1, + legalFormId = 1, + active = true, + dateFormat = DateHelper.SHORT_MONTH, + activationDate = DateHelper.formattedShortDate, + submittedOnDate = DateHelper.formattedShortDate, + locale = "en_US", ) } + +@Serializable +data class Address( + val addressLine1: String, + val addressLine2: String, + val postalCode: String, + val stateProvinceId: String, + val countryId: String, + val addressTypeId: Int = 805, +) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt index 72a2aee2a..fe550e20b 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/NewUser.kt @@ -9,21 +9,49 @@ */ package org.mifospay.core.model.domain.user +import kotlinx.serialization.Serializable + +// Mandatory Fields +// username, firstname, lastname, email, officeId, roles, sendPasswordToEmail +// +// Optional Fields +// staffId,passwordNeverExpires,isSelfServiceUser,clients + +@Serializable class NewUser( - val username: String?, - val firstname: String?, - val lastname: String?, - val email: String?, - val password: String?, + val username: String, + val firstname: String, + val lastname: String, + val email: String, + val password: String, + val officeId: Int, + val roles: ArrayList, + val sendPasswordToEmail: Boolean, + val isSelfServiceUser: Boolean, + val repeatPassword: String, ) { - val officeId = "1" - val roles: MutableList = NEW_USER_ROLE_IDS.toMutableList() - val sendPasswordToEmail = false - val isSelfServiceUser = true - val repeatPassword: String? = password + constructor( + username: String, + firstname: String, + lastname: String, + email: String, + password: String, + ) : this( + username = username, + firstname = firstname, + lastname = lastname, + email = email, + password = password, + officeId = OFFICE_ID, + roles = NEW_USER_ROLE_IDS, + sendPasswordToEmail = false, + isSelfServiceUser = true, + repeatPassword = password, + ) } -private const val MOBILE_WALLET_ROLE_ID = 471 +private const val OFFICE_ID = 1 +private const val MOBILE_WALLET_ROLE_ID = 2 private const val SUPER_USER_ROLE_ID = 1 -val NEW_USER_ROLE_IDS: Collection = listOf(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID) +val NEW_USER_ROLE_IDS: ArrayList = arrayListOf(MOBILE_WALLET_ROLE_ID, SUPER_USER_ROLE_ID) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt index c1de67fe0..0d45ba07c 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/domain/user/User.kt @@ -15,13 +15,13 @@ import org.mifospay.core.model.entity.Role @Serializable data class User( val username: String, - val userId: Long = 0, + val userId: Long, val base64EncodedAuthenticationKey: String, - val authenticated: Boolean = false, + val authenticated: Boolean, val officeId: Int, val officeName: String, - val roles: List, - val permissions: List, + val roles: List = emptyList(), + val permissions: List = emptyList(), val clients: List = emptyList(), val shouldRenewPassword: Boolean, val isTwoFactorAuthenticationRequired: Boolean, diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt index d69b2019f..4775b6f5e 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/entity/SearchedEntity.kt @@ -14,9 +14,9 @@ import kotlinx.serialization.Serializable @Serializable data class SearchedEntity( val entityId: Int = 0, - val entityAccountNo: String = " ", - val entityName: String = " ", - val entityType: String = " ", + val entityAccountNo: String = "", + val entityName: String = "", + val entityType: String = "", val parentId: Int = 0, - val parentName: String = " ", + val parentName: String = "", ) diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt index 981e3d6eb..819cdd41d 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt +++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/utils/DateHelper.kt @@ -25,8 +25,8 @@ import kotlin.time.Duration.Companion.days @OptIn(FormatStringsInDatetimeFormats::class) object DateHelper { private const val LOG_TAG = "DateHelper" - private const val FULL_MONTH = "dd MMM yyyy" - private const val SHORT_MONTH = "dd-MM-yyyy" + const val FULL_MONTH = "dd MM yyyy" + const val SHORT_MONTH = "dd-MM-yyyy" private val fullMonthFormat = LocalDateTime.Format { byUnicodePattern(FULL_MONTH) @@ -144,6 +144,7 @@ object DateHelper { return fullMonthFormat.parse(timeInMillis.toString()).toString() } - val currentDate = Clock.System.now().toEpochMilliseconds().toString() - val formattedDate = fullMonthFormat.parse(currentDate).toString() + val currentDate = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + val formattedFullDate = currentDate.format(fullMonthFormat) + val formattedShortDate = currentDate.format(shortMonthFormat) } diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts index 68ba5e7bb..9f836460f 100644 --- a/core/network/build.gradle.kts +++ b/core/network/build.gradle.kts @@ -19,7 +19,6 @@ */ plugins { alias(libs.plugins.mifospay.kmp.library) - alias(libs.plugins.mifospay.kotlin.inject) alias(libs.plugins.ktrofit) id("kotlinx-serialization") id("com.google.devtools.ksp") @@ -44,6 +43,7 @@ kotlin { api(libs.kotlinx.datetime) api(projects.core.common) api(projects.core.model) + implementation(projects.core.datastore) implementation(libs.kotlinx.serialization.json) implementation(libs.ktor.client.core) implementation(libs.ktor.client.json) @@ -51,28 +51,29 @@ kotlin { implementation(libs.ktor.client.serialization) implementation(libs.ktor.client.content.negotiation) implementation(libs.ktor.client.auth) - implementation(libs.ktor.client.cio) implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.ktorfit.lib) - implementation(libs.ktorfit.converters.call) - implementation(libs.ktorfit.converters.flow) implementation(libs.squareup.okio) } + androidMain.dependencies { - implementation(libs.ktor.client.android) + implementation(libs.ktor.client.okhttp) implementation(libs.koin.android) } - appleMain.dependencies { + nativeMain.dependencies { implementation(libs.ktor.client.darwin) } -// wasmJsMain.dependencies { -// implementation(libs.ktor.client.js) -// } - jvmMain.dependencies { - implementation(libs.ktor.client.java) + + val desktopMain by getting { + dependencies { + implementation(libs.ktor.client.okhttp) + } + } + jsMain.dependencies { + implementation(libs.ktor.client.js) } - mingwMain.dependencies { - implementation(libs.ktor.client.winhttp) + wasmJsMain.dependencies { + implementation(libs.ktor.client.js) } } } @@ -80,8 +81,9 @@ kotlin { dependencies { add("kspCommonMainMetadata", libs.ktorfit.ksp) add("kspAndroid", libs.ktorfit.ksp) -// add("kspWasmJs", libs.ktorfit.ksp) - add("kspJvm", libs.ktorfit.ksp) + add("kspJs", libs.ktorfit.ksp) + add("kspWasmJs", libs.ktorfit.ksp) + add("kspDesktop", libs.ktorfit.ksp) add("kspIosX64", libs.ktorfit.ksp) add("kspIosArm64", libs.ktorfit.ksp) add("kspIosSimulatorArm64", libs.ktorfit.ksp) diff --git a/core/network/src/androidMain/AndroidManifest.xml b/core/network/src/androidMain/AndroidManifest.xml index 961389810..31df960ef 100644 --- a/core/network/src/androidMain/AndroidManifest.xml +++ b/core/network/src/androidMain/AndroidManifest.xml @@ -9,5 +9,5 @@ See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md --> - + \ No newline at end of file diff --git a/core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorAndroidHttpClient.kt b/core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorAndroidHttpClient.kt new file mode 100644 index 000000000..efd65e12b --- /dev/null +++ b/core/network/src/androidMain/kotlin/org/mifospay/core/network/KtorAndroidHttpClient.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import io.ktor.client.HttpClient +import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json +import co.touchlab.kermit.Logger.Companion as KermitLogger + +actual val ktorHttpClient: HttpClient + get() = HttpClient(OkHttp) { + expectSuccess = true + + install(HttpTimeout) { + socketTimeoutMillis = 60_000 + requestTimeoutMillis = 60_000 + } + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + KermitLogger.d(tag = "KtorClient", messageString = message) + } + } + } + + install(ContentNegotiation) { + json( + Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + explicitNulls = false + }, + ) + } + } diff --git a/shared/src/iosMain/kotlin/org/mifospay/shared/di/Modules.ios.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorHttpClient.kt similarity index 69% rename from shared/src/iosMain/kotlin/org/mifospay/shared/di/Modules.ios.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorHttpClient.kt index e7cbc9318..a51b5ad54 100644 --- a/shared/src/iosMain/kotlin/org/mifospay/shared/di/Modules.ios.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorHttpClient.kt @@ -7,9 +7,8 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared.di +package org.mifospay.core.network -import org.koin.core.module.Module +import io.ktor.client.HttpClient -actual val platformModule: Module - get() = TODO("Not yet implemented") +expect val ktorHttpClient: HttpClient diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt index 86e5e5afa..120a55e25 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/KtorfitClient.kt @@ -10,39 +10,7 @@ package org.mifospay.core.network import de.jensklingenberg.ktorfit.Ktorfit -import de.jensklingenberg.ktorfit.converter.CallConverterFactory -import de.jensklingenberg.ktorfit.converter.FlowConverterFactory import io.ktor.client.HttpClient -import io.ktor.client.engine.cio.CIO -import io.ktor.client.plugins.DefaultRequest -import io.ktor.client.plugins.contentnegotiation.ContentNegotiation -import io.ktor.client.plugins.defaultRequest -import io.ktor.client.plugins.logging.DEFAULT -import io.ktor.client.plugins.logging.LogLevel -import io.ktor.client.plugins.logging.Logger -import io.ktor.client.plugins.logging.Logging -import io.ktor.http.ContentType -import io.ktor.http.contentType -import io.ktor.http.headers -import io.ktor.serialization.kotlinx.json.json -import kotlinx.serialization.json.Json -import org.mifospay.core.network.services.AccountTransfersService -import org.mifospay.core.network.services.AuthenticationService -import org.mifospay.core.network.services.BeneficiaryService -import org.mifospay.core.network.services.ClientService -import org.mifospay.core.network.services.DocumentService -import org.mifospay.core.network.services.InvoiceService -import org.mifospay.core.network.services.KYCLevel1Service -import org.mifospay.core.network.services.NotificationService -import org.mifospay.core.network.services.RegistrationService -import org.mifospay.core.network.services.RunReportService -import org.mifospay.core.network.services.SavedCardService -import org.mifospay.core.network.services.SavingsAccountsService -import org.mifospay.core.network.services.SearchService -import org.mifospay.core.network.services.StandingInstructionService -import org.mifospay.core.network.services.ThirdPartyTransferService -import org.mifospay.core.network.services.TwoFactorAuthService -import org.mifospay.core.network.services.UserService import org.mifospay.core.network.services.createAccountTransfersService import org.mifospay.core.network.services.createAuthenticationService import org.mifospay.core.network.services.createBeneficiaryService @@ -60,122 +28,67 @@ import org.mifospay.core.network.services.createStandingInstructionService import org.mifospay.core.network.services.createThirdPartyTransferService import org.mifospay.core.network.services.createTwoFactorAuthService import org.mifospay.core.network.services.createUserService +import org.mifospay.core.network.utils.FlowConverterFactory class KtorfitClient( - private val httpClient: HttpClient, - private val ktorfit: Ktorfit, + ktorfit: Ktorfit, ) { - internal val authenticationApi: AuthenticationService = ktorfit.createAuthenticationService() + internal val authenticationApi by lazy { ktorfit.createAuthenticationService() } - internal val clientsApi: ClientService = ktorfit.createClientService() + internal val clientsApi by lazy { ktorfit.createClientService() } - internal val registrationAPi: RegistrationService = ktorfit.createRegistrationService() + internal val registrationAPi by lazy { ktorfit.createRegistrationService() } - internal val searchApi: SearchService = ktorfit.createSearchService() + internal val searchApi by lazy { ktorfit.createSearchService() } - internal val documentApi: DocumentService = ktorfit.createDocumentService() + internal val documentApi by lazy { ktorfit.createDocumentService() } - internal val runReportApi: RunReportService = ktorfit.createRunReportService() + internal val runReportApi by lazy { ktorfit.createRunReportService() } - internal val twoFactorAuthApi: TwoFactorAuthService = ktorfit.createTwoFactorAuthService() + internal val twoFactorAuthApi by lazy { ktorfit.createTwoFactorAuthService() } - internal val accountTransfersApi: AccountTransfersService = - ktorfit.createAccountTransfersService() + internal val accountTransfersApi by lazy { ktorfit.createAccountTransfersService() } - internal val savedCardApi: SavedCardService = ktorfit.createSavedCardService() + internal val savedCardApi by lazy { ktorfit.createSavedCardService() } - internal val kycLevel1Api: KYCLevel1Service = ktorfit.createKYCLevel1Service() + internal val kycLevel1Api by lazy { ktorfit.createKYCLevel1Service() } - internal val invoiceApi: InvoiceService = ktorfit.createInvoiceService() + internal val invoiceApi by lazy { ktorfit.createInvoiceService() } - internal val userApi: UserService = ktorfit.createUserService() + internal val userApi by lazy { ktorfit.createUserService() } - internal val thirdPartyTransferApi: ThirdPartyTransferService = - ktorfit.createThirdPartyTransferService() + internal val thirdPartyTransferApi by lazy { ktorfit.createThirdPartyTransferService() } - internal val notificationApi: NotificationService = ktorfit.createNotificationService() + internal val notificationApi by lazy { ktorfit.createNotificationService() } - internal val savingsAccountsApi: SavingsAccountsService = ktorfit.createSavingsAccountsService() + internal val savingsAccountsApi by lazy { ktorfit.createSavingsAccountsService() } - internal val standingInstructionApi: StandingInstructionService = - ktorfit.createStandingInstructionService() + internal val standingInstructionApi by lazy { ktorfit.createStandingInstructionService() } - internal val beneficiaryApi: BeneficiaryService = ktorfit.createBeneficiaryService() + internal val beneficiaryApi by lazy { ktorfit.createBeneficiaryService() } class Builder internal constructor() { private lateinit var baseURL: String - private var tenant: String? = BaseURL.DEFAULT - private var loginUsername: String? = null - private var loginPassword: String? = null - private var insecure: Boolean = false - private var token: String? = null + private lateinit var httpClient: HttpClient fun baseURL(baseURL: String): Builder { this.baseURL = baseURL return this } - fun tenant(tenant: String?): Builder { - this.tenant = tenant - return this - } - - fun basicAuth(username: String?, password: String?): Builder { - this.loginUsername = username - this.loginPassword = password - return this - } - - fun inSecure(insecure: Boolean): Builder { - this.insecure = insecure - return this - } - - fun token(token: String?): Builder { - this.token = token + fun httpClient(ktorHttpClient: HttpClient): Builder { + this.httpClient = ktorHttpClient return this } fun build(): KtorfitClient { - val ktorClient = HttpClient(CIO) { - install(ContentNegotiation) { - json( - Json { - isLenient = true - ignoreUnknownKeys = true - }, - ) - } - - install(DefaultRequest) - - install(Logging) { - logger = Logger.DEFAULT - level = LogLevel.INFO - } - - defaultRequest { - contentType(ContentType.Application.Json) - headers { - append("Accept", "application/json") - tenant?.let { - append(BaseURL.HEADER_TENANT, it) - } - token?.let { - append(BaseURL.HEADER_AUTH, it) - } - } - } - } - val ktorfitBuilder = Ktorfit.Builder() - .httpClient(ktorClient) + .httpClient(httpClient) .baseUrl(baseURL) - .converterFactories(CallConverterFactory()) .converterFactories(FlowConverterFactory()) .build() - return KtorfitClient(ktorClient, ktorfitBuilder) + return KtorfitClient(ktorfitBuilder) } } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt index a40f51b42..f5ff5d5dc 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/NetworkModule.kt @@ -9,42 +9,73 @@ */ package org.mifospay.core.network.di -import kotlinx.serialization.json.Json +import io.ktor.client.HttpClient +import io.ktor.client.plugins.auth.Auth +import io.ktor.client.plugins.auth.providers.BasicAuthCredentials +import io.ktor.client.plugins.auth.providers.basic +import io.ktor.client.plugins.defaultRequest +import io.ktor.client.request.header import org.koin.dsl.module -import org.mifospay.core.network.BaseURL import org.mifospay.core.network.FineractApiManager import org.mifospay.core.network.KtorfitClient import org.mifospay.core.network.SelfServiceApiManager +import org.mifospay.core.network.ktorHttpClient +import org.mifospay.core.network.utils.BaseURL +import org.mifospay.core.network.utils.KtorInterceptor val NetworkModule = module { - single { - Json { - ignoreUnknownKeys = true + single(KtorClient) { + ktorHttpClient.config { + install(Auth) + install(KtorInterceptor) { + preferenceRepository = get() + } + } + } + + // TODO:: This could be removed, added for testing + single(KtorBaseClient) { + ktorHttpClient.config { + install(Auth) { + basic { + sendWithoutRequest { true } + credentials { + BasicAuthCredentials( + username = "mifos", + password = "password", + ) + } + } + } + + defaultRequest { + header("Fineract-Platform-TenantId", "default") + header("Content-Type", "application/json") + header("Accept", "application/json") + } } } single(BaseClient) { KtorfitClient.builder() + .httpClient(get(KtorBaseClient)) .baseURL(BaseURL.url) .build() } - single(SelfClient) { + single(SelfClient) { KtorfitClient.builder() + .httpClient(get(KtorClient)) .baseURL(BaseURL.selfServiceUrl) .build() } single { - FineractApiManager( - ktorfitClient = get(BaseClient), - ) + FineractApiManager(ktorfitClient = get(BaseClient)) } single { - SelfServiceApiManager( - ktorfitClient = get(SelfClient), - ) + SelfServiceApiManager(ktorfitClient = get(SelfClient)) } } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt index ce5bbce78..9e5dc7469 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/di/Qualifier.kt @@ -13,15 +13,5 @@ import org.koin.core.qualifier.named val SelfClient = named("SelfClient") val BaseClient = named("BaseClient") - -val FineractAuthenticationService = named("FineractAuthenticationService") -val FineractClientService = named("FineractClientService") -val FineractSavingsAccountsService = named("FineractSavingsAccountsService") -val FineractRegistrationService = named("FineractRegistrationService") -val FineractThirdPartyTransferService = named("FineractThirdPartyTransferService") - -val SelfServiceAuthenticationService = named("SelfServiceAuthenticationService") -val SelfServiceClientService = named("SelfServiceClientService") -val SelfServiceSavingsAccountsService = named("SelfServiceSavingsAccountsService") -val SelfServiceRegistrationService = named("SelfServiceRegistrationService") -val SelfServiceThirdPartyTransferService = named("SelfServiceThirdPartyTransferService") +val KtorClient = named("KtorClient") +val KtorBaseClient = named("KtorBaseClient") diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt index 858c886f0..feed1e7e6 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/JvmLocalAssetManager.kt @@ -9,14 +9,8 @@ */ package org.mifospay.core.network.localAssets -import okio.FileHandle -import okio.FileSystem -import okio.Path.Companion.toPath -import okio.SYSTEM - internal object JvmLocalAssetManager : LocalAssetManager { - override fun open(fileName: String): FileHandle { - val path = fileName.toPath() - return FileSystem.SYSTEM.openReadOnly(path) + override fun open(fileName: String): String { + return "" } } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt index 98f8b1138..3f519965b 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/LocalAssetManager.kt @@ -9,8 +9,6 @@ */ package org.mifospay.core.network.localAssets -import okio.FileHandle - fun interface LocalAssetManager { - fun open(fileName: String): FileHandle + fun open(fileName: String): String } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt index 78c4b9d60..417fc9810 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/localAssets/MifosLocalAssetDataSource.kt @@ -18,7 +18,6 @@ import org.mifospay.core.model.State class MifosLocalAssetDataSource( private val ioDispatcher: CoroutineDispatcher, private val networkJson: Json, - private val assets: LocalAssetManager, ) : LocalAssetDataSource { override suspend fun getCountries(): List { diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Role.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponse.kt similarity index 59% rename from shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Role.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponse.kt index 29bd13e8d..5fb91288a 100644 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Role.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/model/ClientResponse.kt @@ -7,11 +7,14 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared.modal.domain +package org.mifospay.core.network.model -data class Role( - var id: String? = null, - var name: String? = null, - var description: String? = null, - val disabled: Boolean, +import kotlinx.serialization.Serializable + +@Serializable +data class ClientResponse( + val officeId: Int, + val clientId: Int, + val resourceId: Int, + val savingsId: Int, ) diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt index 16c31ed4d..b5e7ae1ce 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AccountTransfersService.kt @@ -13,12 +13,12 @@ import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.accounts.savings.TransferDetail -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints /** * Created by ankur on 05/June/2018 */ interface AccountTransfersService { @GET(ApiEndPoints.ACCOUNT_TRANSFER + "/{transferId}") - fun getAccountTransfer(@Path("transferId") transferId: Long): Flow + suspend fun getAccountTransfer(@Path("transferId") transferId: Long): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt index 61daeae86..4c23736ef 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/AuthenticationService.kt @@ -11,12 +11,11 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.POST -import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.domain.user.User import org.mifospay.core.model.entity.authentication.AuthenticationPayload -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface AuthenticationService { @POST(ApiEndPoints.AUTHENTICATION) - fun authenticate(@Body authPayload: AuthenticationPayload): Flow + suspend fun authenticate(@Body authPayload: AuthenticationPayload): User } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt index f3baaabcf..c06628a2a 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/BeneficiaryService.kt @@ -20,25 +20,25 @@ import org.mifospay.core.model.entity.beneficary.Beneficiary import org.mifospay.core.model.entity.beneficary.BeneficiaryPayload import org.mifospay.core.model.entity.beneficary.BeneficiaryUpdatePayload import org.mifospay.core.model.entity.templates.beneficiary.BeneficiaryTemplate -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.CommonResponse +import org.mifospay.core.network.utils.ApiEndPoints interface BeneficiaryService { @GET(ApiEndPoints.BENEFICIARIES + "/tpt") - fun beneficiaryList(): Flow> + suspend fun beneficiaryList(): Flow> @GET(ApiEndPoints.BENEFICIARIES + "/tpt/template") - fun beneficiaryTemplate(): Flow + suspend fun beneficiaryTemplate(): Flow @POST(ApiEndPoints.BENEFICIARIES + "/tpt") - fun createBeneficiary(@Body beneficiaryPayload: BeneficiaryPayload): Flow + suspend fun createBeneficiary(@Body beneficiaryPayload: BeneficiaryPayload): Flow @PUT(ApiEndPoints.BENEFICIARIES + "/tpt/{beneficiaryId}") - fun updateBeneficiary( + suspend fun updateBeneficiary( @Path("beneficiaryId") beneficiaryId: Long, @Body payload: BeneficiaryUpdatePayload, ): Flow @DELETE(ApiEndPoints.BENEFICIARIES + "/tpt/{beneficiaryId}") - fun deleteBeneficiary(@Path("beneficiaryId") beneficiaryId: Long): Flow + suspend fun deleteBeneficiary(@Path("beneficiaryId") beneficiaryId: Long): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt index fc8dee419..f32e8b422 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ClientService.kt @@ -10,6 +10,7 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.Body +import de.jensklingenberg.ktorfit.http.DELETE import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Headers import de.jensklingenberg.ktorfit.http.POST @@ -21,40 +22,44 @@ import org.mifospay.core.model.domain.client.NewClient import org.mifospay.core.model.entity.Page import org.mifospay.core.model.entity.client.ClientAccounts import org.mifospay.core.model.entity.client.ClientEntity -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.model.ClientResponse +import org.mifospay.core.network.utils.ApiEndPoints interface ClientService { @GET(ApiEndPoints.CLIENTS) - fun clients(): Flow> + suspend fun clients(): Flow> @GET(ApiEndPoints.CLIENTS + "/{clientId}") - fun getClientForId(@Path("clientId") clientId: Long): Flow + suspend fun getClientForId(@Path("clientId") clientId: Long): ClientEntity @PUT(ApiEndPoints.CLIENTS + "/{clientId}") - fun updateClient( + suspend fun updateClient( @Path("clientId") clientId: Long, @Body payload: Any, ): Flow @GET(ApiEndPoints.CLIENTS + "/{clientId}/images") @Headers("Accept: text/plain") - fun getClientImage(@Path("clientId") clientId: Long): Flow + suspend fun getClientImage(@Path("clientId") clientId: Long): Flow @PUT(ApiEndPoints.CLIENTS + "/{clientId}/images") - fun updateClientImage( + suspend fun updateClientImage( @Path("clientId") clientId: Long, @Body typedFile: String?, ): Flow @GET(ApiEndPoints.CLIENTS + "/{clientId}/accounts") - fun getClientAccounts(@Path("clientId") clientId: Long): Flow + suspend fun getClientAccounts(@Path("clientId") clientId: Long): Flow @GET(ApiEndPoints.CLIENTS + "/{clientId}/accounts") - fun getAccounts( + suspend fun getAccounts( @Path("clientId") clientId: Long, @Query("fields") accountType: String, ): Flow @POST(ApiEndPoints.CLIENTS) - fun createClient(@Body newClient: NewClient): Flow + suspend fun createClient(@Body newClient: NewClient): ClientResponse + + @DELETE(ApiEndPoints.CLIENTS + "/{clientId}") + suspend fun deleteClient(@Path("clientId") clientId: Int): ClientResponse } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt index 43df8a93b..b605ad4e0 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/DocumentService.kt @@ -19,11 +19,11 @@ import de.jensklingenberg.ktorfit.http.Path import io.ktor.http.content.PartData import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.noncore.Document -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface DocumentService { @GET("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS) - fun getDocuments( + suspend fun getDocuments( @Path("entityType") entityType: String, @Path("entityId") entityId: Int, ): Flow> @@ -38,7 +38,7 @@ interface DocumentService { */ @POST("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS) @Multipart - fun createDocument( + suspend fun createDocument( @Path("entityType") entityType: String, @Path("entityId") entityId: Int, @Part("name") nameOfDocument: String, @@ -59,7 +59,7 @@ interface DocumentService { * @return ResponseBody */ @GET("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS + "/{documentId}/attachment") - fun downloadDocument( + suspend fun downloadDocument( @Path("entityType") entityType: String, @Path("entityId") entityId: Int, @Path("documentId") documentId: Int, @@ -77,7 +77,7 @@ interface DocumentService { * @param documentId - Document Id */ @DELETE("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS + "/{documentId}") - fun removeDocument( + suspend fun removeDocument( @Path("entityType") entityType: String, @Path("entityId") entityId: Int, @Path("documentId") documentId: Int, @@ -100,7 +100,7 @@ interface DocumentService { */ @PUT("{entityType}/{entityId}/" + ApiEndPoints.DOCUMENTS + "/{documentId}") @Multipart - fun updateDocument( + suspend fun updateDocument( @Path("entityType") entityType: String, @Path("entityId") entityId: Int, @Path("documentId") documentId: Int, diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt index 7052adb17..94ac56fff 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/InvoiceService.kt @@ -17,35 +17,35 @@ import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.Invoice -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints // TODO:: Fix this endpoints, there's no such endpoint for invoices interface InvoiceService { @GET(ApiEndPoints.DATATABLES + "/invoices/{clientId}") - fun getInvoices(@Path("clientId") clientId: Int): Flow> + suspend fun getInvoices(@Path("clientId") clientId: Int): Flow> @GET(ApiEndPoints.DATATABLES + "/invoices/{clientId}/{invoiceId}") - fun getInvoice( + suspend fun getInvoice( @Path("clientId") clientId: Int, @Path("invoiceId") invoiceId: Int, ): Flow @POST(ApiEndPoints.DATATABLES + "/invoices/{clientId}") - fun addInvoice( + suspend fun addInvoice( @Path("clientId") clientId: Int, @Body invoice: Invoice?, ): Unit @PUT(ApiEndPoints.DATATABLES + "/invoices/{clientId}/{invoiceId}") - fun updateInvoice( + suspend fun updateInvoice( @Path("clientId") clientId: Int, @Path("invoiceId") invoiceId: Int, @Body invoice: Invoice?, ): Flow @DELETE(ApiEndPoints.DATATABLES + "/invoices/{clientId}/{invoiceId}") - fun deleteInvoice( + suspend fun deleteInvoice( @Path("clientId") clientId: Int, @Path("invoiceId") invoiceId: Int, ): Flow diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt index 07e63bcb4..538863215 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/KYCLevel1Service.kt @@ -16,22 +16,22 @@ import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.kyc.KYCLevel1Details -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints interface KYCLevel1Service { @GET(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}") - fun fetchKYCLevel1Details(@Path("clientId") clientId: Int): Flow> + suspend fun fetchKYCLevel1Details(@Path("clientId") clientId: Int): Flow> @POST(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}") - fun addKYCLevel1Details( + suspend fun addKYCLevel1Details( @Path("clientId") clientId: Int, @Body kycLevel1Details: KYCLevel1Details, ): Flow @PUT(ApiEndPoints.DATATABLES + "/kyc_level1_details/{clientId}/") - fun updateKYCLevel1Details( + suspend fun updateKYCLevel1Details( @Path("clientId") clientId: Int, @Body kycLevel1Details: KYCLevel1Details, ): Flow diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt index 33c1dc603..a19c37df6 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/NotificationService.kt @@ -13,9 +13,9 @@ import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.domain.NotificationPayload -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface NotificationService { @GET(ApiEndPoints.DATATABLES + "/notifications/{clientId}") - fun fetchNotifications(@Path("clientId") clientId: Long): Flow> + suspend fun fetchNotifications(@Path("clientId") clientId: Long): Flow> } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt index d93401cf6..f93f575f4 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RegistrationService.kt @@ -13,12 +13,12 @@ import de.jensklingenberg.ktorfit.http.Body import de.jensklingenberg.ktorfit.http.POST import org.mifospay.core.model.entity.register.RegisterPayload import org.mifospay.core.model.entity.register.UserVerify -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface RegistrationService { @POST(ApiEndPoints.REGISTRATION) - fun registerUser(@Body registerPayload: RegisterPayload) + suspend fun registerUser(@Body registerPayload: RegisterPayload) @POST(ApiEndPoints.REGISTRATION + "/user") - fun verifyUser(@Body userVerify: UserVerify) + suspend fun verifyUser(@Body userVerify: UserVerify) } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt index c502d067f..b32f50fab 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/RunReportService.kt @@ -13,11 +13,11 @@ import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Query import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface RunReportService { @GET(ApiEndPoints.RUN_REPORT + "/Savings Transaction Receipt") - fun getTransactionReceipt( + suspend fun getTransactionReceipt( @Query("output-type") outputType: String, @Query("R_transactionId") transactionId: String, ): Flow diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt index dcf5e4a60..d513872d8 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavedCardService.kt @@ -17,27 +17,27 @@ import de.jensklingenberg.ktorfit.http.PUT import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.savedcards.Card -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints interface SavedCardService { @POST(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}") - fun addSavedCard( + suspend fun addSavedCard( @Path("clientId") clientId: Int, @Body card: Card, ): Flow @GET(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}") - fun getSavedCards(@Path("clientId") clientId: Int): Flow> + suspend fun getSavedCards(@Path("clientId") clientId: Int): Flow> @DELETE(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}/{cardId}") - fun deleteCard( + suspend fun deleteCard( @Path("clientId") clientId: Int, @Path("cardId") cardId: Int, ): Flow @PUT(ApiEndPoints.DATATABLES + "/saved_cards/{clientId}/{cardId}") - fun updateCard( + suspend fun updateCard( @Path("clientId") clientId: Int, @Path("cardId") cardId: Int, @Body card: Card, diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt index 7927c84cd..1a20ce280 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SavingsAccountsService.kt @@ -19,8 +19,8 @@ import org.mifospay.core.model.entity.Page import org.mifospay.core.model.entity.accounts.savings.SavingAccount import org.mifospay.core.model.entity.accounts.savings.SavingsWithAssociationsEntity import org.mifospay.core.model.entity.accounts.savings.TransactionsEntity -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints interface SavingsAccountsService { @GET(ApiEndPoints.SAVINGS_ACCOUNTS + "/{accountId}") diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt index c80edd09c..c075e395c 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/SearchService.kt @@ -11,9 +11,8 @@ package org.mifospay.core.network.services import de.jensklingenberg.ktorfit.http.GET import de.jensklingenberg.ktorfit.http.Query -import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.SearchedEntity -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface SearchService { @GET(ApiEndPoints.SEARCH) @@ -21,5 +20,5 @@ interface SearchService { @Query("query") query: String, @Query("resource") resources: String, @Query("exactMatch") exactMatch: Boolean, - ): Flow> + ): List } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt index 2fbd5cbe7..134d910a8 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/StandingInstructionService.kt @@ -20,13 +20,13 @@ import org.mifospay.core.model.entity.Page import org.mifospay.core.model.entity.payload.StandingInstructionPayload import org.mifospay.core.model.entity.standinginstruction.SDIResponse import org.mifospay.core.model.entity.standinginstruction.StandingInstruction -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints interface StandingInstructionService { @POST(ApiEndPoints.STANDING_INSTRUCTION) - fun createStandingInstruction( + suspend fun createStandingInstruction( @Body standingInstructionPayload: StandingInstructionPayload, ): Flow @@ -35,12 +35,12 @@ interface StandingInstructionService { * @param clientId - passed as Query to limit the response to client specific response */ @GET(ApiEndPoints.STANDING_INSTRUCTION) - fun getAllStandingInstructions( + suspend fun getAllStandingInstructions( @Query("clientId") clientId: Long, ): Flow> @GET("${ApiEndPoints.STANDING_INSTRUCTION}/{standingInstructionId}") - fun getStandingInstruction( + suspend fun getStandingInstruction( @Path("standingInstructionId") standingInstructionId: Long, ): Flow @@ -53,13 +53,13 @@ interface StandingInstructionService { * will be performed. */ @PUT("${ApiEndPoints.STANDING_INSTRUCTION}/{standingInstructionId}") - fun deleteStandingInstruction( + suspend fun deleteStandingInstruction( @Path("standingInstructionId") standingInstructionId: Long, @Query("command") command: String, ): Flow @PUT("${ApiEndPoints.STANDING_INSTRUCTION}/{standingInstructionId}") - fun updateStandingInstruction( + suspend fun updateStandingInstruction( @Path("standingInstructionId") standingInstructionId: Long, @Body standingInstructionPayload: StandingInstructionPayload, @Query("command") command: String, diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt index 601234d2d..0586c2393 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/ThirdPartyTransferService.kt @@ -16,12 +16,12 @@ import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.entity.TPTResponse import org.mifospay.core.model.entity.payload.TransferPayload import org.mifospay.core.model.entity.templates.account.AccountOptionsTemplate -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface ThirdPartyTransferService { @GET(ApiEndPoints.ACCOUNT_TRANSFER + "/template?type=tpt") - fun accountTransferTemplate(): Flow + suspend fun accountTransferTemplate(): Flow @POST(ApiEndPoints.ACCOUNT_TRANSFER + "?type=tpt") - fun makeTransfer(@Body transferPayload: TransferPayload): Flow + suspend fun makeTransfer(@Body transferPayload: TransferPayload): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt index c3defdb53..18b4f9a19 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/TwoFactorAuthService.kt @@ -15,15 +15,15 @@ import de.jensklingenberg.ktorfit.http.Query import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.domain.twofactor.AccessToken import org.mifospay.core.model.domain.twofactor.DeliveryMethod -import org.mifospay.core.network.ApiEndPoints +import org.mifospay.core.network.utils.ApiEndPoints interface TwoFactorAuthService { @GET(ApiEndPoints.TWOFACTOR) - fun deliveryMethods(): Flow> + suspend fun deliveryMethods(): Flow> @POST(ApiEndPoints.TWOFACTOR) - fun requestOTP(@Query("deliveryMethod") deliveryMethod: String): Flow + suspend fun requestOTP(@Query("deliveryMethod") deliveryMethod: String): Flow @POST(ApiEndPoints.TWOFACTOR + "/validate") - fun validateToken(@Query("token") token: String): Flow + suspend fun validateToken(@Query("token") token: String): Flow } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt index 2a6c585f7..2ec6be88e 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/services/UserService.kt @@ -18,28 +18,34 @@ import de.jensklingenberg.ktorfit.http.Path import kotlinx.coroutines.flow.Flow import org.mifospay.core.model.domain.user.NewUser import org.mifospay.core.model.entity.UserWithRole -import org.mifospay.core.network.ApiEndPoints import org.mifospay.core.network.model.CommonResponse import org.mifospay.core.network.model.GenericResponse +import org.mifospay.core.network.utils.ApiEndPoints interface UserService { @GET(ApiEndPoints.USER) - fun users(): Flow> + suspend fun users(): Flow> @POST(ApiEndPoints.USER) - fun createUser(@Body user: NewUser): Flow + suspend fun createUser(@Body user: NewUser): CommonResponse @PUT(ApiEndPoints.USER + "/{userId}") - fun updateUser( + suspend fun updateUser( @Path("userId") userId: Int, @Body updateUserEntity: NewUser, ): Flow @DELETE(ApiEndPoints.USER + "/{userId}") - fun deleteUser( + suspend fun deleteUser( @Path("userId") userId: Int, - ): Flow + ): CommonResponse @GET("self/userdetails") - fun getUser(): Flow + suspend fun getUser(): Flow + + @PUT(ApiEndPoints.USER + "/{userId}") + suspend fun assignClientToUser( + @Path("userId") userId: Int, + @Body clients: Map>, + ) } diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/ApiEndPoints.kt similarity index 92% rename from core/network/src/commonMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/ApiEndPoints.kt index eb4d9bee8..19d8424b2 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/ApiEndPoints.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/ApiEndPoints.kt @@ -7,11 +7,12 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.network +package org.mifospay.core.network.utils object ApiEndPoints { // This class contains all the Constants for API End Points const val AUTHENTICATION = "authentication" + const val AUTHENTICATION_OAUTH = "oauth/token" const val REGISTRATION = "registration" const val CLIENTS = "clients" const val SAVINGS_ACCOUNTS = "savingsaccounts" diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/BaseURL.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/BaseURL.kt similarity index 96% rename from core/network/src/commonMain/kotlin/org/mifospay/core/network/BaseURL.kt rename to core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/BaseURL.kt index ed472d2e0..c274d11c3 100644 --- a/core/network/src/commonMain/kotlin/org/mifospay/core/network/BaseURL.kt +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/BaseURL.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.network +package org.mifospay.core.network.utils object BaseURL { private const val PROTOCOL_HTTPS = "https://" diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/FlowConverterFactory.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/FlowConverterFactory.kt new file mode 100644 index 000000000..4943f05ef --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/FlowConverterFactory.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.utils + +import de.jensklingenberg.ktorfit.Ktorfit +import de.jensklingenberg.ktorfit.converter.Converter +import de.jensklingenberg.ktorfit.converter.KtorfitResult +import de.jensklingenberg.ktorfit.converter.TypeData +import io.ktor.client.call.body +import io.ktor.client.statement.HttpResponse +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flow + +/** + * Factory that enables the use of Flow as return type + */ +public class FlowConverterFactory : Converter.Factory { + override fun responseConverter( + typeData: TypeData, + ktorfit: Ktorfit, + ): Converter.ResponseConverter? { + if (typeData.typeInfo.type == Flow::class) { + return object : Converter.ResponseConverter> { + override fun convert(getResponse: suspend () -> HttpResponse): Flow { + val requestType = typeData.typeArgs.first() + return flow { + val response = getResponse() + if (requestType.typeInfo.type == HttpResponse::class) { + emit(response) + } else { + val convertedBody = + ktorfit.nextSuspendResponseConverter( + this@FlowConverterFactory, + typeData.typeArgs.first(), + )?.convert(KtorfitResult.Success(response)) + ?: response.body(typeData.typeArgs.first().typeInfo) + emit(convertedBody) + } + } + } + } + } + return null + } +} diff --git a/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt new file mode 100644 index 000000000..89fae835a --- /dev/null +++ b/core/network/src/commonMain/kotlin/org/mifospay/core/network/utils/KtorInterceptor.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network.utils + +import io.ktor.client.HttpClient +import io.ktor.client.plugins.HttpClientPlugin +import io.ktor.client.request.HttpRequestPipeline +import io.ktor.client.request.header +import io.ktor.util.AttributeKey +import org.mifospay.core.datastore.UserPreferencesRepository + +class KtorInterceptor( + private val repository: UserPreferencesRepository, +) { + companion object Plugin : HttpClientPlugin { + private const val HEADER_TENANT = "Fineract-Platform-TenantId" + private const val HEADER_AUTH = "Authorization" + private const val DEFAULT = "venus" + + override val key: AttributeKey = AttributeKey("KtorInterceptor") + + override fun install(plugin: KtorInterceptor, scope: HttpClient) { + val authToken = plugin.repository.token.value + + scope.requestPipeline.intercept(HttpRequestPipeline.State) { + context.header("Content-Type", "application/json") + context.header("Accept", "application/json") + context.header(HEADER_TENANT, DEFAULT) + if (!authToken.isNullOrEmpty()) { + context.header(HEADER_AUTH, "Basic $authToken") + } + } + } + + override fun prepare(block: Config.() -> Unit): KtorInterceptor { + val config = Config().apply(block) + return KtorInterceptor(config.preferenceRepository!!) + } + } +} + +class Config( + var preferenceRepository: UserPreferencesRepository? = null, +) diff --git a/core/network/src/desktopMain/kotlin/org/mifospay/core/network/KtorJvmHttpClient.kt b/core/network/src/desktopMain/kotlin/org/mifospay/core/network/KtorJvmHttpClient.kt new file mode 100644 index 000000000..981faa77e --- /dev/null +++ b/core/network/src/desktopMain/kotlin/org/mifospay/core/network/KtorJvmHttpClient.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import io.ktor.client.HttpClient +import io.ktor.client.engine.okhttp.OkHttp +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json + +actual val ktorHttpClient: HttpClient + get() = HttpClient(OkHttp) { + expectSuccess = true + + install(HttpTimeout) { + socketTimeoutMillis = 60_000 + requestTimeoutMillis = 60_000 + } + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + co.touchlab.kermit.Logger.d(tag = "KtorClient", messageString = message) + } + } + } + + install(ContentNegotiation) { + json( + Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + explicitNulls = false + }, + ) + } + } diff --git a/core/network/src/jsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt b/core/network/src/jsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt new file mode 100644 index 000000000..f62b94c43 --- /dev/null +++ b/core/network/src/jsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import io.ktor.client.HttpClient +import io.ktor.client.engine.js.Js +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json + +actual val ktorHttpClient: HttpClient + get() = HttpClient(Js) { + expectSuccess = true + + install(HttpTimeout) { + socketTimeoutMillis = 60_000 + requestTimeoutMillis = 60_000 + } + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + co.touchlab.kermit.Logger.d(tag = "KtorClient", messageString = message) + } + } + } + + install(ContentNegotiation) { + json( + Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + explicitNulls = false + }, + ) + } + } diff --git a/core/network/src/nativeMain/kotlin/org/mifospay/core/network/KtorNativeHttpClient.kt b/core/network/src/nativeMain/kotlin/org/mifospay/core/network/KtorNativeHttpClient.kt new file mode 100644 index 000000000..7209585ce --- /dev/null +++ b/core/network/src/nativeMain/kotlin/org/mifospay/core/network/KtorNativeHttpClient.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import io.ktor.client.HttpClient +import io.ktor.client.engine.darwin.Darwin +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json + +actual val ktorHttpClient: HttpClient + get() = HttpClient(Darwin) { + expectSuccess = true + + install(HttpTimeout) { + socketTimeoutMillis = 60_000 + requestTimeoutMillis = 60_000 + } + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + co.touchlab.kermit.Logger.d(tag = "KtorClient", messageString = message) + } + } + } + + install(ContentNegotiation) { + json( + Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + explicitNulls = false + }, + ) + } + } diff --git a/core/network/src/wasmJsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt b/core/network/src/wasmJsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt new file mode 100644 index 000000000..f62b94c43 --- /dev/null +++ b/core/network/src/wasmJsMain/kotlin/org/mifospay/core/network/KtorJsHttpClient.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.network + +import io.ktor.client.HttpClient +import io.ktor.client.engine.js.Js +import io.ktor.client.plugins.HttpTimeout +import io.ktor.client.plugins.contentnegotiation.ContentNegotiation +import io.ktor.client.plugins.logging.DEFAULT +import io.ktor.client.plugins.logging.LogLevel +import io.ktor.client.plugins.logging.Logger +import io.ktor.client.plugins.logging.Logging +import io.ktor.serialization.kotlinx.json.json +import kotlinx.serialization.json.Json + +actual val ktorHttpClient: HttpClient + get() = HttpClient(Js) { + expectSuccess = true + + install(HttpTimeout) { + socketTimeoutMillis = 60_000 + requestTimeoutMillis = 60_000 + } + + install(Logging) { + logger = Logger.DEFAULT + level = LogLevel.ALL + logger = object : Logger { + override fun log(message: String) { + co.touchlab.kermit.Logger.d(tag = "KtorClient", messageString = message) + } + } + } + + install(ContentNegotiation) { + json( + Json { + prettyPrint = true + isLenient = true + ignoreUnknownKeys = true + explicitNulls = false + }, + ) + } + } diff --git a/core/ui/build.gradle.kts b/core/ui/build.gradle.kts index ae180d6af..0bb0546c4 100644 --- a/core/ui/build.gradle.kts +++ b/core/ui/build.gradle.kts @@ -30,6 +30,9 @@ kotlin { api(projects.core.designsystem) api(projects.core.model) api(projects.core.common) + implementation(libs.jb.composeViewmodel) + implementation(libs.jb.lifecycleViewmodel) + implementation(libs.jb.lifecycleViewmodelSavedState) implementation(libs.coil.kt) implementation(libs.coil.kt.compose) implementation(compose.material3) diff --git a/mifospay/src/main/res/drawable/mifospay_round_logo.png b/core/ui/src/commonMain/composeResources/drawable/feature_receipt_mifospay_round_logo.png similarity index 100% rename from mifospay/src/main/res/drawable/mifospay_round_logo.png rename to core/ui/src/commonMain/composeResources/drawable/feature_receipt_mifospay_round_logo.png diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/MifosPasswordField.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/MifosPasswordField.kt new file mode 100644 index 000000000..fbbcb3f00 --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/MifosPasswordField.kt @@ -0,0 +1,189 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui + +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.OutlinedTextField +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTag +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.designsystem.utils.tabNavigation + +@Composable +fun MifosPasswordField( + label: String, + value: String, + showPassword: Boolean, + showPasswordChange: (Boolean) -> Unit, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + readOnly: Boolean = false, + singleLine: Boolean = true, + hint: String? = null, + showPasswordTestTag: String? = null, + autoFocus: Boolean = false, + keyboardType: KeyboardType = KeyboardType.Password, + imeAction: ImeAction = ImeAction.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, +) { + val focusRequester = remember { FocusRequester() } + OutlinedTextField( + modifier = modifier + .tabNavigation() + .focusRequester(focusRequester), + label = { Text(text = label) }, + value = value, + onValueChange = onValueChange, + visualTransformation = when { + !showPassword -> PasswordVisualTransformation() + readOnly -> nonLetterColorVisualTransformation() + else -> VisualTransformation.None + }, + singleLine = singleLine, + readOnly = readOnly, + keyboardOptions = KeyboardOptions( + keyboardType = keyboardType, + imeAction = imeAction, + ), + keyboardActions = keyboardActions, + supportingText = hint?.let { + { + Text( + text = hint, + style = MaterialTheme.typography.bodySmall, + ) + } + }, + trailingIcon = { + IconButton( + onClick = { showPasswordChange.invoke(!showPassword) }, + ) { + val imageVector = if (showPassword) { + MifosIcons.VisibilityOff + } else { + MifosIcons.Visibility + } + + Icon( + modifier = Modifier.semantics { showPasswordTestTag?.let { testTag = it } }, + imageVector = imageVector, + contentDescription = "togglePassword", + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + }, + ) + if (autoFocus) { + LaunchedEffect(Unit) { focusRequester.requestFocus() } + } +} + +@Composable +fun MifosPasswordField( + label: String, + value: String, + onValueChange: (String) -> Unit, + modifier: Modifier = Modifier, + readOnly: Boolean = false, + singleLine: Boolean = true, + hint: String? = null, + initialShowPassword: Boolean = false, + showPasswordTestTag: String? = null, + autoFocus: Boolean = false, + keyboardType: KeyboardType = KeyboardType.Password, + imeAction: ImeAction = ImeAction.Default, + keyboardActions: KeyboardActions = KeyboardActions.Default, +) { + var showPassword by rememberSaveable { mutableStateOf(initialShowPassword) } + MifosPasswordField( + modifier = modifier, + label = label, + value = value, + showPassword = showPassword, + showPasswordChange = { showPassword = !showPassword }, + onValueChange = onValueChange, + readOnly = readOnly, + singleLine = singleLine, + hint = hint, + showPasswordTestTag = showPasswordTestTag, + autoFocus = autoFocus, + keyboardType = keyboardType, + imeAction = imeAction, + keyboardActions = keyboardActions, + ) +} + +@Preview +@Composable +private fun MifosPasswordField_preview_withInput_hidePassword() { + MifosPasswordField( + label = "Label", + value = "Password", + onValueChange = {}, + initialShowPassword = false, + hint = "Hint", + ) +} + +@Preview +@Composable +private fun MifosPasswordField_preview_withInput_showPassword() { + MifosPasswordField( + label = "Label", + value = "Password", + onValueChange = {}, + initialShowPassword = true, + hint = "Hint", + ) +} + +@Preview +@Composable +private fun MifosPasswordField_preview_withoutInput_hidePassword() { + MifosPasswordField( + label = "Label", + value = "", + onValueChange = {}, + initialShowPassword = false, + hint = "Hint", + ) +} + +@Preview +@Composable +private fun MifosPasswordField_preview_withoutInput_showPassword() { + MifosPasswordField( + label = "Label", + value = "", + onValueChange = {}, + initialShowPassword = true, + hint = "Hint", + ) +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/NonLetterColorVisualTransformation.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/NonLetterColorVisualTransformation.kt new file mode 100644 index 000000000..d7051993d --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/NonLetterColorVisualTransformation.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui + +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.input.OffsetMapping +import androidx.compose.ui.text.input.TransformedText +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.withStyle + +@Composable +fun nonLetterColorVisualTransformation(): VisualTransformation { + val digitColor = MaterialTheme.colorScheme.primary + val specialCharacterColor = MaterialTheme.colorScheme.error + return remember(digitColor, specialCharacterColor) { + NonLetterColorVisualTransformation( + digitColor = digitColor, + specialCharacterColor = specialCharacterColor, + ) + } +} + +private class NonLetterColorVisualTransformation( + private val digitColor: Color, + private val specialCharacterColor: Color, +) : VisualTransformation { + + override fun filter(text: AnnotatedString): TransformedText = + TransformedText( + buildTransformedAnnotatedString(text.toString()), + OffsetMapping.Identity, + ) + + private fun buildTransformedAnnotatedString(text: String): AnnotatedString { + val builder = AnnotatedString.Builder() + text.toCharArray().forEach { char -> + when { + char.isDigit() -> builder.withStyle(SpanStyle(color = digitColor)) { append(char) } + + !char.isLetter() -> { + builder.withStyle(SpanStyle(color = specialCharacterColor)) { append(char) } + } + + else -> builder.append(char) + } + } + return builder.toAnnotatedString() + } +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BackgroundEvent.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BackgroundEvent.kt new file mode 100644 index 000000000..0e6459add --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BackgroundEvent.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +/** + * Almost all the events in the app involve navigation or toasts. To prevent accidentally + * navigating to the same view twice, by default, events are ignored if the view is not currently + * resumed. To avoid that restriction, specific events can implement [BackgroundEvent]. + */ +interface BackgroundEvent diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BaseViewModel.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BaseViewModel.kt new file mode 100644 index 000000000..b955bf226 --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/BaseViewModel.kt @@ -0,0 +1,100 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.SendChannel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.consumeAsFlow +import kotlinx.coroutines.flow.receiveAsFlow +import kotlinx.coroutines.launch + +/** + * A base [ViewModel] that helps enforce the unidirectional data flow pattern and associated + * responsibilities of a typical ViewModel: + * + * - Maintaining and emitting a current state (of type [S]) with the given `initialState`. + * - Emitting one-shot events as needed (of type [E]). These should be rare and are typically + * reserved for things such as non-state based navigation. + * - Receiving actions (of type [A]) that may induce changes in the current state, trigger an + * event emission, or both. + */ +abstract class BaseViewModel( + initialState: S, +) : ViewModel() { + protected val mutableStateFlow: MutableStateFlow = MutableStateFlow(initialState) + private val eventChannel: Channel = Channel(capacity = Channel.UNLIMITED) + private val internalActionChannel: Channel = Channel(capacity = Channel.UNLIMITED) + + /** + * A helper that returns the current state of the view model. + */ + protected val state: S get() = mutableStateFlow.value + + /** + * A [StateFlow] representing state updates. + */ + val stateFlow: StateFlow = mutableStateFlow.asStateFlow() + + /** + * A [Flow] of one-shot events. These may be received and consumed by only a single consumer. + * Any additional consumers will receive no events. + */ + val eventFlow: Flow = eventChannel.receiveAsFlow() + + /** + * A [SendChannel] for sending actions to the ViewModel for processing. + */ + val actionChannel: SendChannel = internalActionChannel + + init { + viewModelScope.launch { + internalActionChannel + .consumeAsFlow() + .collect { action -> + handleAction(action) + } + } + } + + /** + * Handles the given [action] in a synchronous manner. + * + * Any changes to internal state that first require asynchronous work should post a follow-up + * action that may be used to then update the state synchronously. + */ + protected abstract fun handleAction(action: A): Unit + + /** + * Convenience method for sending an action to the [actionChannel]. + */ + fun trySendAction(action: A) { + actionChannel.trySend(action) + } + + /** + * Helper method for sending an internal action. + */ + protected suspend fun sendAction(action: A) { + actionChannel.send(action) + } + + /** + * Helper method for sending an event. + */ + protected fun sendEvent(event: E) { + viewModelScope.launch { eventChannel.send(event) } + } +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/EventsEffect.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/EventsEffect.kt new file mode 100644 index 000000000..b10cfdd8c --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/EventsEffect.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +/** + * Convenience method for observing event flow from [BaseViewModel]. + * + * By default, events will only be consumed when the associated screen is + * resumed, to avoid bugs like duplicate navigation calls. To override + * this behavior, a given event type can implement [BackgroundEvent]. + */ +@Composable +fun EventsEffect( + viewModel: BaseViewModel<*, E, *>, + lifecycleOwner: Lifecycle = LocalLifecycleOwner.current.lifecycle, + handler: suspend (E) -> Unit, +) { + LaunchedEffect(key1 = Unit) { + viewModel.eventFlow + .filter { + it is BackgroundEvent || + lifecycleOwner.currentState.isAtLeast(Lifecycle.State.RESUMED) + } + .onEach { handler.invoke(it) } + .launchIn(this) + } +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/LifecycleEventEffect.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/LifecycleEventEffect.kt new file mode 100644 index 000000000..98e75cf87 --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/LifecycleEventEffect.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect +import androidx.compose.runtime.rememberUpdatedState +import androidx.compose.ui.platform.LocalLifecycleOwner +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner + +/** + * Creates a side effect to observe lifecycle events. + */ +@Composable +fun LivecycleEventEffect( + onEvent: (owner: LifecycleOwner, event: Lifecycle.Event) -> Unit, +) { + val eventHandler = rememberUpdatedState(onEvent) + val lifecycleOwner = rememberUpdatedState(LocalLifecycleOwner.current) + + DisposableEffect(lifecycleOwner.value) { + val lifecycle = lifecycleOwner.value.lifecycle + val observer = LifecycleEventObserver { owner, event -> + eventHandler.value(owner, event) + } + + lifecycle.addObserver(observer) + onDispose { + lifecycle.removeObserver(observer) + } + } +} diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordChecker.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordChecker.kt new file mode 100644 index 000000000..8b7f5bb94 --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordChecker.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +import kotlin.math.log2 +import kotlin.math.pow + +object PasswordChecker { + private const val MIN_PASSWORD_LENGTH = 8 + private const val STRONG_PASSWORD_LENGTH = 12 + private const val MIN_ENTROPY_BITS = 60.0 + private const val MAX_PASSWORD_LENGTH = 128 + + fun getPasswordStrengthResult(password: String): PasswordStrengthResult { + when { + password.isEmpty() -> return PasswordStrengthResult.Error("Password cannot be empty.") + password.length > MAX_PASSWORD_LENGTH -> { + return PasswordStrengthResult.Error( + "Password is too long. Maximum length is $MAX_PASSWORD_LENGTH characters.", + ) + } + } + + val result = getPasswordStrength(password) + + return PasswordStrengthResult.Success(result) + } + + fun getPasswordStrength(password: String): PasswordStrength { + val length = password.length + val hasUpperCase = password.any { it.isUpperCase() } + val hasLowerCase = password.any { it.isLowerCase() } + val hasNumbers = password.any { it.isDigit() } + val hasSymbols = password.any { !it.isLetterOrDigit() } + + val numTypesPresent = + listOf(hasUpperCase, hasLowerCase, hasNumbers, hasSymbols).count { it } + val entropyBits = calculateEntropy(password) + + return when { + length < MIN_PASSWORD_LENGTH -> PasswordStrength.LEVEL_0 + numTypesPresent == 1 -> PasswordStrength.LEVEL_1 + numTypesPresent == 2 -> PasswordStrength.LEVEL_2 + numTypesPresent == 3 && length >= STRONG_PASSWORD_LENGTH -> PasswordStrength.LEVEL_4 + numTypesPresent == 4 && length >= STRONG_PASSWORD_LENGTH && + entropyBits >= MIN_ENTROPY_BITS -> PasswordStrength.LEVEL_5 + + else -> PasswordStrength.LEVEL_3 + } + } + + private fun calculateEntropy(password: String): Double { + val charPool = 26 + 26 + 10 + 33 // lowercase + uppercase + digits + symbols + return log2(charPool.toDouble().pow(password.length)) + } + + fun getPasswordFeedback(password: String): List { + val feedback = mutableListOf() + + if (password.length < MIN_PASSWORD_LENGTH) { + feedback.add("Password should be at least $MIN_PASSWORD_LENGTH characters long.") + } + if (!password.any { it.isUpperCase() }) { + feedback.add("Include at least one uppercase letter.") + } + if (!password.any { it.isLowerCase() }) { + feedback.add("Include at least one lowercase letter.") + } + if (!password.any { it.isDigit() }) { + feedback.add("Include at least one number.") + } + if (!password.any { !it.isLetterOrDigit() }) { + feedback.add("Include at least one special character.") + } + if (password.length < STRONG_PASSWORD_LENGTH) { + feedback.add("For a stronger password, use at least $STRONG_PASSWORD_LENGTH characters.") + } + + return feedback + } +} + +sealed class PasswordStrengthResult { + data class Success(val passwordStrength: PasswordStrength) : PasswordStrengthResult() + + data class Error(val message: String) : PasswordStrengthResult() +} diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/PasswordStrength.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrength.kt similarity index 74% rename from core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/PasswordStrength.kt rename to core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrength.kt index b8c6ebd33..033554673 100644 --- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/signup/PasswordStrength.kt +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrength.kt @@ -7,13 +7,13 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.core.model.signup +package org.mifospay.core.ui.utils enum class PasswordStrength { - WEAK, - MODERATE, - STRONG, - VERY_STRONG, - EXCELLENT, - INVALID, + LEVEL_0, + LEVEL_1, + LEVEL_2, + LEVEL_3, + LEVEL_4, + LEVEL_5, } diff --git a/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrengthExtensions.kt b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrengthExtensions.kt new file mode 100644 index 000000000..eecae452d --- /dev/null +++ b/core/ui/src/commonMain/kotlin/org/mifospay/core/ui/utils/PasswordStrengthExtensions.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.core.ui.utils + +/** + * Converts the given [Int] to a [PasswordStrength]. A `null` value is returned if this value is + * not in the [0, 4] range. + */ +@Suppress("MagicNumber") +fun Int.toPasswordStrengthOrNull(): PasswordStrength? = + when (this) { + 0 -> PasswordStrength.LEVEL_0 + 1 -> PasswordStrength.LEVEL_1 + 2 -> PasswordStrength.LEVEL_2 + 3 -> PasswordStrength.LEVEL_3 + 4 -> PasswordStrength.LEVEL_4 + 5 -> PasswordStrength.LEVEL_5 + else -> null + } + +/** + * Converts the given [PasswordStrength] to an [Int]. + */ +@Suppress("MagicNumber") +fun PasswordStrength.toInt(): Int = + when (this) { + PasswordStrength.LEVEL_0 -> 0 + PasswordStrength.LEVEL_1 -> 1 + PasswordStrength.LEVEL_2 -> 2 + PasswordStrength.LEVEL_3 -> 3 + PasswordStrength.LEVEL_4 -> 4 + PasswordStrength.LEVEL_5 -> 5 + } diff --git a/feature/auth/build.gradle.kts b/feature/auth/build.gradle.kts index ae4c6d07b..2eb49adfd 100644 --- a/feature/auth/build.gradle.kts +++ b/feature/auth/build.gradle.kts @@ -8,8 +8,9 @@ * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifospay.android.feature) - alias(libs.plugins.mifospay.android.library.compose) + alias(libs.plugins.mifospay.cmp.feature) + alias(libs.plugins.kotlin.parcelize) + alias(libs.plugins.kotlin.serialization) } android { @@ -19,15 +20,32 @@ android { } } -dependencies { - implementation(projects.libs.countryCodePicker) +kotlin { + sourceSets { + commonMain.dependencies { + implementation(projects.core.domain) + implementation(compose.material3) + implementation(compose.foundation) + implementation(compose.ui) + implementation(compose.components.resources) + implementation(compose.components.uiToolingPreview) + implementation(libs.koin.compose.viewmodel) + implementation(libs.koin.compose) + implementation(libs.jb.kotlin.stdlib) + implementation(libs.kotlin.reflect) + } - // Credentials Manager - implementation(libs.androidx.credentials) - // optional - needed for credentials support from play services, for devices running - // Android 13 and below. - implementation(libs.androidx.credentials.play.services.auth) - implementation(libs.googleid) + androidMain.dependencies { + implementation(projects.libs.countryCodePicker) - implementation(libs.play.services.auth) + // Credentials Manager + implementation(libs.androidx.credentials) + // optional - needed for credentials support from play services, for devices running + // Android 13 and below. + implementation(libs.androidx.credentials.play.services.auth) + implementation(libs.googleid) + + implementation(libs.play.services.auth) + } + } } \ No newline at end of file diff --git a/feature/auth/src/main/AndroidManifest.xml b/feature/auth/src/androidMain/AndroidManifest.xml similarity index 100% rename from feature/auth/src/main/AndroidManifest.xml rename to feature/auth/src/androidMain/AndroidManifest.xml diff --git a/feature/auth/src/main/res/values/strings.xml b/feature/auth/src/commonMain/composeResources/values/strings.xml similarity index 91% rename from feature/auth/src/main/res/values/strings.xml rename to feature/auth/src/commonMain/composeResources/values/strings.xml index 13745ed1c..acc1b6be0 100644 --- a/feature/auth/src/main/res/values/strings.xml +++ b/feature/auth/src/commonMain/composeResources/values/strings.xml @@ -20,7 +20,7 @@ Sign up as merchant Sign up as customer or - Ease my sign up using Google Account + Ease my sign up using Google Account Please enter a valid email address All fields are mandatory. Complete your registration @@ -33,6 +33,8 @@ Address Line 2 Pin Code State + Country + Mobile No Complete Please waitā€¦ Mandatory field @@ -46,7 +48,7 @@ It should be currently activated on your device and linked with your bank account as well. - Enter otp received on your registered device + Enter otp received on your registered device Verify Phone Verify Otp Phone Number diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/di/AuthModule.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/di/AuthModule.kt new file mode 100644 index 000000000..126684fd3 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/di/AuthModule.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.di + +import org.koin.core.module.dsl.viewModelOf +import org.koin.dsl.module +import org.mifospay.feature.auth.login.LoginViewModel +import org.mifospay.feature.auth.mobileVerify.MobileVerificationViewModel +import org.mifospay.feature.auth.signup.SignupViewModel + +val AuthModule = module { + viewModelOf(::LoginViewModel) + viewModelOf(::SignupViewModel) + viewModelOf(::MobileVerificationViewModel) +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt new file mode 100644 index 000000000..0f673bb5a --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt @@ -0,0 +1,252 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.login + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.SnackbarHost +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.text.input.PasswordVisualTransformation +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.style.TextDecoration +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch +import mobile_wallet.feature.auth.generated.resources.Res +import mobile_wallet.feature.auth.generated.resources.feature_auth_login +import mobile_wallet.feature.auth.generated.resources.feature_auth_password +import mobile_wallet.feature.auth.generated.resources.feature_auth_sign_up +import mobile_wallet.feature.auth.generated.resources.feature_auth_username +import mobile_wallet.feature.auth.generated.resources.feature_auth_welcome_back +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.koin.compose.viewmodel.koinViewModel +import org.mifospay.core.designsystem.component.BasicDialogState +import org.mifospay.core.designsystem.component.LoadingDialogState +import org.mifospay.core.designsystem.component.MifosBasicDialog +import org.mifospay.core.designsystem.component.MifosButton +import org.mifospay.core.designsystem.component.MifosLoadingDialog +import org.mifospay.core.designsystem.component.MifosOutlinedTextField +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.designsystem.theme.MifosTheme +import org.mifospay.core.designsystem.theme.grey +import org.mifospay.core.designsystem.theme.styleNormal18sp +import org.mifospay.core.ui.utils.EventsEffect + +@Composable +internal fun LoginScreen( + onNavigateBack: () -> Unit, + navigateToPasscodeScreen: () -> Unit, + navigateToSignupScreen: () -> Unit, + modifier: Modifier = Modifier, + viewModel: LoginViewModel = koinViewModel(), +) { + val state by viewModel.stateFlow.collectAsState() + val snackbarHostState = remember { SnackbarHostState() } + val scope = rememberCoroutineScope() + + EventsEffect(viewModel) { event -> + when (event) { + is LoginEvent.NavigateBack -> onNavigateBack.invoke() + is LoginEvent.NavigateToSignup -> navigateToSignupScreen.invoke() + is LoginEvent.NavigateToPasscodeScreen -> navigateToPasscodeScreen.invoke() + is LoginEvent.ShowToast -> { + scope.launch { + snackbarHostState.showSnackbar(event.message) + } + } + } + } + + LoginDialogs( + dialogState = state.dialogState, + onDismissRequest = remember(viewModel) { + { viewModel.trySendAction(LoginAction.ErrorDialogDismiss) } + }, + ) + + Scaffold( + snackbarHost = { SnackbarHost(snackbarHostState) }, + modifier = modifier.fillMaxSize(), + containerColor = MaterialTheme.colorScheme.background, + ) { paddingValues -> + LoginScreenContent( + state = state, + onEvent = remember(viewModel) { + { viewModel.trySendAction(it) } + }, + modifier = modifier.padding(paddingValues), + navigateToSignupScreen = navigateToSignupScreen, + ) + } +} + +@Composable +private fun LoginDialogs( + dialogState: LoginState.DialogState?, + onDismissRequest: () -> Unit, +) { + when (dialogState) { + is LoginState.DialogState.Error -> MifosBasicDialog( + visibilityState = BasicDialogState.Shown( + message = dialogState.message, + ), + onDismissRequest = onDismissRequest, + ) + + is LoginState.DialogState.Loading -> MifosLoadingDialog( + visibilityState = LoadingDialogState.Shown, + ) + + null -> Unit + } +} + +@Composable +private fun LoginScreenContent( + state: LoginState, + onEvent: (LoginAction) -> Unit, + modifier: Modifier = Modifier, + navigateToSignupScreen: () -> Unit, +) { + Column( + modifier = modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(horizontal = 24.dp) + .padding(top = 100.dp), + horizontalAlignment = Alignment.Start, + ) { + Text( + text = stringResource(Res.string.feature_auth_login), + style = MaterialTheme.typography.titleLarge, + color = MaterialTheme.colorScheme.primary, + ) + Text( + modifier = Modifier + .padding(top = 24.dp), + text = stringResource(Res.string.feature_auth_welcome_back), + style = styleNormal18sp.copy(color = grey), + ) + Spacer(modifier = Modifier.padding(top = 32.dp)) + MifosOutlinedTextField( + label = stringResource(Res.string.feature_auth_username), + value = state.username, + onValueChange = { + onEvent(LoginAction.UsernameChanged(it)) + }, + modifier = Modifier.fillMaxWidth(), + ) + Spacer(modifier = Modifier.padding(top = 16.dp)) + MifosOutlinedTextField( + label = stringResource(Res.string.feature_auth_password), + value = state.password, + onValueChange = { + onEvent(LoginAction.PasswordChanged(it)) + }, + modifier = Modifier.fillMaxWidth(), + visualTransformation = if (state.isPasswordVisible) { + VisualTransformation.None + } else { + PasswordVisualTransformation() + }, + trailingIcon = { + val icon = if (state.isPasswordVisible) { + MifosIcons.Visibility + } else { + MifosIcons.VisibilityOff + } + IconButton( + onClick = { onEvent(LoginAction.TogglePasswordVisibility) }, + ) { + Icon(imageVector = icon, null) + } + }, + ) + val isLoginButtonEnabled = state.username.isNotEmpty() && state.password.isNotEmpty() + MifosButton( + modifier = Modifier + .fillMaxWidth() + .padding(top = 16.dp), + enabled = isLoginButtonEnabled, + onClick = { + onEvent(LoginAction.LoginClicked) + }, + contentPadding = PaddingValues(12.dp), + ) { + Text( + text = stringResource(Res.string.feature_auth_login).uppercase(), + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.onPrimary, + ) + } + + SignupButton { navigateToSignupScreen() } + } +} + +@Composable +private fun SignupButton( + navigateToSignupScreen: () -> Unit, +) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 24.dp), + horizontalArrangement = Arrangement.Center, + ) { + Text( + text = "Donā€™t have an account yet? ", + style = MaterialTheme.typography.labelLarge, + color = MaterialTheme.colorScheme.onSurface, + ) + Text( + modifier = Modifier.clickable { + navigateToSignupScreen() + }, + text = stringResource(Res.string.feature_auth_sign_up), + style = MaterialTheme.typography.titleMedium.copy( + textDecoration = TextDecoration.Underline, + ), + ) + } +} + +@Preview +@Composable +private fun LoanScreenPreview() { + MifosTheme { + LoginScreenContent( + state = LoginState(dialogState = null), + onEvent = {}, + navigateToSignupScreen = {}, + ) + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt new file mode 100644 index 000000000..9bd45e200 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt @@ -0,0 +1,154 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.login + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.mifospay.core.common.IgnoredOnParcel +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize +import org.mifospay.core.common.Result +import org.mifospay.core.domain.LoginUseCase +import org.mifospay.core.model.domain.user.User +import org.mifospay.core.ui.utils.BaseViewModel + +private const val KEY_STATE = "state" + +class LoginViewModel( + private val loginUseCase: LoginUseCase, + savedStateHandle: SavedStateHandle, +) : BaseViewModel( + initialState = savedStateHandle[KEY_STATE] ?: LoginState(dialogState = null), +) { + + init { + savedStateHandle.get("username")?.let { + trySendAction(LoginAction.UsernameChanged(it)) + } + } + + override fun handleAction(action: LoginAction) { + when (action) { + is LoginAction.UsernameChanged -> { + mutableStateFlow.update { + it.copy(username = action.username) + } + } + + is LoginAction.PasswordChanged -> { + mutableStateFlow.update { + it.copy(password = action.password) + } + } + + is LoginAction.TogglePasswordVisibility -> { + mutableStateFlow.update { + it.copy(isPasswordVisible = !it.isPasswordVisible) + } + } + + is LoginAction.LoginClicked -> { + loginUser(state.username, state.password) + } + + is LoginAction.Internal.ReceiveLoginResult -> { + handleLoginResult(action) + } + + is LoginAction.SignupClicked -> { + sendEvent(LoginEvent.NavigateToSignup) + } + + is LoginAction.ErrorDialogDismiss -> { + mutableStateFlow.update { it.copy(dialogState = null) } + } + } + } + + private fun handleLoginResult(action: LoginAction.Internal.ReceiveLoginResult) { + when (action.loginResult) { + is Result.Error -> { + val message = action.loginResult.exception.message ?: "" + + mutableStateFlow.update { + it.copy(dialogState = LoginState.DialogState.Error(message)) + } + } + + is Result.Loading -> { + mutableStateFlow.update { + it.copy(dialogState = LoginState.DialogState.Loading) + } + } + + is Result.Success -> { + mutableStateFlow.update { + it.copy(dialogState = null) + } + sendEvent(LoginEvent.NavigateToPasscodeScreen) + } + } + } + + private fun loginUser( + username: String, + password: String, + ) { + mutableStateFlow.update { + it.copy(dialogState = LoginState.DialogState.Loading) + } + + viewModelScope.launch { + val result = loginUseCase(username, password) + sendAction(LoginAction.Internal.ReceiveLoginResult(result)) + } + } +} + +@Parcelize +data class LoginState( + val username: String = "", + @IgnoredOnParcel + val password: String = "", + val isPasswordVisible: Boolean = false, + val dialogState: DialogState?, +) : Parcelable { + sealed class DialogState : Parcelable { + @Parcelize + data class Error(val message: String) : DialogState() + + @Parcelize + data object Loading : DialogState() + } +} + +sealed class LoginEvent { + data object NavigateBack : LoginEvent() + data object NavigateToSignup : LoginEvent() + data object NavigateToPasscodeScreen : LoginEvent() + data class ShowToast(val message: String) : LoginEvent() +} + +sealed class LoginAction { + data class UsernameChanged(val username: String) : LoginAction() + data class PasswordChanged(val password: String) : LoginAction() + data object TogglePasswordVisibility : LoginAction() + data object ErrorDialogDismiss : LoginAction() + data object LoginClicked : LoginAction() + data object SignupClicked : LoginAction() + + sealed class Internal : LoginAction() { + data class ReceiveLoginResult( + val loginResult: Result, + ) : Internal() + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt new file mode 100644 index 000000000..d81788914 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt @@ -0,0 +1,291 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.mobileVerify + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTopAppBarState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch +import mobile_wallet.feature.auth.generated.resources.Res +import mobile_wallet.feature.auth.generated.resources.feature_auth_enter_mobile_number +import mobile_wallet.feature.auth.generated.resources.feature_auth_enter_mobile_number_description +import mobile_wallet.feature.auth.generated.resources.feature_auth_enter_otp +import mobile_wallet.feature.auth.generated.resources.feature_auth_enter_otp_received +import mobile_wallet.feature.auth.generated.resources.feature_auth_phone_number +import mobile_wallet.feature.auth.generated.resources.feature_auth_verify_otp +import mobile_wallet.feature.auth.generated.resources.feature_auth_verify_phone +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.koin.compose.viewmodel.koinViewModel +import org.mifospay.core.designsystem.component.BasicDialogState +import org.mifospay.core.designsystem.component.LoadingDialogState +import org.mifospay.core.designsystem.component.MifosBasicDialog +import org.mifospay.core.designsystem.component.MifosButton +import org.mifospay.core.designsystem.component.MifosLoadingDialog +import org.mifospay.core.designsystem.component.MifosOutlinedTextField +import org.mifospay.core.designsystem.component.MifosScaffold +import org.mifospay.core.designsystem.component.MifosTopAppBar +import org.mifospay.core.designsystem.component.NavigationIcon +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.designsystem.theme.MifosTheme +import org.mifospay.core.ui.utils.EventsEffect + +@Composable +internal fun MobileVerificationScreen( + onNavigateBack: () -> Unit, + onOtpVerificationSuccess: (String) -> Unit, + modifier: Modifier = Modifier, + viewModel: MobileVerificationViewModel = koinViewModel(), +) { + val state by viewModel.stateFlow.collectAsState() + val snackbarHostState = remember { SnackbarHostState() } + val scope = rememberCoroutineScope() + + EventsEffect(viewModel) { event -> + when (event) { + is MobileVerificationEvent.NavigateBack -> onNavigateBack.invoke() + + is MobileVerificationEvent.NavigateToSignup -> { + onOtpVerificationSuccess(event.phoneNo) + } + + is MobileVerificationEvent.ShowToast -> { + scope.launch { + snackbarHostState.showSnackbar(event.message) + } + } + } + } + + MobileVerificationScreen( + uiState = state, + onEvent = remember(viewModel) { + { viewModel.trySendAction(it) } + }, + snackbarHostState = snackbarHostState, + modifier = modifier, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun MobileVerificationScreen( + uiState: MobileVerificationState, + onEvent: (MobileVerificationAction) -> Unit, + modifier: Modifier = Modifier, + snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }, +) { + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) + + val title = if (uiState is MobileVerificationState.VerifyPhoneState) { + stringResource(Res.string.feature_auth_enter_mobile_number) + } else { + stringResource(Res.string.feature_auth_enter_otp) + } + + MifosScaffold( + modifier = modifier.fillMaxSize(), + snackbarHostState = snackbarHostState, + topBar = { + MifosTopAppBar( + title = title, + scrollBehavior = scrollBehavior, + navigationIcon = NavigationIcon( + navigationIcon = MifosIcons.Back, + navigationIconContentDescription = "Go Back", + onNavigationIconClick = { + onEvent(MobileVerificationAction.CloseButtonClick) + }, + ), + ) + }, + ) { paddingValues -> + when (uiState) { + is MobileVerificationState.VerifyPhoneState -> { + PhoneNoVerifyContent( + modifier = Modifier.padding(paddingValues), + state = uiState, + onEvent = onEvent, + ) + } + + is MobileVerificationState.VerifyOtpState -> { + OtpVerifyContent( + modifier = Modifier.padding(paddingValues), + state = uiState, + onEvent = onEvent, + ) + } + } + } +} + +@Composable +fun PhoneNoVerifyContent( + modifier: Modifier = Modifier, + state: MobileVerificationState.VerifyPhoneState, + onEvent: (MobileVerificationAction) -> Unit, +) { + MobileVerificationDialogs( + dialogState = state.dialogState, + onDismissRequest = { + onEvent(MobileVerificationAction.DismissDialog) + }, + ) + + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + MifosOutlinedTextField( + modifier = modifier, + value = state.phoneNo, + label = stringResource(Res.string.feature_auth_phone_number), + onValueChange = { + onEvent(MobileVerificationAction.PhoneNoChanged(it)) + }, + ) + + Text( + text = stringResource(Res.string.feature_auth_enter_mobile_number_description), + style = MaterialTheme.typography.bodySmall, + ) + + MifosButton( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 32.dp, vertical = 16.dp), + color = MaterialTheme.colorScheme.primary, + enabled = state.isPhoneNoValid, + onClick = { + onEvent(MobileVerificationAction.VerifyPhoneBtnClicked) + }, + contentPadding = PaddingValues(12.dp), + ) { + Text( + text = stringResource(Res.string.feature_auth_verify_phone).uppercase(), + style = MaterialTheme.typography.labelLarge, + ) + } + } +} + +@Composable +fun OtpVerifyContent( + modifier: Modifier = Modifier, + state: MobileVerificationState.VerifyOtpState, + onEvent: (MobileVerificationAction) -> Unit, +) { + MobileVerificationDialogs( + dialogState = state.dialogState, + onDismissRequest = { + onEvent(MobileVerificationAction.DismissDialog) + }, + ) + + Column( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 12.dp), + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + MifosOutlinedTextField( + modifier = modifier, + value = state.otp, + label = stringResource(Res.string.feature_auth_enter_otp), + onValueChange = { + onEvent(MobileVerificationAction.PhoneNoChanged(it)) + }, + ) + + Text( + text = stringResource(Res.string.feature_auth_enter_otp_received), + style = MaterialTheme.typography.bodySmall, + ) + + MifosButton( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 32.dp, vertical = 16.dp), + color = MaterialTheme.colorScheme.primary, + enabled = state.isOtpValid, + onClick = { + onEvent(MobileVerificationAction.VerifyOtpBtnClicked) + }, + contentPadding = PaddingValues(12.dp), + ) { + Text( + text = stringResource(Res.string.feature_auth_verify_otp).uppercase(), + style = MaterialTheme.typography.labelLarge, + ) + } + } +} + +@Composable +private fun MobileVerificationDialogs( + dialogState: MobileVerificationState.DialogState?, + onDismissRequest: () -> Unit, +) { + when (dialogState) { + is MobileVerificationState.DialogState.Error -> MifosBasicDialog( + visibilityState = BasicDialogState.Shown( + message = dialogState.message, + ), + onDismissRequest = onDismissRequest, + ) + + is MobileVerificationState.DialogState.Loading -> MifosLoadingDialog( + visibilityState = LoadingDialogState.Shown, + ) + + null -> Unit + } +} + +@Preview +@Composable +private fun MobileVerificationScreenVerifyPhonePreview() { + MifosTheme { + MobileVerificationScreen( + uiState = MobileVerificationState.VerifyPhoneState(), + onEvent = {}, + ) + } +} + +@Preview +@Composable +private fun MobileVerificationScreenVerifyOtpPreview() { + MifosTheme { + MobileVerificationScreen( + uiState = MobileVerificationState.VerifyOtpState(phoneNo = ""), + onEvent = {}, + ) + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt new file mode 100644 index 000000000..c90595ad5 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt @@ -0,0 +1,287 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.mobileVerify + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize +import org.mifospay.core.common.Result +import org.mifospay.core.data.repository.SearchRepository +import org.mifospay.core.data.util.Constants +import org.mifospay.core.ui.utils.BaseViewModel +import org.mifospay.feature.auth.mobileVerify.MobileVerificationAction.Internal.ReceiveOtpVerifyResult + +private const val KEY_STATE = "mobile_verification" + +class MobileVerificationViewModel( + private val searchRepository: SearchRepository, + savedStateHandle: SavedStateHandle, +) : BaseViewModel( + initialState = savedStateHandle[KEY_STATE] ?: MobileVerificationState.VerifyPhoneState(), +) { + + init { + stateFlow.onEach { savedStateHandle[KEY_STATE] = it }.launchIn(viewModelScope) + } + + override fun handleAction(action: MobileVerificationAction) { + when (action) { + is MobileVerificationAction.PhoneNoChanged -> { + mutableStateFlow.update { + if (it is MobileVerificationState.VerifyPhoneState) { + it.copy(phoneNo = action.phoneNo) + } else { + it + } + } + } + + is MobileVerificationAction.VerifyPhoneBtnClicked -> { + val currentState = state as? MobileVerificationState.VerifyPhoneState ?: return + verifyPhoneNo(currentState) + } + + is MobileVerificationAction.OtpChanged -> { + mutableStateFlow.update { + if (it is MobileVerificationState.VerifyOtpState) { + it.copy(otp = action.otp) + } else { + it + } + } + } + + is MobileVerificationAction.VerifyOtpBtnClicked -> { + val currentState = state as? MobileVerificationState.VerifyOtpState ?: return + verifyEnteredOTP(currentState) + } + + is ReceiveOtpVerifyResult -> handleOtpVerifyResult(action) + + is MobileVerificationAction.ChangePhoneNumber -> handleChangePhoneNoClick() + + is MobileVerificationAction.DismissDialog -> handleDismissDialog() + + is MobileVerificationAction.CloseButtonClick -> handleCloseButtonClick() + } + } + + private fun verifyPhoneNo(currentState: MobileVerificationState.VerifyPhoneState) { + if (currentState.isPhoneNoValid) { + verifyMobileAndRequestOtp(currentState.phoneNo, currentState) + } else { + mutableStateFlow.update { + currentState.copy( + dialogState = MobileVerificationState.DialogState.Error("Phone no isn't valid"), + ) + } + } + } + + private fun verifyMobileAndRequestOtp( + phoneNo: String, + currentState: MobileVerificationState.VerifyPhoneState, + ) { + viewModelScope.launch { + val result = searchRepository.searchResources( + query = phoneNo, + resources = Constants.CLIENTS, + exactMatch = true, + ) + + when (result) { + is Result.Error -> { + val message = result.exception.message ?: "Something Went Wrong!" + mutableStateFlow.update { + currentState.copy( + dialogState = MobileVerificationState.DialogState.Error(message), + ) + } + } + + is Result.Loading -> { + mutableStateFlow.update { + currentState.copy(dialogState = MobileVerificationState.DialogState.Loading) + } + } + + is Result.Success -> { + if (result.data.isEmpty()) { + requestAnOtpToPhoneNo(phoneNo) + } else { + val message = "Mobile number already exists." + mutableStateFlow.update { + currentState.copy( + dialogState = MobileVerificationState.DialogState.Error(message), + ) + } + } + } + } + } + } + + private fun requestAnOtpToPhoneNo(phoneNo: String) { + viewModelScope.launch { + // TODO:: Call repository request an otp to this phone no. + mutableStateFlow.update { + MobileVerificationState.VerifyOtpState(phoneNo) + } + trySendAction(MobileVerificationAction.DismissDialog) + } + } + + private fun verifyEnteredOTP(state: MobileVerificationState.VerifyOtpState) { + viewModelScope.launch { + if (state.isOtpValid) { + // TODO:: Match send otp to entered otp + mutableStateFlow.update { + state.copy( + dialogState = MobileVerificationState.DialogState.Loading, + ) + } + + sendAction(ReceiveOtpVerifyResult(Result.Success(state.phoneNo))) + } else { + mutableStateFlow.update { + state.copy( + dialogState = MobileVerificationState.DialogState.Error("OTP isn't valid"), + ) + } + } + } + } + + private fun handleOtpVerifyResult(action: ReceiveOtpVerifyResult) { + when (action.loginResult) { + is Result.Error -> { + mutableStateFlow.update { + (state as? MobileVerificationState.VerifyOtpState)?.copy( + dialogState = MobileVerificationState.DialogState.Error("Otp Verification Failed"), + ) ?: state + } + } + + is Result.Loading -> { + mutableStateFlow.update { + (state as? MobileVerificationState.VerifyOtpState)?.copy( + dialogState = MobileVerificationState.DialogState.Loading, + ) ?: state + } + } + + is Result.Success -> { + mutableStateFlow.update { + (state as? MobileVerificationState.VerifyOtpState)?.copy( + dialogState = null, + ) ?: state + } + sendEvent(MobileVerificationEvent.ShowToast("Otp Verified Successfully")) + sendEvent(MobileVerificationEvent.NavigateToSignup(action.loginResult.data)) + } + } + } + + private fun handleChangePhoneNoClick() { + viewModelScope.launch { + mutableStateFlow.update { + if (it is MobileVerificationState.VerifyOtpState) { + MobileVerificationState.VerifyPhoneState(phoneNo = it.phoneNo) + } else { + it + } + } + } + } + + private fun handleDismissDialog() { + viewModelScope.launch { + mutableStateFlow.update { + when (it) { + is MobileVerificationState.VerifyOtpState -> { + it.copy(dialogState = null) + } + + is MobileVerificationState.VerifyPhoneState -> { + it.copy(dialogState = null) + } + } + } + } + } + + private fun handleCloseButtonClick() { + viewModelScope.launch { + if (state is MobileVerificationState.VerifyOtpState) { + sendEvent(MobileVerificationEvent.NavigateBack) + } else { + sendAction(MobileVerificationAction.ChangePhoneNumber) + } + } + } +} + +sealed class MobileVerificationState : Parcelable { + @Parcelize + data class VerifyPhoneState( + val phoneNo: String = "", + val dialogState: DialogState? = null, + ) : MobileVerificationState() { + val isPhoneNoValid: Boolean + get() = phoneNo.length == 10 + } + + @Parcelize + data class VerifyOtpState( + val phoneNo: String, + val otp: String = "", + val dialogState: DialogState? = null, + ) : MobileVerificationState() { + val isOtpValid: Boolean + get() = otp.length == 6 + } + + sealed class DialogState : Parcelable { + @Parcelize + data class Error(val message: String) : DialogState() + + @Parcelize + data object Loading : DialogState() + } +} + +sealed interface MobileVerificationEvent { + data object NavigateBack : MobileVerificationEvent + data class NavigateToSignup(val phoneNo: String) : MobileVerificationEvent + data class ShowToast(val message: String) : MobileVerificationEvent +} + +sealed interface MobileVerificationAction { + data class PhoneNoChanged(val phoneNo: String) : MobileVerificationAction + data object VerifyPhoneBtnClicked : MobileVerificationAction + + data class OtpChanged(val otp: String) : MobileVerificationAction + data object ChangePhoneNumber : MobileVerificationAction + data object VerifyOtpBtnClicked : MobileVerificationAction + + data object DismissDialog : MobileVerificationAction + data object CloseButtonClick : MobileVerificationAction + + sealed class Internal : MobileVerificationAction { + data class ReceiveOtpVerifyResult( + val loginResult: Result, + ) : Internal() + } +} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt similarity index 63% rename from feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt rename to feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt index ef1c44d0f..98aec8fba 100644 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/LoginScreenNavigation.kt @@ -11,23 +11,35 @@ package org.mifospay.feature.auth.navigation import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType import androidx.navigation.compose.composable +import androidx.navigation.navArgument import org.mifospay.feature.auth.login.LoginScreen const val LOGIN_ROUTE = "login_route" fun NavGraphBuilder.loginScreen( + onNavigateBack: () -> Unit, onNavigateToPasscodeScreen: () -> Unit, onNavigateToSignupScreen: () -> Unit, ) { - composable(route = LOGIN_ROUTE) { + composable( + route = "$LOGIN_ROUTE?username={username}", + arguments = listOf( + navArgument("username") { + type = NavType.StringType + defaultValue = "" + }, + ), + ) { LoginScreen( + onNavigateBack = onNavigateBack, navigateToPasscodeScreen = onNavigateToPasscodeScreen, navigateToSignupScreen = onNavigateToSignupScreen, ) } } -fun NavController.navigateToLogin() { - this.navigate(LOGIN_ROUTE) +fun NavController.navigateToLogin(username: String = "") { + this.navigate("$LOGIN_ROUTE?username=$username") } diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt new file mode 100644 index 000000000..5bd912564 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +@file:Suppress("MaxLineLength") + +package org.mifospay.feature.auth.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable +import org.mifospay.feature.auth.mobileVerify.MobileVerificationScreen + +const val MOBILE_VERIFICATION_ROUTE = "mobile_verification_route" + +fun NavGraphBuilder.mobileVerificationScreen( + onNavigateBack: () -> Unit, + onOtpVerificationSuccess: (String) -> Unit, +) { + composable( + route = MOBILE_VERIFICATION_ROUTE, + ) { + MobileVerificationScreen( + onNavigateBack = onNavigateBack, + onOtpVerificationSuccess = onOtpVerificationSuccess, + ) + } +} + +fun NavController.navigateToMobileVerification() { + this.navigate(MOBILE_VERIFICATION_ROUTE) +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt new file mode 100644 index 000000000..e3d961162 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +@file:Suppress("MaxLineLength") + +package org.mifospay.feature.auth.navigation + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.NavType +import androidx.navigation.compose.composable +import androidx.navigation.navArgument +import org.mifospay.feature.auth.signup.SignupScreen + +const val SIGNUP_ROUTE = "signup_route" + +fun NavGraphBuilder.signupScreen( + onNavigateBack: () -> Unit, + onNavigateToLogin: (String) -> Unit, +) { + composable( + route = "$SIGNUP_ROUTE?savingsProductId={savingsProductId}" + + "&mobileNumber={mobileNumber}&businessName={businessName}", + arguments = listOf( + navArgument("savingsProductId") { + type = NavType.IntType + defaultValue = 0 + }, + navArgument("mobileNumber") { + type = NavType.StringType + defaultValue = "" + }, + navArgument("businessName") { + type = NavType.StringType + defaultValue = "" + }, + ), + ) { + SignupScreen( + onNavigateBack = onNavigateBack, + onNavigateToLogin = onNavigateToLogin, + ) + } +} + +fun NavController.navigateToSignup( + savingsProductId: Int = 0, + mobileNumber: String = "", + businessName: String = "", +) { + this.navigate( + "$SIGNUP_ROUTE?savingsProductId=$savingsProductId" + + "&mobileNumber=$mobileNumber&businessName=$businessName", + ) +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/PasswordStrengthIndicator.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/PasswordStrengthIndicator.kt new file mode 100644 index 000000000..ef44fb1f5 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/PasswordStrengthIndicator.kt @@ -0,0 +1,217 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.signup + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CheckCircle +import androidx.compose.material.icons.filled.Close +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.TransformOrigin +import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.unit.dp +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.designsystem.theme.MifosTheme + +@Suppress("LongMethod", "CyclomaticComplexMethod", "MagicNumber") +@Composable +fun PasswordStrengthIndicator( + modifier: Modifier = Modifier, + state: PasswordStrengthState, + currentCharacterCount: Int, + minimumCharacterCount: Int? = null, +) { + val widthPercent by animateFloatAsState( + targetValue = when (state) { + PasswordStrengthState.NONE -> 0f + PasswordStrengthState.WEAK_1 -> .25f + PasswordStrengthState.WEAK_2 -> .5f + PasswordStrengthState.WEAK_3 -> .66f + PasswordStrengthState.GOOD -> .82f + PasswordStrengthState.STRONG -> 1f + PasswordStrengthState.VERY_STRONG -> 1f + }, + label = "Width Percent State", + ) + val indicatorColor = when (state) { + PasswordStrengthState.NONE -> MaterialTheme.colorScheme.error + PasswordStrengthState.WEAK_1 -> MaterialTheme.colorScheme.error + PasswordStrengthState.WEAK_2 -> MaterialTheme.colorScheme.error + PasswordStrengthState.WEAK_3 -> weakColor + PasswordStrengthState.GOOD -> MaterialTheme.colorScheme.primary + PasswordStrengthState.STRONG -> strongColor + PasswordStrengthState.VERY_STRONG -> Color.Magenta + } + val animatedIndicatorColor by animateColorAsState( + targetValue = indicatorColor, + label = "Indicator Color State", + ) + val label = when (state) { + PasswordStrengthState.NONE -> "" + PasswordStrengthState.WEAK_1 -> "Weak" + PasswordStrengthState.WEAK_2 -> "Weak" + PasswordStrengthState.WEAK_3 -> "Weak" + PasswordStrengthState.GOOD -> "Good" + PasswordStrengthState.STRONG -> "Strong" + PasswordStrengthState.VERY_STRONG -> "Very Strong" + } + Column( + modifier = modifier, + ) { + Box( + Modifier + .fillMaxWidth() + .height(4.dp) + .background(MaterialTheme.colorScheme.surfaceContainerHigh), + ) { + Box( + modifier = Modifier + .fillMaxHeight() + .fillMaxWidth() + .graphicsLayer { + transformOrigin = TransformOrigin(pivotFractionX = 0f, pivotFractionY = 0f) + scaleX = widthPercent + } + .drawBehind { + drawRect(animatedIndicatorColor) + }, + ) + } + Spacer(Modifier.height(4.dp)) + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically, + ) { + minimumCharacterCount?.let { minCount -> + MinimumCharacterCount( + minimumRequirementMet = currentCharacterCount >= minCount, + minimumCharacterCount = minCount, + ) + } + Text( + text = label, + style = MaterialTheme.typography.labelSmall, + color = indicatorColor, + ) + } + } +} + +@Composable +private fun MinimumCharacterCount( + modifier: Modifier = Modifier, + minimumRequirementMet: Boolean, + minimumCharacterCount: Int, +) { + val characterCountColor by animateColorAsState( + targetValue = if (minimumRequirementMet) { + strongColor + } else { + MaterialTheme.colorScheme.surfaceDim + }, + label = "minmumCharacterCountColor", + ) + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically, + ) { + AnimatedContent( + targetState = if (minimumRequirementMet) { + Icons.Default.CheckCircle + } else { + Icons.Default.Close + }, + label = "iconForMinimumCharacterCount", + ) { + Icon( + imageVector = it, + contentDescription = null, + tint = characterCountColor, + modifier = Modifier.size(12.dp), + ) + } + Spacer(modifier = Modifier.width(2.dp)) + Text( + text = "$minimumCharacterCount characters", + color = characterCountColor, + style = MaterialTheme.typography.labelSmall, + ) + } +} + +enum class PasswordStrengthState { + NONE, + WEAK_1, + WEAK_2, + WEAK_3, + GOOD, + STRONG, + VERY_STRONG, +} + +private val strongColor = Color(0xFF41B06D) +private val weakColor = Color(0xFF8B6609) + +@Preview +@Composable +private fun PasswordStrengthIndicatorPreview_minCharMet() { + MifosTheme { + PasswordStrengthIndicator( + state = PasswordStrengthState.WEAK_3, + currentCharacterCount = 12, + minimumCharacterCount = 12, + ) + } +} + +@Preview +@Composable +private fun PasswordStrengthIndicatorPreview_minCharNotMet() { + MifosTheme { + PasswordStrengthIndicator( + state = PasswordStrengthState.WEAK_3, + currentCharacterCount = 11, + minimumCharacterCount = 12, + ) + } +} + +@Preview +@Composable +private fun PasswordStrengthIndicatorPreview_noMinChar() { + MifosTheme { + PasswordStrengthIndicator( + state = PasswordStrengthState.WEAK_3, + currentCharacterCount = 12, + ) + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt new file mode 100644 index 000000000..0d1266f4d --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt @@ -0,0 +1,308 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.signup + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.material3.rememberTopAppBarState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import kotlinx.coroutines.launch +import mobile_wallet.feature.auth.generated.resources.Res +import mobile_wallet.feature.auth.generated.resources.feature_auth_address_line_1 +import mobile_wallet.feature.auth.generated.resources.feature_auth_address_line_2 +import mobile_wallet.feature.auth.generated.resources.feature_auth_all_fields_are_mandatory +import mobile_wallet.feature.auth.generated.resources.feature_auth_complete +import mobile_wallet.feature.auth.generated.resources.feature_auth_complete_your_registration +import mobile_wallet.feature.auth.generated.resources.feature_auth_confirm_password +import mobile_wallet.feature.auth.generated.resources.feature_auth_country +import mobile_wallet.feature.auth.generated.resources.feature_auth_email +import mobile_wallet.feature.auth.generated.resources.feature_auth_first_name +import mobile_wallet.feature.auth.generated.resources.feature_auth_last_name +import mobile_wallet.feature.auth.generated.resources.feature_auth_mobile_no +import mobile_wallet.feature.auth.generated.resources.feature_auth_password +import mobile_wallet.feature.auth.generated.resources.feature_auth_pin_code +import mobile_wallet.feature.auth.generated.resources.feature_auth_state +import mobile_wallet.feature.auth.generated.resources.feature_auth_username +import org.jetbrains.compose.resources.stringResource +import org.koin.compose.viewmodel.koinViewModel +import org.mifospay.core.designsystem.component.BasicDialogState +import org.mifospay.core.designsystem.component.LoadingDialogState +import org.mifospay.core.designsystem.component.MfOutlinedTextField +import org.mifospay.core.designsystem.component.MifosBasicDialog +import org.mifospay.core.designsystem.component.MifosButton +import org.mifospay.core.designsystem.component.MifosLoadingDialog +import org.mifospay.core.designsystem.component.MifosScaffold +import org.mifospay.core.designsystem.component.MifosTopAppBar +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.ui.MifosPasswordField +import org.mifospay.core.ui.utils.EventsEffect + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +internal fun SignupScreen( + onNavigateBack: () -> Unit, + onNavigateToLogin: (String) -> Unit, + modifier: Modifier = Modifier, + viewModel: SignupViewModel = koinViewModel(), +) { + val state by viewModel.stateFlow.collectAsState() + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState()) + val snackbarHostState = remember { SnackbarHostState() } + val scope = rememberCoroutineScope() + + EventsEffect(viewModel) { event -> + when (event) { + is SignUpEvent.NavigateBack -> onNavigateBack.invoke() + is SignUpEvent.NavigateToLogin -> onNavigateToLogin.invoke(event.username) + is SignUpEvent.ShowToast -> { + scope.launch { + snackbarHostState.showSnackbar(event.message) + } + } + } + } + + SignUpDialogs( + dialogState = state.dialogState, + onDismissRequest = remember(viewModel) { + { viewModel.trySendAction(SignUpAction.ErrorDialogDismiss) } + }, + ) + + MifosScaffold( + snackbarHostState = snackbarHostState, + modifier = modifier, + topBar = { + MifosTopAppBar( + title = stringResource(Res.string.feature_auth_complete_your_registration), + subtitle = stringResource(Res.string.feature_auth_all_fields_are_mandatory), + scrollBehavior = scrollBehavior, + navigationIcon = MifosIcons.Back, + navigationIconContentDescription = "Back", + onNavigationIconClick = remember(viewModel) { + { viewModel.trySendAction(SignUpAction.CloseClick) } + }, + ) + }, + ) { + SignupScreenContent( + modifier = Modifier.padding(it), + state = state, + onAction = viewModel::trySendAction, + ) + } +} + +@Composable +private fun SignUpDialogs( + dialogState: SignUpDialog?, + onDismissRequest: () -> Unit, +) { + when (dialogState) { + is SignUpDialog.Error -> MifosBasicDialog( + visibilityState = BasicDialogState.Shown( + message = dialogState.message, + ), + onDismissRequest = onDismissRequest, + ) + + is SignUpDialog.Loading -> MifosLoadingDialog( + visibilityState = LoadingDialogState.Shown, + ) + + null -> Unit + } +} + +@Composable +private fun SignupScreenContent( + modifier: Modifier = Modifier, + state: SignUpState, + onAction: (SignUpAction) -> Unit, +) { + Column( + modifier = modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(horizontal = 16.dp), + verticalArrangement = Arrangement.spacedBy(8.dp), + ) { + MfOutlinedTextField( + value = state.firstNameInput, + label = stringResource(Res.string.feature_auth_first_name), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.FirstNameInputChange(it)) + }, + isError = state.firstNameInput.isEmpty(), + ) + + MfOutlinedTextField( + value = state.lastNameInput, + label = stringResource(Res.string.feature_auth_last_name), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.LastNameInputChange(it)) + }, + isError = state.lastNameInput.isEmpty(), + ) + + MfOutlinedTextField( + value = state.userNameInput, + label = stringResource(Res.string.feature_auth_username), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.UserNameInputChange(it)) + }, + isError = state.userNameInput.isEmpty(), + ) + + MfOutlinedTextField( + value = state.emailInput, + label = stringResource(Res.string.feature_auth_email), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.EmailInputChange(it)) + }, + isError = state.emailInput.isEmpty(), + ) + + MfOutlinedTextField( + value = state.mobileNumberInput, + label = stringResource(Res.string.feature_auth_mobile_no), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.MobileNumberInputChange(it)) + }, + isError = state.mobileNumberInput.isEmpty(), + ) + + var showPassword by rememberSaveable { mutableStateOf(false) } + + MifosPasswordField( + value = state.passwordInput, + label = stringResource(Res.string.feature_auth_password), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.PasswordInputChange(it)) + }, + showPassword = showPassword, + showPasswordChange = { showPassword = !showPassword }, + ) + PasswordStrengthIndicator( + modifier = Modifier.padding(horizontal = 16.dp), + state = state.passwordStrengthState, + currentCharacterCount = state.passwordInput.length, + ) + MifosPasswordField( + value = state.confirmPasswordInput, + label = stringResource(Res.string.feature_auth_confirm_password), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.ConfirmPasswordInputChange(it)) + }, + showPassword = showPassword, + showPasswordChange = { showPassword = !showPassword }, + ) + + MfOutlinedTextField( + value = state.addressLine1Input, + label = stringResource(Res.string.feature_auth_address_line_1), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.AddressLine1InputChange(it)) + }, + isError = state.addressLine1Input.isEmpty(), + ) + + MfOutlinedTextField( + value = state.addressLine2Input, + modifier = Modifier.fillMaxWidth(), + label = stringResource(Res.string.feature_auth_address_line_2), + onValueChange = { + onAction(SignUpAction.AddressLine2InputChange(it)) + }, + isError = state.addressLine2Input.isEmpty(), + ) + + MfOutlinedTextField( + value = state.pinCodeInput, + label = stringResource(Res.string.feature_auth_pin_code), + modifier = Modifier.fillMaxWidth(), + onValueChange = { + onAction(SignUpAction.PinCodeInputChange(it)) + }, + isError = state.pinCodeInput.isEmpty(), + ) + + Row( + modifier = Modifier.fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(8.dp), + ) { + MfOutlinedTextField( + value = state.countryInput, + label = stringResource(Res.string.feature_auth_country), + onValueChange = { + onAction(SignUpAction.CountryInputChange(it)) + }, + modifier = Modifier.weight(1.5f), + isError = state.countryInput.isEmpty(), + ) + + MfOutlinedTextField( + value = state.stateInput, + label = stringResource(Res.string.feature_auth_state), + onValueChange = { + onAction(SignUpAction.StateInputChange(it)) + }, + modifier = Modifier.weight(1.5f), + isError = state.stateInput.isEmpty(), + ) + } + + MifosButton( + modifier = Modifier + .fillMaxWidth(), + color = MaterialTheme.colorScheme.primary, + enabled = true, + onClick = { + onAction(SignUpAction.SubmitClick) + }, + contentPadding = PaddingValues(12.dp), + ) { + Text( + text = stringResource(Res.string.feature_auth_complete), + ) + } + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt new file mode 100644 index 000000000..45d9e040f --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt @@ -0,0 +1,591 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.signup + +import androidx.lifecycle.SavedStateHandle +import androidx.lifecycle.viewModelScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.update +import kotlinx.coroutines.launch +import org.mifospay.core.common.Parcelable +import org.mifospay.core.common.Parcelize +import org.mifospay.core.common.Result +import org.mifospay.core.common.utils.isValidEmail +import org.mifospay.core.data.repository.ClientRepository +import org.mifospay.core.data.repository.SearchRepository +import org.mifospay.core.data.repository.UserRepository +import org.mifospay.core.data.util.Constants +import org.mifospay.core.model.domain.client.Address +import org.mifospay.core.model.domain.client.NewClient +import org.mifospay.core.model.domain.user.NewUser +import org.mifospay.core.ui.utils.BaseViewModel +import org.mifospay.core.ui.utils.PasswordChecker +import org.mifospay.core.ui.utils.PasswordStrength +import org.mifospay.core.ui.utils.PasswordStrengthResult +import org.mifospay.feature.auth.signup.SignUpAction.Internal.ReceivePasswordStrengthResult + +private const val KEY_STATE = "signup_state" +private const val MIN_PASSWORD_LENGTH = 8 + +class SignupViewModel( + private val userRepository: UserRepository, + private val searchRepository: SearchRepository, + private val clientRepository: ClientRepository, + savedStateHandle: SavedStateHandle, +) : BaseViewModel( + initialState = savedStateHandle[KEY_STATE] ?: SignUpState(), +) { + private var passwordStrengthJob: Job = Job().apply { complete() } + + init { + stateFlow + .onEach { savedStateHandle[KEY_STATE] = it } + .launchIn(viewModelScope) + + savedStateHandle.get("mobileNumber")?.let { + viewModelScope.launch { + trySendAction(SignUpAction.MobileNumberInputChange(it)) + } + } + + savedStateHandle.get("savingsProductId")?.let { + viewModelScope.launch { + trySendAction(SignUpAction.SavingsAccountNoInputChange(it)) + } + } + + savedStateHandle.get("businessName")?.let { + viewModelScope.launch { + trySendAction(SignUpAction.BusinessNameInputChange(it)) + } + } + } + + override fun handleAction(action: SignUpAction) { + when (action) { + is SignUpAction.FirstNameInputChange -> { + mutableStateFlow.update { + it.copy(firstNameInput = action.firstName) + } + } + + is SignUpAction.LastNameInputChange -> { + mutableStateFlow.update { + it.copy(lastNameInput = action.lastName) + } + } + + is SignUpAction.UserNameInputChange -> { + mutableStateFlow.update { + it.copy(userNameInput = action.username) + } + } + + is SignUpAction.PasswordInputChange -> handlePasswordInput(action) + + is SignUpAction.ConfirmPasswordInputChange -> { + mutableStateFlow.update { + it.copy(confirmPasswordInput = action.confirmPassword) + } + } + + is SignUpAction.EmailInputChange -> { + mutableStateFlow.update { + it.copy(emailInput = action.email) + } + } + + is SignUpAction.AddressLine1InputChange -> { + mutableStateFlow.update { + it.copy(addressLine1Input = action.addressLineOne) + } + } + + is SignUpAction.AddressLine2InputChange -> { + mutableStateFlow.update { + it.copy(addressLine2Input = action.addressLineTwo) + } + } + + is SignUpAction.PinCodeInputChange -> { + mutableStateFlow.update { + it.copy(pinCodeInput = action.pincode) + } + } + + is SignUpAction.BusinessNameInputChange -> { + mutableStateFlow.update { + it.copy(businessNameInput = action.businessName) + } + } + + is SignUpAction.MobileNumberInputChange -> { + mutableStateFlow.update { + it.copy(mobileNumberInput = action.mobileNumber) + } + } + + is SignUpAction.SavingsAccountNoInputChange -> { + mutableStateFlow.update { + it.copy(savingsProductId = action.savingsAccountNo) + } + } + + is SignUpAction.StateInputChange -> { + mutableStateFlow.update { + it.copy(stateInput = action.state) + } + } + + is SignUpAction.CountryInputChange -> { + mutableStateFlow.update { + it.copy(countryInput = action.country) + } + } + + is SignUpAction.CloseClick -> { + sendEvent(SignUpEvent.NavigateBack) + } + + is SignUpAction.ErrorDialogDismiss -> { + mutableStateFlow.update { + it.copy(dialogState = null) + } + } + + is ReceivePasswordStrengthResult -> handlePasswordStrengthResult(action) + + is SignUpAction.Internal.ReceiveRegisterResult -> handleSignUpResult(action) + + is SignUpAction.SubmitClick -> handleSubmitClick() + } + } + + private fun handlePasswordInput(action: SignUpAction.PasswordInputChange) { + // Update input: + mutableStateFlow.update { it.copy(passwordInput = action.password) } + // Update password strength: + passwordStrengthJob.cancel() + if (action.password.isEmpty()) { + mutableStateFlow.update { + it.copy(passwordStrengthState = PasswordStrengthState.NONE) + } + } else { + passwordStrengthJob = viewModelScope.launch { + val result = PasswordChecker.getPasswordStrengthResult(action.password) + trySendAction(ReceivePasswordStrengthResult(result)) + } + } + } + + private fun handlePasswordStrengthResult(action: ReceivePasswordStrengthResult) { + when (val result = action.result) { + is PasswordStrengthResult.Success -> { + val updatedState = when (result.passwordStrength) { + PasswordStrength.LEVEL_0 -> PasswordStrengthState.WEAK_1 + PasswordStrength.LEVEL_1 -> PasswordStrengthState.WEAK_2 + PasswordStrength.LEVEL_2 -> PasswordStrengthState.WEAK_3 + PasswordStrength.LEVEL_3 -> PasswordStrengthState.GOOD + PasswordStrength.LEVEL_4 -> PasswordStrengthState.STRONG + PasswordStrength.LEVEL_5 -> PasswordStrengthState.VERY_STRONG + } + mutableStateFlow.update { oldState -> + oldState.copy(passwordStrengthState = updatedState) + } + } + + is PasswordStrengthResult.Error -> {} + } + } + + private fun handleSignUpResult(action: SignUpAction.Internal.ReceiveRegisterResult) { + when (val result = action.registerResult) { + is Result.Success -> { + mutableStateFlow.update { it.copy(dialogState = null) } + sendEvent(SignUpEvent.NavigateToLogin(result.data)) + } + + is Result.Error -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error(result.exception.message.toString())) + } + } + + Result.Loading -> { + mutableStateFlow.update { it.copy(dialogState = SignUpDialog.Loading) } + } + + else -> {} + } + } + + // TODO:: move error messages to strings.xml + private fun handleSubmitClick() = when { + state.savingsProductId == 0 -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please select a savings account.")) + } + } + + state.firstNameInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your first name.")) + } + } + + state.lastNameInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your last name.")) + } + } + + state.userNameInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your username.")) + } + } + + state.emailInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your email.")) + } + } + + !state.emailInput.isValidEmail() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter a valid email.")) + } + } + + state.mobileNumberInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your mobile number.")) + } + } + + state.mobileNumberInput.length < 10 -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Mobile number must be 10 digits long.")) + } + } + + state.passwordInput.length < MIN_PASSWORD_LENGTH -> { + mutableStateFlow.update { + it.copy( + dialogState = SignUpDialog.Error( + "Password must be at least $MIN_PASSWORD_LENGTH characters long.", + ), + ) + } + } + + !state.isPasswordMatch -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Passwords do not match.")) + } + } + + !state.isPasswordStrong -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Password is weak.")) + } + } + + state.addressLine1Input.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your address line 1.")) + } + } + + state.addressLine2Input.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your address line 2.")) + } + } + + state.pinCodeInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your pin code.")) + } + } + + state.pinCodeInput.length < 6 -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Pin code must be 6 digits long.")) + } + } + + state.countryInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your country.")) + } + } + + state.stateInput.isEmpty() -> { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Please enter your state.")) + } + } + + else -> initiateSignUp() + } + + /* + Enhancement: Move the following code in to a Use Case + */ + private fun initiateSignUp() { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Loading) + } + + // 0. Unique Mobile Number (checked in MOBILE VERIFICATION ACTIVITY) + // 1. Check for unique external id and username + // 2. Create user + // 3. Create Client + // 4. Update User and connect client with user + checkForUsernameExists(state.userNameInput) + } + + private fun checkForUsernameExists(username: String) { + viewModelScope.launch { + val result = searchRepository.searchResources( + username, + Constants.CLIENTS, + false, + ) + + when (result) { + is Result.Error -> { + val message = result.exception.message.toString() + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error(message)) + } + } + + is Result.Success -> { + if (result.data.isEmpty()) { + // Username is unique + val newUser = NewUser( + state.userNameInput, + state.firstNameInput, + state.lastNameInput, + state.emailInput, + state.passwordInput, + ) + + createUser(newUser) + } else { + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error("Username already exists.")) + } + } + } + + is Result.Loading -> Unit + } + } + } + + private fun createUser(newUser: NewUser) { + viewModelScope.launch { + when (val result = userRepository.createUser(newUser)) { + is Result.Error -> { + val message = result.exception.message.toString() + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error(message)) + } + } + + is Result.Success -> { + createClient(result.data.resourceId) + } + + is Result.Loading -> Unit + } + } + } + + private fun createClient(userId: Int) { + viewModelScope.launch { + val newClient = NewClient( + firstname = state.firstNameInput, + lastname = state.lastNameInput, + externalId = state.userNameInput.plus("_client"), + mobileNo = state.mobileNumberInput, + savingsProductId = state.savingsProductId, + address = Address( + addressLine1 = state.addressLine1Input, + addressLine2 = state.addressLine2Input, + postalCode = state.pinCodeInput, + stateProvinceId = state.stateInput, + countryId = state.countryInput, + ), + ) + + when (val result = clientRepository.createClient(newClient)) { + is Result.Error -> { + deleteUser(userId) + val message = result.exception.message.toString() + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error(message)) + } + } + + is Result.Success -> { + assignClientToUser(result.data.clientId, userId) + } + + is Result.Loading -> Unit + } + } + } + + private fun assignClientToUser(clientId: Int, userId: Int) { + viewModelScope.launch { + when (val result = userRepository.assignClientToUser(userId, clientId)) { + is Result.Error -> { + deleteUser(userId) + deleteClient(clientId) + val message = result.exception.message.toString() + mutableStateFlow.update { + it.copy(dialogState = SignUpDialog.Error(message)) + } + } + + is Result.Success -> { + mutableStateFlow.update { + it.copy(dialogState = null) + } + sendEvent(SignUpEvent.ShowToast("Registration successful.")) + sendAction( + SignUpAction.Internal.ReceiveRegisterResult( + Result.Success(state.userNameInput), + ), + ) + } + + is Result.Loading -> Unit + } + } + } + + private fun deleteUser(userId: Int) { + viewModelScope.launch { + userRepository.deleteUser(userId) + } + } + + private fun deleteClient(clientId: Int) { + viewModelScope.launch { + clientRepository.deleteClient(clientId) + } + } +} + +@Parcelize +data class SignUpState( + val savingsProductId: Int = 0, + val firstNameInput: String = "", + val lastNameInput: String = "", + val emailInput: String = "", + val userNameInput: String = "", + val addressLine1Input: String = "", + val addressLine2Input: String = "", + val pinCodeInput: String = "", + val passwordInput: String = "", + val confirmPasswordInput: String = "", + val mobileNumberInput: String = "", + val stateInput: String = "", + val countryInput: String = "", + val businessNameInput: String = "", + val dialogState: SignUpDialog? = null, + val passwordStrengthState: PasswordStrengthState = PasswordStrengthState.NONE, +) : Parcelable { + val isPasswordStrong: Boolean + get() = when (passwordStrengthState) { + PasswordStrengthState.NONE, + PasswordStrengthState.WEAK_1, + PasswordStrengthState.WEAK_2, + PasswordStrengthState.WEAK_3, + -> false + + PasswordStrengthState.GOOD, + PasswordStrengthState.STRONG, + PasswordStrengthState.VERY_STRONG, + -> true + } + + val isPasswordMatch: Boolean + get() = passwordInput == confirmPasswordInput + + val isSubmitEnabled: Boolean + get() = firstNameInput.isNotEmpty() && + lastNameInput.isNotEmpty() && + emailInput.isNotEmpty() && + userNameInput.isNotEmpty() && + addressLine1Input.isNotEmpty() && + addressLine2Input.isNotEmpty() && + pinCodeInput.isNotEmpty() && + mobileNumberInput.isNotEmpty() && + passwordInput.isNotEmpty() && + confirmPasswordInput.isNotEmpty() && + stateInput.isNotEmpty() && + countryInput.isNotEmpty() && + passwordInput.length >= MIN_PASSWORD_LENGTH && + isPasswordStrong && isPasswordMatch && + savingsProductId != 0 +} + +sealed interface SignUpDialog : Parcelable { + @Parcelize + data object Loading : SignUpDialog + + @Parcelize + data class Error(val message: String) : SignUpDialog +} + +sealed interface SignUpEvent { + data object NavigateBack : SignUpEvent + data class ShowToast(val message: String) : SignUpEvent + data class NavigateToLogin(val username: String) : SignUpEvent +} + +sealed interface SignUpAction { + data class FirstNameInputChange(val firstName: String) : SignUpAction + data class LastNameInputChange(val lastName: String) : SignUpAction + data class EmailInputChange(val email: String) : SignUpAction + data class UserNameInputChange(val username: String) : SignUpAction + data class AddressLine1InputChange(val addressLineOne: String) : SignUpAction + data class AddressLine2InputChange(val addressLineTwo: String) : SignUpAction + data class PinCodeInputChange(val pincode: String) : SignUpAction + data class BusinessNameInputChange(val businessName: String) : SignUpAction + data class PasswordInputChange(val password: String) : SignUpAction + data class ConfirmPasswordInputChange(val confirmPassword: String) : SignUpAction + data class MobileNumberInputChange(val mobileNumber: String) : SignUpAction + data class SavingsAccountNoInputChange(val savingsAccountNo: Int) : SignUpAction + data class StateInputChange(val state: String) : SignUpAction + data class CountryInputChange(val country: String) : SignUpAction + + data object SubmitClick : SignUpAction + data object CloseClick : SignUpAction + data object ErrorDialogDismiss : SignUpAction + + sealed class Internal : SignUpAction { + data class ReceiveRegisterResult( + val registerResult: Result, + ) : Internal() + + data class ReceivePasswordStrengthResult( + val result: PasswordStrengthResult, + ) : Internal() + } +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodNavigation.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodNavigation.kt new file mode 100644 index 000000000..a49df5196 --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodNavigation.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.socialSignup + +import androidx.navigation.NavController +import androidx.navigation.NavGraphBuilder +import androidx.navigation.compose.composable + +const val SIGNUP_METHOD_ROUTE = "signup_method_route" + +fun NavGraphBuilder.signupMethodScreen( + onNavigateBack: () -> Unit, + onNavigateToSignUp: (savingsProductId: Int) -> Unit, +) { + composable( + route = SIGNUP_METHOD_ROUTE, + ) { + SignupMethodScreen( + onDismissSignUp = onNavigateBack, + navigateToSignupScreen = onNavigateToSignUp, + ) + } +} + +fun NavController.navigateToSignupMethod() { + this.navigate(SIGNUP_METHOD_ROUTE) +} diff --git a/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodScreen.kt b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodScreen.kt new file mode 100644 index 000000000..45acff8ac --- /dev/null +++ b/feature/auth/src/commonMain/kotlin/org/mifospay/feature/auth/socialSignup/SignupMethodScreen.kt @@ -0,0 +1,175 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.feature.auth.socialSignup + +import androidx.compose.foundation.BorderStroke +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.wrapContentWidth +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.HorizontalDivider +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.dp +import mobile_wallet.feature.auth.generated.resources.Res +import mobile_wallet.feature.auth.generated.resources.feature_auth_create_an_account +import mobile_wallet.feature.auth.generated.resources.feature_auth_or +import mobile_wallet.feature.auth.generated.resources.feature_auth_sign_up_as_customer +import mobile_wallet.feature.auth.generated.resources.feature_auth_sign_up_as_merchant +import org.jetbrains.compose.resources.stringResource +import org.jetbrains.compose.ui.tooling.preview.Preview +import org.mifospay.core.data.util.Constants.WALLET_ACCOUNT_SAVINGS_PRODUCT_ID +import org.mifospay.core.designsystem.component.MifosOutlinedButton +import org.mifospay.core.designsystem.component.MifosScaffold +import org.mifospay.core.designsystem.component.MifosTopAppBar +import org.mifospay.core.designsystem.icon.MifosIcons +import org.mifospay.core.designsystem.theme.MifosTheme + +@Composable +internal fun SignupMethodScreen( + modifier: Modifier = Modifier, + navigateToSignupScreen: (savingsProductId: Int) -> Unit = {}, + onDismissSignUp: () -> Unit = {}, +) { + SignupMethodScreenContent( + modifier = modifier, + onDismissSignUp = onDismissSignUp, + navigateToSignupScreen = navigateToSignupScreen, + ) +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun SignupMethodScreenContent( + modifier: Modifier = Modifier, + onDismissSignUp: () -> Unit = {}, + navigateToSignupScreen: (savingsProductId: Int) -> Unit = {}, +) { + val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior() + MifosScaffold( + modifier = modifier, + topBar = { + MifosTopAppBar( + title = "Choose Account Type", + navigationIcon = MifosIcons.Back, + onNavigationIconClick = onDismissSignUp, + navigationIconContentDescription = "Back", + scrollBehavior = scrollBehavior, + ) + }, + ) { + SignupMethodScreenContent( + modifier = Modifier.padding(it), + onSignUpAsMerchant = { + navigateToSignupScreen(WALLET_ACCOUNT_SAVINGS_PRODUCT_ID) + }, + onSignupAsCustomer = { + navigateToSignupScreen(WALLET_ACCOUNT_SAVINGS_PRODUCT_ID) + }, + ) + } +} + +@Composable +private fun SignupMethodScreenContent( + onSignUpAsMerchant: () -> Unit, + onSignupAsCustomer: () -> Unit, + modifier: Modifier = Modifier, +) { + Column( + modifier = modifier + .fillMaxSize() + .background(color = MaterialTheme.colorScheme.surface), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + modifier = Modifier.padding(top = 16.dp), + text = stringResource(Res.string.feature_auth_create_an_account), + ) + + MifosOutlinedButton( + modifier = Modifier.padding(top = 48.dp), + onClick = onSignUpAsMerchant, + border = BorderStroke(1.dp, Color.LightGray), + shape = RoundedCornerShape(4.dp), + colors = ButtonDefaults.outlinedButtonColors( + contentColor = MaterialTheme.colorScheme.primary, + ), + ) { + Text( + text = stringResource(Res.string.feature_auth_sign_up_as_merchant).uppercase(), + style = MaterialTheme.typography.labelMedium, + ) + } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(top = 24.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + HorizontalDivider( + modifier = Modifier + .padding(start = 24.dp, end = 8.dp) + .weight(.4f), + thickness = 1.dp, + ) + Text( + modifier = Modifier + .wrapContentWidth() + .weight(.1f), + text = stringResource(Res.string.feature_auth_or), + ) + HorizontalDivider( + modifier = Modifier + .padding(start = 8.dp, end = 24.dp) + .weight(.4f), + thickness = 1.dp, + ) + } + + MifosOutlinedButton( + modifier = Modifier.padding(top = 24.dp), + onClick = onSignupAsCustomer, + border = BorderStroke(1.dp, Color.LightGray), + shape = RoundedCornerShape(4.dp), + colors = ButtonDefaults.outlinedButtonColors( + contentColor = MaterialTheme.colorScheme.primary, + ), + ) { + Text( + text = stringResource(Res.string.feature_auth_sign_up_as_customer).uppercase(), + style = MaterialTheme.typography.labelMedium, + ) + } + } +} + +@Preview +@Composable +private fun SignupMethodContentScreenPreview() { + MifosTheme { + SignupMethodScreenContent( + onSignUpAsMerchant = {}, + onSignupAsCustomer = {}, + ) + } +} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt deleted file mode 100644 index 7da08aa6a..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/di/AuthModule.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.di - -import org.koin.core.module.dsl.viewModel -import org.koin.dsl.module -import org.mifospay.feature.auth.login.LoginViewModel -import org.mifospay.feature.auth.mobileVerify.MobileVerificationViewModel -import org.mifospay.feature.auth.signup.SignupViewModel - -val AuthModule = module { - viewModel { - LoginViewModel( - mUseCaseHandler = get(), - authenticateUserUseCase = get(), - fetchClientDataUseCase = get(), - fetchUserDetailsUseCase = get(), - preferencesHelper = get(), - ) - } - viewModel { - SignupViewModel( - localAssetRepository = get(), - useCaseHandler = get(), - preferencesHelper = get(), - searchClientUseCase = get(), - createClientUseCase = get(), - createUserUseCase = get(), - updateUserUseCase = get(), - authenticateUserUseCase = get(), - fetchClientDataUseCase = get(), - deleteUserUseCase = get(), - fetchUserDetailsUseCase = get(), - ) - } - viewModel { - MobileVerificationViewModel( - mUseCaseHandler = get(), - searchClientUseCase = get(), - ) - } -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt deleted file mode 100644 index 4cddd202e..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginScreen.kt +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.login - -import android.widget.Toast -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.PasswordVisualTransformation -import androidx.compose.ui.text.input.TextFieldValue -import androidx.compose.ui.text.input.VisualTransformation -import androidx.compose.ui.text.style.TextDecoration -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import org.koin.androidx.compose.koinViewModel -import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel -import org.mifospay.core.designsystem.component.MifosButton -import org.mifospay.core.designsystem.component.MifosOutlinedTextField -import org.mifospay.core.designsystem.icon.MifosIcons -import org.mifospay.core.designsystem.theme.MifosTheme -import org.mifospay.core.designsystem.theme.grey -import org.mifospay.core.designsystem.theme.styleNormal18sp -import org.mifospay.feature.auth.R -import org.mifospay.feature.auth.socialSignup.SocialSignupMethodContentScreen - -@Composable -internal fun LoginScreen( - navigateToPasscodeScreen: () -> Unit, - modifier: Modifier = Modifier, - viewModel: LoginViewModel = koinViewModel(), - navigateToSignupScreen: () -> Unit, -) { - val context = LocalContext.current - val showProgress by viewModel.showProgress.collectAsStateWithLifecycle() - val isLoginSuccess by viewModel.isLoginSuccess.collectAsStateWithLifecycle() - - LoginScreenContent( - modifier = modifier, - showProgress = showProgress, - login = { username, password -> - viewModel.loginUser( - username = username, - password = password, - onLoginFailed = { message -> - Toast.makeText(context, message, Toast.LENGTH_SHORT).show() - }, - ) - }, - navigateToSignupScreen = navigateToSignupScreen, - ) - - if (isLoginSuccess) { - navigateToPasscodeScreen() - } -} - -@Composable -@Suppress("LongMethod") -private fun LoginScreenContent( - showProgress: Boolean, - login: (username: String, password: String) -> Unit, - modifier: Modifier = Modifier, - navigateToSignupScreen: () -> Unit, -) { - var showSignUpScreen by rememberSaveable { mutableStateOf(false) } - - var userName by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf( - TextFieldValue(""), - ) - } - var password by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf( - TextFieldValue(""), - ) - } - var passwordVisibility: Boolean by remember { mutableStateOf(false) } - - if (showSignUpScreen) { - SocialSignupMethodContentScreen( - navigateToSignupScreen = navigateToSignupScreen, - ) { - showSignUpScreen = false - } - } - - Box( - modifier = modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.surface), - ) { - Column( - modifier = Modifier - .fillMaxSize() - .verticalScroll(rememberScrollState()) - .padding(top = 100.dp, start = 48.dp, end = 48.dp), - horizontalAlignment = Alignment.Start, - ) { - Text( - text = stringResource(id = R.string.feature_auth_login), - style = MaterialTheme.typography.titleLarge, - color = MaterialTheme.colorScheme.primary, - ) - Text( - modifier = Modifier - .padding(top = 32.dp), - text = stringResource(id = R.string.feature_auth_welcome_back), - style = styleNormal18sp.copy(color = grey), - ) - Spacer(modifier = Modifier.padding(top = 32.dp)) - MifosOutlinedTextField( - label = R.string.feature_auth_username, - value = userName, - onValueChange = { - userName = it - }, - modifier = Modifier.fillMaxWidth(), - ) - Spacer(modifier = Modifier.padding(top = 16.dp)) - MifosOutlinedTextField( - label = R.string.feature_auth_password, - value = password, - onValueChange = { - password = it - }, - modifier = Modifier.fillMaxWidth(), - visualTransformation = if (passwordVisibility) { - VisualTransformation.None - } else { - PasswordVisualTransformation() - }, - trailingIcon = { - val image = if (passwordVisibility) { - MifosIcons.Visibility - } else { - MifosIcons.VisibilityOff - } - IconButton(onClick = { passwordVisibility = !passwordVisibility }) { - Icon(imageVector = image, null) - } - }, - ) - MifosButton( - modifier = Modifier - .fillMaxWidth() - .padding(top = 16.dp), - enabled = userName.text.isNotEmpty() && password.text.isNotEmpty(), - onClick = { - login.invoke(userName.text, password.text) - }, - contentPadding = PaddingValues(12.dp), - ) { - Text( - text = stringResource(id = R.string.feature_auth_login).uppercase(), - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onPrimary, - ) - } - // Hide reset password for now - /*Text( - modifier = Modifier - .fillMaxWidth() - .padding(top = 32.dp), - text = "Forgot Password", - textAlign = TextAlign.Center, - style = styleMedium16sp.copy( - textDecoration = TextDecoration.Underline, - ) - ) - Text( - modifier = Modifier - .fillMaxWidth() - .padding(top = 24.dp), - text = "OR", - textAlign = TextAlign.Center, - style = styleMedium16sp.copy(color = grey) - )*/ - Row( - modifier = Modifier - .fillMaxWidth() - .padding(top = 24.dp), - horizontalArrangement = Arrangement.Center, - ) { - Text( - text = "Donā€™t have an account yet? ", - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onSurface, - ) - Text( - modifier = Modifier.clickable { - showSignUpScreen = true - }, - text = stringResource(id = R.string.feature_auth_sign_up), - style = MaterialTheme.typography.titleMedium.copy( - textDecoration = TextDecoration.Underline, - ), - ) - } - } - - if (showProgress) { - MfOverlayLoadingWheel( - contentDesc = stringResource(id = R.string.feature_auth_logging_in), - ) - } - } -} - -@Preview(showSystemUi = true, device = "id:pixel_5") -@Composable -private fun LoanScreenPreview() { - MifosTheme { - LoginScreenContent( - showProgress = false, - login = { _, _ -> }, - navigateToSignupScreen = {}, - ) - } -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt deleted file mode 100644 index 8ed1a1cec..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/login/LoginViewModel.kt +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.login - -import android.util.Log -import androidx.lifecycle.ViewModel -import com.mifospay.core.model.domain.client.Client -import com.mifospay.core.model.domain.user.User -import com.mifospay.core.model.entity.UserWithRole -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.update -import org.mifospay.core.data.base.UseCase.UseCaseCallback -import org.mifospay.core.data.base.UseCaseHandler -import org.mifospay.core.data.domain.usecase.client.FetchClientData -import org.mifospay.core.data.domain.usecase.user.AuthenticateUser -import org.mifospay.core.data.domain.usecase.user.FetchUserDetails -import org.mifospay.core.datastore.PreferencesHelper - -class LoginViewModel( - private val mUseCaseHandler: UseCaseHandler, - private val authenticateUserUseCase: AuthenticateUser, - private val fetchClientDataUseCase: FetchClientData, - private val fetchUserDetailsUseCase: FetchUserDetails, - private val preferencesHelper: PreferencesHelper, -) : ViewModel() { - - private val _showProgress = MutableStateFlow(false) - val showProgress: StateFlow = _showProgress - - private val _isLoginSuccess = MutableStateFlow(false) - val isLoginSuccess: StateFlow = _isLoginSuccess - - fun updateProgressState(isVisible: Boolean) { - _showProgress.update { isVisible } - } - - fun updateIsLoginSuccess(isLoginSuccess: Boolean) { - _isLoginSuccess.update { isLoginSuccess } - } - - /** - * Authenticate User with username and password - * @param username - * @param password - * Note: username and password can't be empty or null when we pass to API - */ - fun loginUser( - username: String, - password: String, - onLoginFailed: (String) -> Unit, - ) { - updateProgressState(true) - authenticateUserUseCase.walletRequestValues = - AuthenticateUser.RequestValues(username, password) - - val requestValue = authenticateUserUseCase.walletRequestValues - mUseCaseHandler.execute( - authenticateUserUseCase, - requestValue, - object : UseCaseCallback { - override fun onSuccess(response: AuthenticateUser.ResponseValue) { - saveAuthTokenInPref(response.user) - fetchClientData(response.user) - fetchUserDetails(response.user) - } - - override fun onError(message: String) { - updateProgressState(false) - onLoginFailed(message) - } - }, - ) - } - - /** - * Fetch user details return by authenticated user - * @param user - */ - private fun fetchUserDetails(user: User) { - mUseCaseHandler.execute( - fetchUserDetailsUseCase, - FetchUserDetails.RequestValues(user.userId), - object : UseCaseCallback { - override fun onSuccess(response: FetchUserDetails.ResponseValue) { - saveUserDetails(user, response.userWithRole) - } - - override fun onError(message: String) { - updateProgressState(false) - Log.d("Login User Detailed: ", message) - } - }, - ) - } - - /** - * Fetch client details return by authenticated user - * Client Id: user.clients.firstOrNull() ?: 0 - * @param user - */ - private fun fetchClientData(user: User) { - mUseCaseHandler.execute( - fetchClientDataUseCase, - FetchClientData.RequestValues(user.clients.firstOrNull()), - object : UseCaseCallback { - override fun onSuccess(response: FetchClientData.ResponseValue) { - saveClientDetails(response.clientDetails) - updateProgressState(false) - if (response.clientDetails.name != "") { - updateIsLoginSuccess(true) - } - } - - override fun onError(message: String) { - updateProgressState(false) - } - }, - ) - } - - private fun saveAuthTokenInPref(user: User) { - preferencesHelper.saveToken("Basic " + user.base64EncodedAuthenticationKey) - } - - /** - * TODO remove userName, userId and Email from pref and use from saved User - */ - private fun saveUserDetails( - user: User, - userWithRole: UserWithRole, - ) { - val userName = user.username - val userID = user.userId - preferencesHelper.saveUsername(userName) - preferencesHelper.userId = userID - preferencesHelper.saveEmail(userWithRole.email) - preferencesHelper.user = user - } - - /** - * TODO remove name, clientId and mobileNo from pref and use from saved Client - */ - private fun saveClientDetails(client: Client?) { - preferencesHelper.saveFullName(client?.name) - preferencesHelper.clientId = client?.clientId!! - preferencesHelper.saveMobile(client.mobileNo) - preferencesHelper.client = client - } -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt deleted file mode 100644 index 31cc30a7d..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationScreen.kt +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.mobileVerify - -import android.widget.Toast -import androidx.compose.foundation.background -import androidx.compose.foundation.focusable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentSize -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.KeyboardActions -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextFieldDefaults -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalSoftwareKeyboardController -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.input.TextFieldValue -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.mifos.library.countrycodepicker.CountryCodePicker -import org.koin.androidx.compose.koinViewModel -import org.mifospay.core.common.Constants -import org.mifospay.core.designsystem.component.MifosButton -import org.mifospay.core.designsystem.component.MifosLoadingWheel -import org.mifospay.core.designsystem.component.MifosOutlinedTextField -import org.mifospay.core.designsystem.theme.MifosTheme -import org.mifospay.feature.auth.R - -@Composable -internal fun MobileVerificationScreen( - onOtpVerificationSuccess: (String) -> Unit, - modifier: Modifier = Modifier, - viewModel: MobileVerificationViewModel = koinViewModel(), -) { - val context = LocalContext.current - val uiState by viewModel.uiState.collectAsStateWithLifecycle() - - MobileVerificationScreen( - uiState = uiState, - showProgressState = viewModel.showProgress, - verifyMobileAndRequestOtp = { phone, fullPhone -> - viewModel.verifyMobileAndRequestOtp(fullPhone, phone) { - it?.let { - Toast.makeText(context, it, Toast.LENGTH_SHORT).show() - } - } - }, - verifyOtp = { validatedOtp, fullNumber -> - viewModel.verifyOTP(validatedOtp) { - onOtpVerificationSuccess(fullNumber) - } - }, - modifier = modifier, - ) -} - -@Composable -private fun MobileVerificationScreen( - uiState: MobileVerificationUiState, - verifyMobileAndRequestOtp: (String, String) -> Unit, - verifyOtp: (String, String) -> Unit, - modifier: Modifier = Modifier, - showProgressState: Boolean = false, -) { - var phoneNumber by rememberSaveable { mutableStateOf("") } - var fullPhoneNumber by rememberSaveable { mutableStateOf("") } - var isNumberValid: Boolean by rememberSaveable { mutableStateOf(false) } - - var isOtpValidated by rememberSaveable { mutableStateOf(false) } - var validatedOtp by rememberSaveable { mutableStateOf("") } - - fun verifyMobileOrOtp() { - if (uiState == MobileVerificationUiState.VerifyPhone && isNumberValid) { - verifyMobileAndRequestOtp(phoneNumber, fullPhoneNumber) - } else if (isOtpValidated) { - verifyOtp(validatedOtp, fullPhoneNumber) - } - } - - Box(modifier) { - Column( - modifier = Modifier - .fillMaxSize() - .background(color = Color.White) - .focusable(!showProgressState), - ) { - Column( - modifier = Modifier - .fillMaxWidth() - .background(color = MaterialTheme.colorScheme.primary), - verticalArrangement = Arrangement.Top, - ) { - Text( - modifier = Modifier.padding(top = 48.dp, start = 24.dp, end = 24.dp), - text = if (uiState == MobileVerificationUiState.VerifyPhone) { - stringResource(id = R.string.feature_auth_enter_mobile_number) - } else { - stringResource(id = R.string.feature_auth_enter_otp) - }, - style = MaterialTheme.typography.titleLarge.copy(color = MaterialTheme.colorScheme.onPrimary), - ) - Text( - modifier = Modifier.padding( - top = 4.dp, - bottom = 32.dp, - start = 24.dp, - end = 24.dp, - ), - text = if (uiState == MobileVerificationUiState.VerifyPhone) { - stringResource(id = R.string.feature_auth_enter_mobile_number_description) - } else { - stringResource(id = R.string.feature_auth_enter_otp_received_on_your_registered_device) - }, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onPrimary, - ) - } - - when (uiState) { - MobileVerificationUiState.VerifyPhone -> { - EnterPhoneScreen( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 16.dp), - onNumberUpdated = { phone, fullPhone, valid -> - phoneNumber = phone - fullPhoneNumber = fullPhone - isNumberValid = valid - }, - ) - } - - MobileVerificationUiState.VerifyOtp -> { - EnterOtpScreen( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 48.dp, vertical = 24.dp), - onOtpValidated = { isValidated, otp -> - isOtpValidated = isValidated - validatedOtp = otp - }, - ) - } - } - - MifosButton( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 32.dp, vertical = 16.dp), - color = MaterialTheme.colorScheme.primary, - enabled = if (uiState == MobileVerificationUiState.VerifyPhone) { - isNumberValid - } else { - isOtpValidated - }, - onClick = { verifyMobileOrOtp() }, - contentPadding = PaddingValues(12.dp), - ) { - Text( - text = if (uiState == MobileVerificationUiState.VerifyPhone) { - stringResource(id = R.string.feature_auth_verify_phone).uppercase() - } else { - stringResource(id = R.string.feature_auth_verify_otp).uppercase() - }, - style = MaterialTheme.typography.labelLarge, - color = MaterialTheme.colorScheme.onPrimary, - ) - } - } - - if (showProgressState) { - ShowProgressScreen(uiState = uiState) - } - } -} - -@Composable -private fun EnterPhoneScreen( - onNumberUpdated: (String, String, Boolean) -> Unit, - modifier: Modifier = Modifier, -) { - val keyboardController = LocalSoftwareKeyboardController.current - CountryCodePicker( - modifier = modifier, - shape = RoundedCornerShape(8.dp), - colors = OutlinedTextFieldDefaults.colors( - focusedBorderColor = MaterialTheme.colorScheme.primary, - ), - onValueChange = { (code, phone), isValid -> - onNumberUpdated(phone, code + phone, isValid) - }, - label = { Text(stringResource(id = R.string.feature_auth_phone_number)) }, - keyboardActions = KeyboardActions { keyboardController?.hide() }, - ) -} - -@Composable -private fun EnterOtpScreen( - onOtpValidated: (Boolean, String) -> Unit, - modifier: Modifier = Modifier, -) { - val keyboardController = LocalSoftwareKeyboardController.current - var otp by rememberSaveable(stateSaver = TextFieldValue.Saver) { - mutableStateOf(TextFieldValue("")) - } - - MifosOutlinedTextField( - label = R.string.feature_auth_enter_otp, - value = otp, - onValueChange = { - otp = it - onOtpValidated(otp.text.length == 6, otp.text) - }, - modifier = modifier, - keyboardActions = KeyboardActions { keyboardController?.hide() }, - ) -} - -@Composable -private fun ShowProgressScreen( - uiState: MobileVerificationUiState, - modifier: Modifier = Modifier, -) { - Box( - modifier = modifier - .fillMaxSize() - .background(color = MaterialTheme.colorScheme.primary.copy(alpha = 0.6f)) - .focusable(), - contentAlignment = Alignment.Center, - ) { - MifosLoadingWheel( - modifier = Modifier.wrapContentSize(), - contentDesc = if (uiState == MobileVerificationUiState.VerifyPhone) { - Constants.SENDING_OTP_TO_YOUR_MOBILE_NUMBER - } else { - Constants.VERIFYING_OTP - }, - ) - } -} - -@Preview -@Composable -private fun MobileVerificationScreenVerifyPhonePreview() { - MifosTheme { - MobileVerificationScreen( - uiState = MobileVerificationUiState.VerifyPhone, - showProgressState = false, - verifyMobileAndRequestOtp = { _, _ -> }, - verifyOtp = { _, _ -> }, - ) - } -} - -@Preview -@Composable -private fun MobileVerificationScreenVerifyOtpPreview() { - MifosTheme { - MobileVerificationScreen( - uiState = MobileVerificationUiState.VerifyOtp, - showProgressState = false, - verifyMobileAndRequestOtp = { _, _ -> }, - verifyOtp = { _, _ -> }, - ) - } -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt deleted file mode 100644 index fa0e3b7ab..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/mobileVerify/MobileVerificationViewModel.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.mobileVerify - -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.update -import kotlinx.coroutines.launch -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.base.UseCaseHandler -import org.mifospay.core.data.domain.usecase.client.SearchClient - -@Suppress("UnusedParameter") -class MobileVerificationViewModel( - private val mUseCaseHandler: UseCaseHandler, - private val searchClientUseCase: SearchClient, -) : ViewModel() { - - private val _uiState = - MutableStateFlow(MobileVerificationUiState.VerifyPhone) - val uiState: StateFlow = _uiState - - var showProgress by mutableStateOf(false) - - /** - * Verify Mobile number that it already exist or not then request otp - */ - fun verifyMobileAndRequestOtp( - fullNumber: String, - mobileNo: String, - onError: (String?) -> Unit, - ) { - showProgress = true - mUseCaseHandler.execute( - searchClientUseCase, - fullNumber.let { SearchClient.RequestValues(it) }, - object : UseCase.UseCaseCallback { - override fun onSuccess(response: SearchClient.ResponseValue) { - onError("Mobile number already exists.") - showProgress = false - } - - override fun onError(message: String) { - requestOtp(fullNumber) - } - }, - ) - } - - /** - * Request Otp from server - */ - fun requestOtp(fullNumber: String) { - viewModelScope.launch { - delay(2000) - showProgress = false - _uiState.update { - MobileVerificationUiState.VerifyOtp - } - } - } - - /** - * Verify Otp - */ - fun verifyOTP(otp: String?, onOtpVerifySuccess: () -> Unit) { - showProgress = true - viewModelScope.launch { - delay(2000) - showProgress = false - onOtpVerifySuccess() - } - } -} - -sealed interface MobileVerificationUiState { - data object VerifyOtp : MobileVerificationUiState - data object VerifyPhone : MobileVerificationUiState -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt deleted file mode 100644 index 2eb75757b..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/MobileVerificationScreenNavigation.kt +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -@file:Suppress("MaxLineLength") - -package org.mifospay.feature.auth.navigation - -import androidx.navigation.NavController -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavType -import androidx.navigation.compose.composable -import androidx.navigation.navArgument -import org.mifospay.core.common.Constants -import org.mifospay.feature.auth.mobileVerify.MobileVerificationScreen - -const val MOBILE_VERIFICATION_ROUTE = "mobile_verification_route" - -fun NavGraphBuilder.mobileVerificationScreen( - onOtpVerificationSuccess: (String, Map) -> Unit, -) { - composable( - route = "$MOBILE_VERIFICATION_ROUTE?mifosSignedUp={mifosSignedUp}&googleDisplayName={googleDisplayName}&googleEmail={googleEmail}&googleFamilyName={googleFamilyName}&googleGivenName={googleGivenName}", - arguments = listOf( - navArgument("mifosSignedUp") { - type = NavType.IntType - defaultValue = 0 - }, - navArgument("googleDisplayName") { - type = NavType.StringType - nullable = true - }, - navArgument("googleEmail") { - type = NavType.StringType - nullable = true - }, - navArgument("googleFamilyName") { - type = NavType.StringType - nullable = true - }, - navArgument("googleGivenName") { - type = NavType.StringType - nullable = true - }, - ), - ) { backStackEntry -> - val mifosSignedUp = backStackEntry.arguments?.getInt("mifosSignedUp") ?: 0 - val googleDisplayName = backStackEntry.arguments?.getString("googleDisplayName") - val googleEmail = backStackEntry.arguments?.getString("googleEmail") - val googleFamilyName = backStackEntry.arguments?.getString("googleFamilyName") - val googleGivenName = backStackEntry.arguments?.getString("googleGivenName") - - MobileVerificationScreen( - onOtpVerificationSuccess = { fullNumber -> - val extraData = mapOf( - Constants.MIFOS_SAVINGS_PRODUCT_ID to mifosSignedUp, - Constants.GOOGLE_DISPLAY_NAME to googleDisplayName, - Constants.GOOGLE_EMAIL to googleEmail, - Constants.GOOGLE_FAMILY_NAME to googleFamilyName, - Constants.GOOGLE_GIVEN_NAME to googleGivenName, - Constants.COUNTRY to "Canada", - Constants.MOBILE_NUMBER to fullNumber, - ) - onOtpVerificationSuccess(fullNumber, extraData) - }, - ) - } -} - -fun NavController.navigateToMobileVerification( - mifosSignedUp: Int, - googleDisplayName: String?, - googleEmail: String?, - googleFamilyName: String?, - googleGivenName: String?, -) { - this.navigate("$MOBILE_VERIFICATION_ROUTE?mifosSignedUp=$mifosSignedUp&googleDisplayName=$googleDisplayName&googleEmail=$googleEmail&googleFamilyName=$googleFamilyName&googleGivenName=$googleGivenName") -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt deleted file mode 100644 index 6c696eba9..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/navigation/SignupScreenNavigation.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -@file:Suppress("MaxLineLength") - -package org.mifospay.feature.auth.navigation - -import androidx.navigation.NavController -import androidx.navigation.NavGraphBuilder -import androidx.navigation.NavType -import androidx.navigation.compose.composable -import androidx.navigation.navArgument -import org.mifospay.feature.auth.signup.SignupScreen - -const val SIGNUP_ROUTE = "signup_route" - -@Suppress("UnusedParameter") -fun NavGraphBuilder.signupScreen( - onLoginSuccess: () -> Unit, - onRegisterSuccess: () -> Unit, -) { - composable( - route = "$SIGNUP_ROUTE?savingProductId={savingProductId}&mobileNumber={mobileNumber}&country={country}&email={email}&firstName={firstName}&lastName={lastName}&businessName={businessName}", - arguments = listOf( - navArgument("savingProductId") { - type = NavType.IntType - defaultValue = 0 - }, - navArgument("mobileNumber") { - type = NavType.StringType - defaultValue = "" - }, - navArgument("country") { - type = NavType.StringType - defaultValue = "" - }, - navArgument("email") { - type = NavType.StringType - defaultValue = "" - }, - navArgument("firstName") { - type = NavType.StringType - defaultValue = "" - }, - navArgument("lastName") { - type = NavType.StringType - defaultValue = "" - }, - navArgument("businessName") { - type = NavType.StringType - defaultValue = "" - }, - ), - ) { backStackEntry -> - val savingProductId = backStackEntry.arguments?.getInt("savingProductId") ?: 0 - val mobileNumber = backStackEntry.arguments?.getString("mobileNumber") ?: "" - val country = backStackEntry.arguments?.getString("country") ?: "" - val email = backStackEntry.arguments?.getString("email") ?: "" - val firstName = backStackEntry.arguments?.getString("firstName") ?: "" - val lastName = backStackEntry.arguments?.getString("lastName") ?: "" - val businessName = backStackEntry.arguments?.getString("businessName") ?: "" - - SignupScreen( - onLoginSuccess = onLoginSuccess, - savingProductId = savingProductId, - mobileNumber = mobileNumber, - country = country, - email = email, - firstName = firstName, - lastName = lastName, - businessName = businessName, - ) - } -} - -fun NavController.navigateToSignup( - savingProductId: Int = 0, - mobileNumber: String = "", - country: String = "", - email: String = "", - firstName: String = "", - lastName: String = "", - businessName: String = "", -) { - this.navigate( - "$SIGNUP_ROUTE?savingProductId=$savingProductId" + - "&mobileNumber=$mobileNumber&country=$country&email=$email" + - "&firstName=$firstName&lastName=$lastName&businessName=$businessName", - ) -} - -@Suppress("UnusedParameter") -fun onRegisterSuccess(s: String?) { - // registered but unable to login or user not updated with client - // TODO :: Consider this case - // 1. User not updated: when logging in update user - // 2. User unable to login (must be caused due to server) - // Toast.makeText(this, "Registered successfully.", Toast.LENGTH_SHORT).show() - // startActivity(Intent(this@SignupActivity, LoginActivity::class.java)) - // finish() -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt deleted file mode 100644 index 91525c17a..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupScreen.kt +++ /dev/null @@ -1,531 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.signup - -import android.widget.Toast -import androidx.compose.foundation.background -import androidx.compose.foundation.focusable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.verticalScroll -import androidx.compose.material3.DropdownMenu -import androidx.compose.material3.DropdownMenuItem -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.ExposedDropdownMenuBox -import androidx.compose.material3.ExposedDropdownMenuDefaults -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import org.mifospay.core.model.State -import com.mifospay.core.model.signup.PasswordStrength -import com.mifospay.core.model.signup.SignupData -import org.koin.androidx.compose.koinViewModel -import org.mifospay.core.data.util.Constants.MIFOS_MERCHANT_SAVINGS_PRODUCT_ID -import org.mifospay.core.designsystem.component.MfOutlinedTextField -import org.mifospay.core.designsystem.component.MfOverlayLoadingWheel -import org.mifospay.core.designsystem.component.MfPasswordTextField -import org.mifospay.core.designsystem.component.MifosButton -import org.mifospay.core.designsystem.theme.styleMedium16sp -import org.mifospay.feature.auth.R -import org.mifospay.feature.auth.utils.ValidateUtil.isValidEmail -import java.util.Locale - -@Composable -internal fun SignupScreen( - savingProductId: Int, - mobileNumber: String, - country: String, - email: String, - firstName: String, - lastName: String, - businessName: String, - onLoginSuccess: () -> Unit, - modifier: Modifier = Modifier, - viewModel: SignupViewModel = koinViewModel(), -) { - val context = LocalContext.current - - val stateList by viewModel.states.collectAsStateWithLifecycle() - - LaunchedEffect(key1 = true) { - viewModel.initSignupData( - savingProductId = savingProductId, - mobileNumber = mobileNumber, - countryName = country, - email = email, - firstName = firstName, - lastName = lastName, - businessName = businessName, - ) - } - LaunchedEffect(viewModel.isLoginSuccess) { - if (viewModel.isLoginSuccess) { - onLoginSuccess.invoke() - } - } - - SignupScreenContent( - modifier = modifier, - showProgressState = viewModel.showProgress, - data = viewModel.signupData, - stateList = stateList, - onCompleteRegistration = { - viewModel.registerUser(it) { message -> - Toast.makeText(context, message, Toast.LENGTH_SHORT).show() - } - }, - ) -} - -@Composable -@Suppress("LongMethod", "CyclomaticComplexMethod") -private fun SignupScreenContent( - data: SignupData, - stateList: List, - onCompleteRegistration: (SignupData) -> Unit, - modifier: Modifier = Modifier, - showProgressState: Boolean = false, -) { - val context = LocalContext.current - - var firstName by rememberSaveable { mutableStateOf(data.firstName ?: "") } - var lastName by rememberSaveable { mutableStateOf(data.lastName ?: "") } - var email by rememberSaveable { mutableStateOf(data.email ?: "") } - var userName by rememberSaveable { - mutableStateOf( - data.email?.ifEmpty { "" } - ?: data.email?.let { it.substring(0, it.indexOf('@')) } ?: "", - ) - } - var addressLine1 by rememberSaveable { mutableStateOf("") } - var addressLine2 by rememberSaveable { mutableStateOf("") } - var pinCode by rememberSaveable { mutableStateOf("") } - var nameOfBusiness by rememberSaveable { mutableStateOf(data.businessName ?: "") } - - var password by rememberSaveable { mutableStateOf("") } - var confirmPassword by rememberSaveable { mutableStateOf("") } - var isPasswordVisible by rememberSaveable { mutableStateOf(false) } - var isConfirmPasswordVisible by rememberSaveable { mutableStateOf(false) } - - var selectedState by rememberSaveable { mutableStateOf(null) } - - fun validateAllFields() { - val isAnyFieldEmpty = - firstName.isEmpty() || - lastName.isEmpty() || - email.isEmpty() || - userName.isEmpty() || - addressLine1.isEmpty() || - addressLine2.isEmpty() || - pinCode.isEmpty() || - password.isEmpty() || - confirmPassword.isEmpty() || - selectedState == null - - val isNameOfBusinessEmpty = - data.mifosSavingsProductId == MIFOS_MERCHANT_SAVINGS_PRODUCT_ID && - nameOfBusiness.isEmpty() - - if (!email.isValidEmail()) { - Toast - .makeText( - context, - context.getString(R.string.feature_auth_validate_email), - Toast.LENGTH_SHORT, - ).show() - return - } - - if (isAnyFieldEmpty || isNameOfBusinessEmpty) { - Toast - .makeText( - context, - context.getString(R.string.feature_auth_all_fields_are_mandatory), - Toast.LENGTH_SHORT, - ).show() - return - } - } - - fun completeRegistration() { - val signUpData = - data.copy( - firstName = firstName, - lastName = lastName, - email = email, - userName = userName, - addressLine1 = addressLine1, - addressLine2 = addressLine2, - pinCode = pinCode, - businessName = nameOfBusiness, - password = password, - stateId = selectedState?.id, - ) - onCompleteRegistration.invoke(signUpData) - } - - Box(modifier) { - Column( - modifier = - Modifier - .fillMaxSize() - .background(color = MaterialTheme.colorScheme.surface) - .verticalScroll(rememberScrollState()) - .focusable(!showProgressState), - ) { - Column( - modifier = - Modifier - .fillMaxWidth() - .background(color = MaterialTheme.colorScheme.primary), - verticalArrangement = Arrangement.Top, - ) { - Text( - modifier = Modifier.padding(top = 48.dp, start = 24.dp, end = 24.dp), - text = stringResource(id = R.string.feature_auth_complete_your_registration), - style = MaterialTheme.typography.titleLarge.copy(color = MaterialTheme.colorScheme.onPrimary), - ) - Text( - modifier = - Modifier.padding( - top = 4.dp, - bottom = 32.dp, - start = 24.dp, - end = 24.dp, - ), - text = stringResource(id = R.string.feature_auth_all_fields_are_mandatory), - style = MaterialTheme.typography.bodySmall.copy(color = Color.White), - ) - } - - Column( - modifier = - Modifier - .fillMaxWidth() - .padding(horizontal = 32.dp) - .focusable(!showProgressState), - ) { - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 16.dp), - label = stringResource(id = R.string.feature_auth_first_name), - value = firstName, - ) { - firstName = it - } - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_last_name), - value = lastName, - ) { - lastName = it - } - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_username), - value = userName, - ) { - userName = it - } - PasswordAndConfirmPassword( - password = password, - onPasswordChange = { password = it }, - confirmPassword = confirmPassword, - onConfirmPasswordChange = { confirmPassword = it }, - isPasswordVisible = isPasswordVisible, - onTogglePasswordVisibility = { isPasswordVisible = !isPasswordVisible }, - isConfirmPasswordVisible = isConfirmPasswordVisible, - onConfirmTogglePasswordVisibility = { - isConfirmPasswordVisible = !isConfirmPasswordVisible - }, - ) - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_email), - value = email, - ) { - email = it - } - if (data.mifosSavingsProductId == MIFOS_MERCHANT_SAVINGS_PRODUCT_ID) { - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_name_of_business), - value = nameOfBusiness, - ) { - nameOfBusiness = it - } - } - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_address_line_1), - value = addressLine1, - ) { - addressLine1 = it - } - UserInfoTextField( - modifier = - Modifier - .fillMaxWidth() - .padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_address_line_2), - value = addressLine2, - ) { - addressLine2 = it - } - UserInfoTextField( - modifier = Modifier.padding(top = 8.dp), - label = stringResource(id = R.string.feature_auth_pin_code), - value = pinCode, - ) { - pinCode = it - } - HorizontalDivider(thickness = 8.dp, color = Color.White) - MifosStateDropDownOutlinedTextField( - value = selectedState?.name ?: "", - label = stringResource(id = R.string.feature_auth_state), - stateList = stateList, - ) { - selectedState = it - } - HorizontalDivider(thickness = 24.dp, color = Color.White) - MifosButton( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - color = MaterialTheme.colorScheme.primary, - enabled = true, - onClick = { - validateAllFields() - completeRegistration() - }, - contentPadding = PaddingValues(12.dp), - ) { - Text( - text = stringResource(id = R.string.feature_auth_complete), - style = styleMedium16sp.copy(color = MaterialTheme.colorScheme.onPrimary), - ) - } - } - } - - if (showProgressState) { - MfOverlayLoadingWheel( - contentDesc = stringResource(id = R.string.feature_auth_please_wait), - ) - } - } -} - -@OptIn(ExperimentalMaterial3Api::class) -@Composable -private fun MifosStateDropDownOutlinedTextField( - value: String, - label: String, - stateList: List, - modifier: Modifier = Modifier, - onSelectedState: (State) -> Unit = {}, -) { - var expanded by rememberSaveable { mutableStateOf(false) } - ExposedDropdownMenuBox( - expanded = expanded, - onExpandedChange = { - expanded = !expanded - }, - ) { - OutlinedTextField( - modifier = modifier.menuAnchor(), - value = value, - onValueChange = { }, - readOnly = true, - label = { Text(label) }, - trailingIcon = { - ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) - }, - ) - DropdownMenu( - expanded = expanded, - onDismissRequest = { - expanded = false - }, - ) { - stateList.forEach { - DropdownMenuItem( - text = { Text(text = it.name) }, - onClick = { - expanded = false - onSelectedState(it) - }, - ) - } - } - } -} - -@Composable -private fun UserInfoTextField( - label: String, - value: String, - modifier: Modifier = Modifier, - onValueChange: (String) -> Unit = {}, -) { - MfOutlinedTextField( - value = value, - label = label, - onValueChange = onValueChange, - modifier = modifier, - isError = value.isEmpty(), - errorMessage = stringResource(id = R.string.feature_auth_mandatory), - ) -} - -@Composable -private fun PasswordAndConfirmPassword( - password: String, - onPasswordChange: (String) -> Unit, - confirmPassword: String, - onConfirmPasswordChange: (String) -> Unit, - isPasswordVisible: Boolean, - onTogglePasswordVisibility: () -> Unit, - isConfirmPasswordVisible: Boolean, - onConfirmTogglePasswordVisibility: () -> Unit, - modifier: Modifier = Modifier, -) { - Column(modifier) { - MfPasswordTextField( - password = password, - label = stringResource(id = R.string.feature_auth_password), - isError = password.isEmpty() || password.length < 6, - isPasswordVisible = isPasswordVisible, - onTogglePasswordVisibility = onTogglePasswordVisibility, - onPasswordChange = onPasswordChange, - modifier = Modifier.fillMaxWidth(), - errorMessage = - if (password.isEmpty()) { - stringResource(id = R.string.feature_auth_password_cannot_be_empty) - } else if (password.length < 6) { - stringResource(id = R.string.feature_auth_password_must_be_least_6_characters) - } else { - null - }, - ) - MfPasswordTextField( - password = confirmPassword, - label = stringResource(id = R.string.feature_auth_confirm_password), - isError = confirmPassword.isEmpty() || password != confirmPassword, - isPasswordVisible = isConfirmPasswordVisible, - onTogglePasswordVisibility = onConfirmTogglePasswordVisibility, - onPasswordChange = onConfirmPasswordChange, - modifier = Modifier.fillMaxWidth(), - errorMessage = - if (confirmPassword.isEmpty()) { - stringResource(id = R.string.feature_auth_confirm_password_cannot_empty) - } else if (password != confirmPassword) { - stringResource(id = R.string.feature_auth_passwords_do_not_match) - } else { - null - }, - ) - if (password.length >= 6) { - Text( - modifier = Modifier.padding(top = 8.dp), - text = "${stringResource(id = R.string.feature_auth_password_strength)}${ - getPasswordStrength(password).replaceFirstChar { - if (it.isLowerCase()) { - it.titlecase( - Locale.ENGLISH, - ) - } else { - it.toString() - } - } - }", - color = getPasswordStrengthColor(password), - ) - } - } -} - -private fun getPasswordStrength(password: String): String { - val hasUpperCase = password.any { it.isUpperCase() } - val hasLowerCase = password.any { it.isLowerCase() } - val hasNumbers = password.any { it.isDigit() } - val hasSymbols = password.any { !it.isLetterOrDigit() } - - val numTypesPresent = - intArrayOf( - hasUpperCase.toInt(), - hasLowerCase.toInt(), - hasNumbers.toInt(), - hasSymbols.toInt(), - ).sum() - return PasswordStrength.entries[numTypesPresent].name -} - -private fun Boolean.toInt() = if (this) 1 else 0 - -private fun getPasswordStrengthColor(password: String): Color { - val strength = getPasswordStrength(password) - return when (PasswordStrength.valueOf(strength)) { - PasswordStrength.WEAK -> Color.Red - PasswordStrength.MODERATE -> Color.DarkGray - PasswordStrength.STRONG -> Color.Green - PasswordStrength.VERY_STRONG -> Color.Blue - PasswordStrength.EXCELLENT -> Color.Magenta - else -> Color.Black - } -} - -@Preview -@Composable -private fun SignupScreenPreview() { - SignupScreenContent( - showProgressState = false, - data = SignupData(), - stateList = listOf(), - onCompleteRegistration = { }, - ) -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt deleted file mode 100644 index 284d93cb4..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/signup/SignupViewModel.kt +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.signup - -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import org.mifospay.core.model.State -import com.mifospay.core.model.domain.user.NewUser -import com.mifospay.core.model.domain.user.UpdateUserEntityClients -import com.mifospay.core.model.domain.user.User -import com.mifospay.core.model.entity.UserWithRole -import com.mifospay.core.model.signup.SignupData -import kotlinx.coroutines.flow.SharingStarted -import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.stateIn -import org.mifospay.core.common.Constants -import org.mifospay.core.common.DebugUtil -import org.mifospay.core.data.base.UseCase -import org.mifospay.core.data.base.UseCaseHandler -import org.mifospay.core.data.domain.usecase.client.CreateClient -import org.mifospay.core.data.domain.usecase.client.FetchClientData -import org.mifospay.core.data.domain.usecase.client.SearchClient -import org.mifospay.core.data.domain.usecase.user.AuthenticateUser -import org.mifospay.core.data.domain.usecase.user.CreateUser -import org.mifospay.core.data.domain.usecase.user.DeleteUser -import org.mifospay.core.data.domain.usecase.user.FetchUserDetails -import org.mifospay.core.data.domain.usecase.user.UpdateUser -import org.mifospay.core.data.repository.local.LocalAssetRepository -import org.mifospay.core.datastore.PreferencesHelper - -class SignupViewModel( - localAssetRepository: LocalAssetRepository, - private val useCaseHandler: UseCaseHandler, - private val preferencesHelper: PreferencesHelper, - private val searchClientUseCase: SearchClient, - private val createClientUseCase: CreateClient, - private val createUserUseCase: CreateUser, - private val updateUserUseCase: UpdateUser, - private val authenticateUserUseCase: AuthenticateUser, - private val fetchClientDataUseCase: FetchClientData, - private val deleteUserUseCase: DeleteUser, - private val fetchUserDetailsUseCase: FetchUserDetails, -) : ViewModel() { - - var showProgress by mutableStateOf(false) - var isLoginSuccess by mutableStateOf(false) - - var signupData by mutableStateOf(SignupData()) - var state by mutableStateOf(null) - - fun initSignupData( - savingProductId: Int, - mobileNumber: String, - countryName: String?, - email: String?, - firstName: String?, - lastName: String?, - businessName: String?, - ) { - signupData = signupData.copy( - mifosSavingsProductId = savingProductId, - mobileNumber = mobileNumber, - countryName = countryName, - email = email, - firstName = firstName!!, - lastName = lastName!!, - businessName = businessName, - ) - } - - val states: StateFlow> = combine( - localAssetRepository.getCountries(), - localAssetRepository.getStateList(), - ::Pair, - ) - .map { - val countries = it.first - signupData = signupData.copy( - countryId = countries.find { it.name == signupData.countryName }?.id ?: "", - ) - it.second.filter { it.countryId == signupData.countryId } - } - .stateIn( - scope = viewModelScope, - started = SharingStarted.WhileSubscribed(5_000), - initialValue = emptyList(), - ) - - fun registerUser(data: SignupData, showToastMessage: (String) -> Unit) { - signupData = data - - // 0. Unique Mobile Number (checked in MOBILE VERIFICATION ACTIVITY) - // 1. Check for unique external id and username - // 2. Create user - // 3. Create Client - // 4. Update User and connect client with user - useCaseHandler.execute( - searchClientUseCase, - SearchClient.RequestValues("${signupData.userName}@mifos"), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: SearchClient.ResponseValue) { - showToastMessage("Username already exists.") - } - - override fun onError(message: String) { - createUser(showToastMessage) - } - }, - ) - } - - private fun createUser(showToastMessage: (String) -> Unit) { - val newUser = NewUser( - signupData.userName, - signupData.firstName, - signupData.lastName, - signupData.email, - signupData.password, - ) - useCaseHandler.execute( - createUserUseCase, - CreateUser.RequestValues(newUser), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: CreateUser.ResponseValue) { - createClient(response.userId, showToastMessage) - } - - override fun onError(message: String) { - DebugUtil.log(message) - showToastMessage(message) - } - }, - ) - } - - private fun createClient(userId: Int, showToastMessage: (String) -> Unit) { - val newClient = com.mifospay.core.model.domain.client.NewClient( - signupData.businessName, signupData.userName, signupData.addressLine1, - signupData.addressLine2, signupData.city, signupData.pinCode, signupData.stateId, - signupData.countryId, signupData.mobileNumber, signupData.mifosSavingsProductId, - ) - useCaseHandler.execute( - createClientUseCase, - CreateClient.RequestValues(newClient), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: CreateClient.ResponseValue) { - response.clientId.let { DebugUtil.log(it) } - val clients = ArrayList() - response.clientId.let { clients.add(it) } - updateClient(clients, userId, showToastMessage) - } - - override fun onError(message: String) { - // delete user - DebugUtil.log(message) - showToastMessage(message) - deleteUser(userId) - } - }, - ) - } - - private fun updateClient( - clients: ArrayList, - userId: Int, - showToastMessage: (String) -> Unit, - ) { - useCaseHandler.execute( - updateUserUseCase, - UpdateUser.RequestValues(UpdateUserEntityClients(clients), userId), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: UpdateUser.ResponseValue?) { - loginUser(signupData.userName, signupData.password, showToastMessage) - } - - override fun onError(message: String) { - // connect client later - DebugUtil.log(message) - showToastMessage("update client error") - } - }, - ) - } - - private fun loginUser( - username: String?, - password: String?, - showToastMessage: (String) -> Unit, - ) { - authenticateUserUseCase.walletRequestValues = AuthenticateUser.RequestValues(username!!, password!!) - val requestValue = authenticateUserUseCase.walletRequestValues - useCaseHandler.execute( - authenticateUserUseCase, - requestValue, - object : UseCase.UseCaseCallback { - override fun onSuccess(response: AuthenticateUser.ResponseValue) { - createAuthenticatedService(response.user) - fetchClientData(showToastMessage) - fetchUserDetails(response.user) - } - - override fun onError(message: String) { - showToastMessage("Login Failed") - } - }, - ) - } - - private fun fetchUserDetails(user: User) { - useCaseHandler.execute( - fetchUserDetailsUseCase, - FetchUserDetails.RequestValues(user.userId), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: FetchUserDetails.ResponseValue) { - saveUserDetails(user, response.userWithRole) - } - - override fun onError(message: String) { - DebugUtil.log(message) - } - }, - ) - } - - private fun fetchClientData(showToastMessage: (String) -> Unit) { - useCaseHandler.execute( - fetchClientDataUseCase, - null, - object : UseCase.UseCaseCallback { - override fun onSuccess(response: FetchClientData.ResponseValue) { - saveClientDetails(response.clientDetails) - if (response.clientDetails.name != "") { - isLoginSuccess = true - } - } - - override fun onError(message: String) { - showToastMessage("Fetch Client Error") - } - }, - ) - } - - private fun createAuthenticatedService(user: User) { - val authToken = Constants.BASIC + user.base64EncodedAuthenticationKey - preferencesHelper.saveToken(authToken) - } - - private fun saveUserDetails( - user: User, - userWithRole: UserWithRole, - ) { - val userName = user.username - val userID = user.userId - preferencesHelper.saveUsername(userName) - preferencesHelper.userId = userID - preferencesHelper.saveEmail(userWithRole.email) - } - - private fun saveClientDetails(client: com.mifospay.core.model.domain.client.Client) { - preferencesHelper.saveFullName(client.name) - preferencesHelper.clientId = client.clientId - preferencesHelper.saveMobile(client.mobileNo) - } - - private fun deleteUser(userId: Int) { - useCaseHandler.execute( - deleteUserUseCase, - DeleteUser.RequestValues(userId), - object : UseCase.UseCaseCallback { - override fun onSuccess(response: DeleteUser.ResponseValue) {} - override fun onError(message: String) {} - }, - ) - } -} - -sealed interface SignupUiState { - data object None : SignupUiState - data object Success : SignupUiState - data class Error(val exception: String) : SignupUiState -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt deleted file mode 100644 index 87c377b69..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/socialSignup/SocialSignupMethodScreen.kt +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -@file:Suppress("MaxLineLength") - -package org.mifospay.feature.auth.socialSignup - -import android.content.Context -import android.util.Log -import android.widget.Toast -import androidx.compose.foundation.BorderStroke -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.wrapContentWidth -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Checkbox -import androidx.compose.material3.CheckboxDefaults -import androidx.compose.material3.CircularProgressIndicator -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableIntStateOf -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.saveable.rememberSaveable -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.credentials.ClearCredentialStateRequest -import androidx.credentials.CredentialManager -import androidx.credentials.CustomCredential -import androidx.credentials.GetCredentialRequest -import androidx.credentials.GetCredentialResponse -import androidx.credentials.exceptions.GetCredentialException -import com.google.android.libraries.identity.googleid.GetGoogleIdOption -import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential -import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException -import kotlinx.coroutines.launch -import org.mifospay.core.common.Constants -import org.mifospay.core.data.util.Constants.MIFOS_CONSUMER_SAVINGS_PRODUCT_ID -import org.mifospay.core.data.util.Constants.MIFOS_MERCHANT_SAVINGS_PRODUCT_ID -import org.mifospay.core.designsystem.component.MifosBottomSheet -import org.mifospay.core.designsystem.component.MifosOutlinedButton -import org.mifospay.core.designsystem.theme.MifosTheme -import org.mifospay.feature.auth.R - -const val TAG = "Social Login" - -// Followed this https://medium.com/@nirmale.ashwin9696/a-comprehensive-guide-to-google-sign-in-integration-with-credential-manager-in-android-apps-05286f8f5848 -// Keeping until we fix sign up -@Composable -internal fun SocialSignupMethodContentScreen( - modifier: Modifier = Modifier, - navigateToSignupScreen: () -> Unit = {}, - onDismissSignUp: () -> Unit = {}, -) { - SocialSignupMethodScreen( - modifier = modifier, - onDismissSignUp = onDismissSignUp, - navigateToSignupScreen = navigateToSignupScreen, - ) -} - -@Composable -@Suppress("NestedBlockDepth") -private fun SocialSignupMethodScreen( - modifier: Modifier = Modifier, - onDismissSignUp: () -> Unit = {}, - navigateToSignupScreen: () -> Unit = {}, -) { - val context = LocalContext.current - var mifosSavingProductId by remember { mutableIntStateOf(0) } - var showProgress by remember { mutableStateOf(false) } - - val credentialManager = CredentialManager.create(context) - val coroutineScope = rememberCoroutineScope() - var showFilterByAuthorizedAccounts by rememberSaveable { mutableStateOf(false) } - var googleIdTokenCredential by remember { mutableStateOf(null) } - - val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder() - .setFilterByAuthorizedAccounts(false) - .setServerClientId("728434912738-ea88f1thgvhi9058o23dbtp3p0555m32.apps.googleusercontent.com") - .build() - - val request: GetCredentialRequest = GetCredentialRequest.Builder() - .addCredentialOption(googleIdOption) - .build() - - fun signUpWithMifos() { - googleIdTokenCredential.signUpWithMifos(context, mifosSavingProductId) { - coroutineScope.launch { - credentialManager.clearCredentialState(ClearCredentialStateRequest()) - } - onDismissSignUp.invoke() - } - } - - fun handleSignIn(result: GetCredentialResponse) { - // Handle the successfully returned credential. - when (val credential = result.credential) { - is CustomCredential -> { - if (credential.type == GoogleIdTokenCredential.TYPE_GOOGLE_ID_TOKEN_CREDENTIAL) { - try { - googleIdTokenCredential = - GoogleIdTokenCredential.createFrom(credential.data) - googleIdTokenCredential?.let { - signUpWithMifos() - } ?: { - Toast.makeText( - context, - Constants.GOOGLE_SIGN_IN_FAILED, - Toast.LENGTH_SHORT, - ).show() - } - } catch (e: GoogleIdTokenParsingException) { - Log.e(TAG, "Received an invalid google id token response", e) - } - } else { - // Catch any unrecognized custom credential type here. - Log.e(TAG, "Unexpected type of credential") - } - } - - else -> { - // Catch any unrecognized credential type here. - Log.e(TAG, "Unexpected type of credential") - } - } - } - - fun signUpCredentialManager() { - coroutineScope.launch { - try { - val result = credentialManager.getCredential( - request = request, - context = context, - ) - handleSignIn(result) - } catch (e: GetCredentialException) { - showFilterByAuthorizedAccounts = false - Log.e(TAG, e.message.toString()) - // handleFailure(e) - } - } - } - - fun signUp(checkedGoogleAccount: Boolean) { - if (checkedGoogleAccount) { - signUpCredentialManager() - } else { - signUpWithMifos() - } - showProgress = true - } - - MifosBottomSheet( - modifier = modifier, - content = { - SignupMethodContentScreen( - showProgress = showProgress, - onSignUpAsMerchant = { checkedGoogleAccount -> - mifosSavingProductId = MIFOS_MERCHANT_SAVINGS_PRODUCT_ID - signUp(checkedGoogleAccount) - }, - onSignupAsCustomer = { checkedGoogleAccount -> - mifosSavingProductId = MIFOS_CONSUMER_SAVINGS_PRODUCT_ID - signUp(checkedGoogleAccount) - }, - navigateToSignupScreen = navigateToSignupScreen, - ) - }, - onDismiss = { - onDismissSignUp.invoke() - }, - ) -} - -@Composable -@Suppress("LongMethod") -private fun SignupMethodContentScreen( - showProgress: Boolean, - onSignUpAsMerchant: (Boolean) -> Unit, - onSignupAsCustomer: (Boolean) -> Unit, - modifier: Modifier = Modifier, - navigateToSignupScreen: () -> Unit = {}, -) { - var checkedGoogleAccountState by remember { mutableStateOf(true) } - - Box( - modifier = modifier, - ) { - Column( - modifier = Modifier - .fillMaxSize() - .background(color = MaterialTheme.colorScheme.surface), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Text( - modifier = Modifier.padding(top = 16.dp), - text = stringResource(id = R.string.feature_auth_create_an_account), - ) - MifosOutlinedButton( - modifier = Modifier.padding(top = 48.dp), - onClick = { - if (checkedGoogleAccountState) { - onSignUpAsMerchant.invoke(checkedGoogleAccountState) - } else { - navigateToSignupScreen.invoke() - } - }, - border = BorderStroke(1.dp, Color.LightGray), - shape = RoundedCornerShape(4.dp), - colors = ButtonDefaults.outlinedButtonColors( - contentColor = MaterialTheme.colorScheme.primary, - ), - ) { - Text( - text = stringResource(id = R.string.feature_auth_sign_up_as_merchant).uppercase(), - style = MaterialTheme.typography.labelMedium, - ) - } - Row( - modifier = Modifier - .fillMaxWidth() - .padding(top = 24.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - HorizontalDivider( - modifier = Modifier - .padding(start = 24.dp, end = 8.dp) - .weight(.4f), - thickness = 1.dp, - ) - Text( - modifier = Modifier - .wrapContentWidth() - .weight(.1f), - text = stringResource(id = R.string.feature_auth_or), - ) - HorizontalDivider( - modifier = Modifier - .padding(start = 8.dp, end = 24.dp) - .weight(.4f), - thickness = 1.dp, - ) - } - MifosOutlinedButton( - modifier = Modifier.padding(top = 24.dp), - onClick = { - if (checkedGoogleAccountState) { - onSignupAsCustomer.invoke(checkedGoogleAccountState) - } else { - navigateToSignupScreen.invoke() - } - }, - border = BorderStroke(1.dp, Color.LightGray), - shape = RoundedCornerShape(4.dp), - colors = ButtonDefaults.outlinedButtonColors( - contentColor = MaterialTheme.colorScheme.primary, - ), - ) { - Text( - text = stringResource(id = R.string.feature_auth_sign_up_as_customer).uppercase(), - style = MaterialTheme.typography.labelMedium, - ) - } - Row( - modifier = Modifier - .padding(top = 24.dp, start = 16.dp, end = 16.dp) - .clickable { - checkedGoogleAccountState = !checkedGoogleAccountState - }, - verticalAlignment = Alignment.CenterVertically, - ) { - Checkbox( - checked = checkedGoogleAccountState, - onCheckedChange = { - checkedGoogleAccountState = !checkedGoogleAccountState - }, - colors = CheckboxDefaults.colors(MaterialTheme.colorScheme.primary), - ) - Text( - text = stringResource(id = R.string.feature_auth_ease_my_sign_up_using_google_account), - style = MaterialTheme.typography.labelSmall, - ) - } - HorizontalDivider(thickness = 48.dp, color = Color.Transparent) - } - if (showProgress) { - Box( - modifier = Modifier - .fillMaxWidth() - .padding(top = 140.dp), - contentAlignment = Alignment.Center, - ) { - CircularProgressIndicator( - modifier = Modifier.size(64.dp), - color = Color.Black, - trackColor = MaterialTheme.colorScheme.surfaceVariant, - ) - } - } - } -} - -@Suppress("UnusedParameter") -private fun GoogleIdTokenCredential?.signUpWithMifos( - context: Context, - mifosSavingsProductId: Int, - signOutGoogleClient: () -> Unit, -) { - val googleIdTokenCredential = this - // Todo:navigate to MobileVerificationScreen with googleIdTokenCredential.givenName,profilePictureUri, - // familyName,mifosSavingsProductId,displayName,data.getString("com.google.android.libraries.identity.googleid.BUNDLE_KEY_ID") - signOutGoogleClient.invoke() -} - -@Preview -@Composable -private fun SignupMethodContentScreenPreview() { - MifosTheme { - SignupMethodContentScreen( - showProgress = true, - onSignUpAsMerchant = {}, - onSignupAsCustomer = {}, - ) - } -} diff --git a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/utils/ValidateUtil.kt b/feature/auth/src/main/kotlin/org/mifospay/feature/auth/utils/ValidateUtil.kt deleted file mode 100644 index 543bead45..000000000 --- a/feature/auth/src/main/kotlin/org/mifospay/feature/auth/utils/ValidateUtil.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.feature.auth.utils - -import android.util.Patterns - -object ValidateUtil { - fun String.isValidEmail() = this.isNotEmpty() && Patterns.EMAIL_ADDRESS.matcher(this).matches() -} diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt index 2fafcf592..ae6028573 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCDescriptionViewModel.kt @@ -11,7 +11,6 @@ package org.mifospay.feature.kyc import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import org.mifospay.core.model.entity.kyc.KYCLevel1Details import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow @@ -21,6 +20,7 @@ import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.kyc.FetchKYCLevel1Details import org.mifospay.core.data.repository.local.LocalRepository +import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.mifospay.feature.kyc.KYCDescriptionUiState.Loading class KYCDescriptionViewModel( @@ -74,7 +74,7 @@ class KYCDescriptionViewModel( } sealed interface KYCDescriptionUiState { - data class KYCDescription(val kycLevel1Details: org.mifospay.core.model.entity.kyc.KYCLevel1Details?) : KYCDescriptionUiState + data class KYCDescription(val kycLevel1Details: KYCLevel1Details?) : KYCDescriptionUiState data object Error : KYCDescriptionUiState data object Loading : KYCDescriptionUiState } diff --git a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt index e55a6d61b..aaa456791 100644 --- a/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt +++ b/feature/kyc/src/main/kotlin/org/mifospay/feature/kyc/KYCLevel1ViewModel.kt @@ -10,13 +10,13 @@ package org.mifospay.feature.kyc import androidx.lifecycle.ViewModel -import org.mifospay.core.model.entity.kyc.KYCLevel1Details import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.mifospay.core.data.base.UseCase import org.mifospay.core.data.base.UseCaseHandler import org.mifospay.core.data.domain.usecase.kyc.UploadKYCLevel1Details import org.mifospay.core.data.repository.local.LocalRepository +import org.mifospay.core.model.entity.kyc.KYCLevel1Details import org.mifospay.feature.kyc.KYCLevel1UiState.Loading class KYCLevel1ViewModel( diff --git a/gradle.properties b/gradle.properties index 79d506e00..577ab461e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -47,6 +47,7 @@ kotlin.code.style=official android.defaults.buildfeatures.resvalues=false android.defaults.buildfeatures.shaders=false android.testOptions.unitTests.isIncludeAndroidResources = true +org.jetbrains.compose.experimental.jscanvas.enabled=true RblClientIdProp=a RblClientSecretProp=b diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fa9c118ff..d75f55986 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,7 +15,7 @@ androidxCoreSplashscreen = "1.0.1" androidxDataStore = "1.1.1" androidxLifecycle = "2.8.6" androidxMetrics = "1.0.0-beta01" -androidxNavigation = "2.8.1" +androidxNavigation = "2.8.2" androidxProfileinstaller = "1.4.0" androidxTracing = "1.3.0-alpha02" appcompatVersion = "1.7.0" @@ -24,9 +24,9 @@ cameraLifecycleVersion = "1.3.4" cameraViewVersion = "1.3.4" coil = "3.0.0-alpha10" compileSdk = "34" -compose-plugin = "1.6.11" +compose-plugin = "1.7.0-rc01" coreKtxVersion = "1.13.1" -credentialsVersion = "1.2.2" +credentialsVersion = "1.3.0" datastore = "1.1.1" dependencyGuard = "0.5.0" detekt = "1.23.7" @@ -46,15 +46,14 @@ koinAnnotationsVersion = "1.4.0-RC4" koinComposeMultiplatform = "1.2.0-Beta4" kotlin = "2.0.20" kotlinInject = "0.7.2" -kotlinStdlibVersion = "2.0.20" kotlinxCoroutines = "1.9.0" -kotlinxDatetime = "0.6.0" +kotlinxDatetime = "0.6.1" kotlinxImmutable = "0.3.8" kotlinxSerializationJson = "1.7.2" kotlinxSerializationJsonVersion = "1.3.0" -ksp = "2.0.20-1.0.24" +ksp = "2.0.20-1.0.25" ktlint = "12.1.1" -ktorVersion = "2.3.4" +ktorVersion = "3.0.0-rc-1" ktorfit = "2.1.0" ktorfitKsp = "2.1.0-1.0.25" libphonenumberAndroidVersion = "8.13.35" @@ -77,6 +76,7 @@ roborazzi = "1.26.0" room = "2.6.1" rxandroidVersion = "1.1.0" rxjavaVersion = "1.3.8" +sandwichVersion = "2.0.9" secrets = "2.0.1" sheets_compose_dialogs_core = "1.3.0" spotlessVersion = "6.25.0" @@ -87,29 +87,46 @@ uiDesktopVersion = "1.7.0" versionCatalogLinterVersion = "1.0.3" wire = "5.0.0" zxingVersion = "3.5.3" +lifecycle-viewmodel-compose = "2.8.2" +navigation-compose = "2.8.0-alpha02" +windowsSizeClass="0.5.0" + +composeJB = "1.7.0-rc01" +composeLifecycle = "2.8.2" +composeJetpackRuntime = "1.6.8" +composeNavigation = "2.8.0-alpha10" +jbCoreBundle = "1.0.1" +jbSavedState = "1.2.2" [libraries] accompanist-pager = { group = "com.google.accompanist", name = "accompanist-pager", version.ref = "accompanistPagerVersion" } + android-desugarJdkLibs = { group = "com.android.tools", name = "desugar_jdk_libs", version.ref = "androidDesugarJdkLibs" } android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "androidGradlePlugin" } android-tools-common = { group = "com.android.tools", name = "common", version.ref = "androidTools" } + androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidxActivity" } androidx-activity-ktx = { group = "androidx.activity", name = "activity-ktx", version.ref = "activityVersion" } + androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompatVersion" } androidx-browser = { group = "androidx.browser", name = "browser", version.ref = "androidxBrowser" } + androidx-camera-lifecycle = { group = "androidx.camera", name = "camera-lifecycle", version.ref = "cameraLifecycleVersion" } androidx-camera-view = { group = "androidx.camera", name = "camera-view", version.ref = "cameraViewVersion" } + androidx-compose-animation = { group = "androidx.compose.animation", name = "animation" } androidx-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "androidxComposeBom" } androidx-compose-compiler = { group = "androidx.compose.compiler", name = "compiler", version.ref = "androidxComposeCompiler" } androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" } androidx-compose-foundation-layout = { group = "androidx.compose.foundation", name = "foundation-layout" } + androidx-compose-material-iconsExtended = { group = "androidx.compose.material", name = "material-icons-extended" } androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } androidx-compose-material3-adaptive = { group = "androidx.compose.material3.adaptive", name = "adaptive", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-adaptive-layout = { group = "androidx.compose.material3.adaptive", name = "adaptive-layout", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-adaptive-navigation = { group = "androidx.compose.material3.adaptive", name = "adaptive-navigation", version.ref = "androidxComposeMaterial3Adaptive" } androidx-compose-material3-windowSizeClass = { group = "androidx.compose.material3", name = "material3-window-size-class" } + androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime" } androidx-compose-runtime-tracing = { group = "androidx.compose.runtime", name = "runtime-tracing", version.ref = "androidxComposeRuntimeTracing" } androidx-compose-ui = { group = "androidx.compose.ui", name = "ui" } @@ -118,35 +135,52 @@ androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui- androidx-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" } androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" } androidx-compose-ui-util = { group = "androidx.compose.ui", name = "ui-util" } + androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtxVersion" } + androidx-core-splashscreen = { group = "androidx.core", name = "core-splashscreen", version.ref = "androidxCoreSplashscreen" } + androidx-credentials = { group = "androidx.credentials", name = "credentials", version.ref = "credentialsVersion" } androidx-credentials-play-services-auth = { group = "androidx.credentials", name = "credentials-play-services-auth", version.ref = "credentialsVersion" } + androidx-dataStore-core = { group = "androidx.datastore", name = "datastore", version.ref = "androidxDataStore" } + androidx-lifecycle-extensions = { group = "androidx.lifecycle", name = "lifecycle-extensions", version.ref = "lifecycleExtensionsVersion" } androidx-lifecycle-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleVersion" } androidx-lifecycle-runtimeCompose = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidxLifecycle" } +androidx-lifecycle-process = { group = "androidx.lifecycle", name = "lifecycle-process", version.ref = "androidxLifecycle" } androidx-lifecycle-runtimeTesting = { group = "androidx.lifecycle", name = "lifecycle-runtime-testing", version.ref = "androidxLifecycle" } androidx-lifecycle-viewModelCompose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "androidxLifecycle" } + androidx-metrics = { group = "androidx.metrics", name = "metrics-performance", version.ref = "androidxMetrics" } + androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "androidxNavigation" } androidx-navigation-testing = { group = "androidx.navigation", name = "navigation-testing", version.ref = "androidxNavigation" } + androidx-profileinstaller = { group = "androidx.profileinstaller", name = "profileinstaller", version.ref = "androidxProfileinstaller" } + androidx-test-ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-ext-junit" } androidx-tracing-ktx = { group = "androidx.tracing", name = "tracing-ktx", version.ref = "androidxTracing" } + androidx-ui-desktop = { group = "androidx.compose.ui", name = "ui-desktop", version.ref = "uiDesktopVersion" } + back-handler= {group="com.arkivanov.essenty", name="back-handler",version.ref="backHandlerVersion"} + coil-core = { group = "io.coil-kt.coil3", name = "coil-core", version.ref = "coil" } coil-kt = { group = "io.coil-kt.coil3", name = "coil", version.ref = "coil" } coil-kt-compose = { group = "io.coil-kt.coil3", name = "coil-compose-core", version.ref = "coil" } coil-network-ktor = { group = "io.coil-kt.coil3", name = "coil-network-ktor3", version.ref = "coil" } coil-svg = { group = "io.coil-kt.coil3", name = "coil-svg", version.ref = "coil" } + compose-gradlePlugin = { group = "org.jetbrains.kotlin", name = "compose-compiler-gradle-plugin", version.ref = "kotlin" } + datastore = { group = "androidx.datastore", name = "datastore-core-okio", version.ref = "datastore" } + detekt-formatting = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" } detekt-gradlePlugin = { group = "io.gitlab.arturbosch.detekt", name = "detekt-gradle-plugin", version.ref = "detekt" } -espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" } -fineract-sdk = { group = "com.github.openMF", name = "mifos-android-sdk-arch", version.ref = "fineractSdk" } +twitter-detekt-compose = { group = "com.twitter.compose.rules", name = "detekt", version.ref = "twitter-detekt-compose" } + + firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics-ktx" } firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" } firebase-cloud-messaging = { group = "com.google.firebase", name = "firebase-messaging-ktx" } @@ -154,14 +188,30 @@ firebase-crashlytics = { group = "com.google.firebase", name = "firebase-crashly firebase-crashlytics-gradlePlugin = { group = "com.google.firebase", name = "firebase-crashlytics-gradle", version.ref = "firebaseCrashlyticsPlugin" } firebase-performance = { group = "com.google.firebase", name = "firebase-perf-ktx" } firebase-performance-gradlePlugin = { group = "com.google.firebase", name = "perf-plugin", version.ref = "firebasePerfPlugin" } + google-oss-licenses = { group = "com.google.android.gms", name = "play-services-oss-licenses", version.ref = "googleOss" } google-oss-licenses-plugin = { group = "com.google.android.gms", name = "oss-licenses-plugin", version.ref = "googleOssPlugin" } google-play-services-code-scanner = { group = "com.google.android.gms", name = "play-services-code-scanner", version.ref = "playServicesCodeScanner" } googleid = { group = "com.google.android.libraries.identity.googleid", name = "googleid", version.ref = "googleidVersion" } -jetbrains-kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlinStdlibVersion" } + +# jb Compose +jb-kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib", version.ref = "kotlin" } +jb-kotlin-stdlib-js = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-js", version.ref = "kotlin" } +jb-kotlin-dom = { group = "org.jetbrains.kotlin", name = "kotlin-dom-api-compat", version.ref = "kotlin" } +jb-composeRuntime = { module = "org.jetbrains.compose.runtime:runtime", version.ref = "composeJB" } +jb-composeViewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "composeLifecycle" } +jb-lifecycleViewmodel = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel", version.ref = "composeLifecycle" } +jb-lifecycleViewmodelSavedState = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate", version.ref = "composeLifecycle" } +jb-bundle = { module = "org.jetbrains.androidx.core:core-bundle", version.ref = "jbCoreBundle" } +jb-savedstate = { module = "org.jetbrains.androidx.savedstate:savedstate", version.ref = "jbSavedState" } +jb-composeNavigation = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "composeNavigation" } +jb-navigation = { module = "org.jetbrains.androidx.navigation:navigation-common", version.ref = "composeNavigation" } + junit = { group = "junit", name = "junit", version.ref = "junitVersion" } + kermit-logging = { group = "co.touchlab", name = "kermit", version.ref = "kermit" } kermit-simple = { group = "co.touchlab", name = "kermit-simple", version.ref = "kermit" } + koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" } koin-androidx-compose = { group = "io.insert-koin", name = "koin-androidx-compose", version.ref = "koin" } koin-androidx-navigation = { group = "io.insert-koin", name = "koin-androidx-navigation", version.ref = "koin" } @@ -169,33 +219,42 @@ koin-annotations = { group = "io.insert-koin", name = "koin-annotations", versio koin-bom = { group = "io.insert-koin", name = "koin-bom", version.ref = "koin" } koin-compose = { group = "io.insert-koin", name = "koin-compose", version.ref = "koinComposeMultiplatform" } koin-compose-viewmodel = { group = "io.insert-koin", name = "koin-compose-viewmodel", version.ref = "koinComposeMultiplatform" } +koin-compose-navigation = { group = "io.insert-koin", name = "koin-compose-viewmodel-navigation", version.ref = "koinComposeMultiplatform" } koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" } koin-core-viewmodel = { group = "io.insert-koin", name = "koin-core-viewmodel", version.ref = "koin" } koin-ksp-compiler = { group = "io.insert-koin", name = "koin-ksp-compiler", version.ref = "koinAnnotationsVersion" } koin-test = { group = "io.insert-koin", name = "koin-test", version.ref = "koin" } koin-test-junit4 = { group = "io.insert-koin", name = "koin-test-junit4", version.ref = "koin" } koin-test-junit5 = { group = "io.insert-koin", name = "koin-test-junit5", version.ref = "koin" } + kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" } kotlin-inject-compiler-ksp = { group = "me.tatarka.inject", name = "kotlin-inject-compiler-ksp", version.ref = "kotlinInject" } kotlin-inject-runtime = { group = "me.tatarka.inject", name = "kotlin-inject-runtime", version.ref = "kotlinInject" } kotlin-inject-runtime-kmp = { group = "me.tatarka.inject", name = "kotlin-inject-runtime-kmp", version.ref = "kotlinInject" } kotlin-stdlib = { group = "org.jetbrains.kotlin", name = "kotlin-stdlib-jdk8", version.ref = "kotlin" } +kotlin-reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin" } kotlin-test = { group = "org.jetbrains.kotlin", name = "kotlin-test", version.ref = "kotlin" } + kotlinx-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinxImmutable" } kotlinx-coroutines-android = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } +kotlinx-coroutines-swing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "kotlinxCoroutines" } kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutines" } kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" } kotlinx-serialization-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-core", version.ref = "kotlinxSerializationJson" } kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } + ksp-gradlePlugin = { group = "com.google.devtools.ksp", name = "com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } + ktlint-gradlePlugin = { group = "org.jlleitschuh.gradle", name = "ktlint-gradle", version.ref = "ktlint" } + ktor-client-android = { group = "io.ktor", name = "ktor-client-android", version.ref = "ktorVersion" } ktor-client-auth = { group = "io.ktor", name = "ktor-client-auth", version.ref = "ktorVersion" } ktor-client-cio = { group = "io.ktor", name = "ktor-client-cio", version.ref = "ktorVersion" } ktor-client-content-negotiation = { group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktorVersion" } ktor-client-core = { group = "io.ktor", name = "ktor-client-core", version.ref = "ktorVersion" } ktor-client-darwin = { group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktorVersion" } +ktor-client-okhttp = { group = "io.ktor", name = "ktor-client-okhttp", version.ref = "ktorVersion" } ktor-client-java = { group = "io.ktor", name = "ktor-client-java", version.ref = "ktorVersion" } ktor-client-js = { group = "io.ktor", name = "ktor-client-js", version.ref = "ktorVersion" } ktor-client-json = { group = "io.ktor", name = "ktor-client-json", version.ref = "ktorVersion" } @@ -204,41 +263,61 @@ ktor-client-serialization = { group = "io.ktor", name = "ktor-client-serializati ktor-client-websockets = { group = "io.ktor", name = "ktor-client-websockets", version.ref = "ktorVersion" } ktor-client-winhttp = { group = "io.ktor", name = "ktor-client-winhttp", version.ref = "ktorVersion" } ktor-serialization-kotlinx-json = { group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktorVersion" } +ktor-server-auth = { group = "io.ktor", name = "ktor-server-auth", version.ref = "ktorVersion" } + ktorfit-converters-call = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-converters-call", version.ref = "ktorfit" } ktorfit-converters-flow = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-converters-flow", version.ref = "ktorfit" } ktorfit-ksp = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-ksp", version.ref = "ktorfitKsp" } -ktorfit-lib = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-lib", version.ref = "ktorfit" } +ktorfit-lib = { group = "de.jensklingenberg.ktorfit", name = "ktorfit-lib-ktor-3.0.0-beta-2", version.ref = "ktorfit" } + libphonenumber-android = { group = "io.michaelrocks", name = "libphonenumber-android", version.ref = "libphonenumberAndroidVersion" } + lint-api = { group = "com.android.tools.lint", name = "lint-api", version.ref = "androidTools" } lint-checks = { group = "com.android.tools.lint", name = "lint-checks", version.ref = "androidTools" } lint-tests = { group = "com.android.tools.lint", name = "lint-tests", version.ref = "androidTools" } + logback-classic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logbackClassicVersion" } + multiplatform-settings = { group = "com.russhwolf", name = "multiplatform-settings-no-arg", version.ref = "multiplatformSettings" } multiplatform-settings-coroutines = { group = "com.russhwolf", name = "multiplatform-settings-coroutines", version.ref = "multiplatformSettings" } multiplatform-settings-serialization = { group = "com.russhwolf", name = "multiplatform-settings-serialization", version.ref = "multiplatformSettings" } multiplatform-settings-test = { group = "com.russhwolf", name = "multiplatform-settings-test", version.ref = "multiplatformSettings" } + moko-permission = {group="dev.icerock.moko", name="permissions", version.ref="mokoPermission"} moko-permission-compose = {group="dev.icerock.moko", name="permissions-compose", version.ref="mokoPermission"} + play-services-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "playServicesAuthVersion" } + protobuf-kotlin-lite = { group = "com.google.protobuf", name = "protobuf-kotlin-lite", version.ref = "protobuf" } protobuf-protoc = { group = "com.google.protobuf", name = "protoc", version.ref = "protobuf" } -reactivex-rxjava = { group = "io.reactivex", name = "rxjava", version.ref = "rxjavaVersion" } -reactivex-rxjava-android = { group = "io.reactivex", name = "rxandroid", version.ref = "rxandroidVersion" } -retrofit-kotlin-serialization = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "retrofitKotlinxSerializationJson" } + room-gradlePlugin = { group = "androidx.room", name = "room-gradle-plugin", version.ref = "room" } + +sandwich = { module = "com.github.skydoves:sandwich", version.ref = "sandwichVersion" } +sandwich-ktorfit = { module = "com.github.skydoves:sandwich-ktorfit", version.ref = "sandwichVersion" } + squareup-okio = { group = "com.squareup.okio", name = "okio", version.ref = "okioVersion" } + sheets-compose-dialogs-calender = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "calendar", version.ref = "sheets_compose_dialogs_core" } sheets-compose-dialogs-core = { group = "com.maxkeppeler.sheets-compose-dialogs", name = "core", version.ref = "sheets_compose_dialogs_core" } + spotless-gradle = { group = "com.diffplug.spotless", name = "spotless-plugin-gradle", version.ref = "spotlessVersion" } + squareup-logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okHttp3Version" } squareup-okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okHttp3Version" } squareup-retrofit-adapter-rxjava = { group = "com.squareup.retrofit2", name = "adapter-rxjava", version.ref = "retrofitVersion" } squareup-retrofit-converter-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofitVersion" } squareup-retrofit2 = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofitVersion" } + truth = { group = "com.google.truth", name = "truth", version.ref = "truth" } -twitter-detekt-compose = { group = "com.twitter.compose.rules", name = "detekt", version.ref = "twitter-detekt-compose" } +espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-core" } + zxing = { group = "com.google.zxing", name = "core", version.ref = "zxingVersion" } + fineract-api = { group = "io.github.niyajali", name = "fineract-client-kmp", version.ref = "fineractSdk" } +fineract-sdk = { group = "com.github.openMF", name = "mifos-android-sdk-arch", version.ref = "fineractSdk" } + +window-size = {group="dev.chrisbanes.material3",name="material3-window-size-class-multiplatform",version.ref="windowsSizeClass"} [bundles] androidx-compose-ui-test = [ diff --git a/kotlin-js-store/yarn.lock b/kotlin-js-store/yarn.lock new file mode 100644 index 000000000..4a3dfa000 --- /dev/null +++ b/kotlin-js-store/yarn.lock @@ -0,0 +1,2882 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@discoveryjs/json-ext@^0.5.0": + version "0.5.7" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" + integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@js-joda/core@3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@js-joda/core/-/core-3.2.0.tgz#3e61e21b7b2b8a6be746df1335cf91d70db2a273" + integrity sha512-PMqgJ0sw5B7FKb2d5bWYIoxjri+QlW/Pys7+Rw82jSH0QN3rB05jZ/VrrsUdh1w4+i2kw9JOejXGq/KhDOX7Kg== + +"@leichtgewicht/ip-codec@^2.0.1": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1" + integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw== + +"@socket.io/component-emitter@~3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz#821f8442f4175d8f0467b9daf26e3a18e2d02af2" + integrity sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA== + +"@types/body-parser@*": + version "1.19.5" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/bonjour@^3.5.9": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.13.tgz#adf90ce1a105e81dd1f9c61fdc5afda1bfb92956" + integrity sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ== + dependencies: + "@types/node" "*" + +"@types/connect-history-api-fallback@^1.3.5": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz#7de71645a103056b48ac3ce07b3520b819c1d5b3" + integrity sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw== + dependencies: + "@types/express-serve-static-core" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/cookie@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" + integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== + +"@types/cors@^2.8.12": + version "2.8.17" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" + integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA== + dependencies: + "@types/node" "*" + +"@types/eslint-scope@^3.7.3": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.1.tgz#d5795ad732ce81715f27f75da913004a56751584" + integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@^1.0.5": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.0.tgz#91f06cda1049e8f17eeab364798ed79c97488a1c" + integrity sha512-AbXMTZGt40T+KON9/Fdxx0B2WK5hsgxcfXJLr5bFpZ7b4JCex2WyQPTEKdXqfHiY5nKKBScZ7yCoO6Pvgxfvnw== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express-serve-static-core@^4.17.33": + version "4.19.6" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz#e01324c2a024ff367d92c66f48553ced0ab50267" + integrity sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@*": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.0.tgz#13a7d1f75295e90d19ed6e74cab3678488eaa96c" + integrity sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^5.0.0" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/express@^4.17.13": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/http-errors@*": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== + +"@types/http-proxy@^1.17.8": + version "1.17.15" + resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36" + integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ== + dependencies: + "@types/node" "*" + +"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + +"@types/node-forge@^1.3.0": + version "1.3.11" + resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da" + integrity sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ== + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@>=10.0.0": + version "22.7.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.4.tgz#e35d6f48dca3255ce44256ddc05dee1c23353fcc" + integrity sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg== + dependencies: + undici-types "~6.19.2" + +"@types/qs@*": + version "6.9.16" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.16.tgz#52bba125a07c0482d26747d5d4947a64daf8f794" + integrity sha512-7i+zxXdPD0T4cKDuxCUXJ4wHcsJLwENa6Z3dCu8cfCK743OGy5Nu1RmAGqDPsoTDINVEcdXKRvR/zre+P2Ku1A== + +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/send@*": + version "0.17.4" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-index@^1.9.1": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.4.tgz#e6ae13d5053cb06ed36392110b4f9a49ac4ec898" + integrity sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug== + dependencies: + "@types/express" "*" + +"@types/serve-static@*", "@types/serve-static@^1.13.10": + version "1.15.7" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@types/send" "*" + +"@types/sockjs@^0.3.33": + version "0.3.36" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.36.tgz#ce322cf07bcc119d4cbf7f88954f3a3bd0f67535" + integrity sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q== + dependencies: + "@types/node" "*" + +"@types/ws@^8.5.5": + version "8.5.12" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.12.tgz#619475fe98f35ccca2a2f6c137702d85ec247b7e" + integrity sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ== + dependencies: + "@types/node" "*" + +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" + integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== + dependencies: + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== + +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== + +"@webassemblyjs/helper-buffer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" + integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== + +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== + +"@webassemblyjs/helper-wasm-section@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" + integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.12.1" + +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + +"@webassemblyjs/wasm-gen@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" + integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" + integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" + integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" + integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-2.1.1.tgz#3b2f852e91dac6e3b85fb2a314fb8bef46d94646" + integrity sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw== + +"@webpack-cli/info@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-2.0.2.tgz#cc3fbf22efeb88ff62310cf885c5b09f44ae0fdd" + integrity sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A== + +"@webpack-cli/serve@^2.0.5": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-2.0.5.tgz#325db42395cd49fe6c14057f9a900e427df8810e" + integrity sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +abort-controller@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + +accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== + +acorn@^8.7.1, acorn@^8.8.2: + version "8.12.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248" + integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^3.5.2: + version "3.5.2" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== + +ajv-keywords@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.12.5: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.9.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-html-community@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" + integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64id@2.0.0, base64id@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" + integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== + +batch@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" + integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +body-parser@1.20.3, body-parser@^1.19.0: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.13.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +bonjour-service@^1.0.11: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.2.1.tgz#eb41b3085183df3321da1264719fbada12478d02" + integrity sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw== + dependencies: + fast-deep-equal "^3.1.3" + multicast-dns "^7.2.5" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browser-stdout@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +browserslist@^4.21.10: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== + dependencies: + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001663: + version "1.0.30001667" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" + integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^3.5.1, chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chrome-trace-event@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" + integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.10, colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +connect-history-api-fallback@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" + integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== + +connect@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" + integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== + dependencies: + debug "2.6.9" + finalhandler "1.1.2" + parseurl "~1.3.3" + utils-merge "1.0.1" + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +cookie@~0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cors@~2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +custom-event@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" + integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg== + +date-format@^4.0.14: + version "4.0.14" + resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.14.tgz#7a8e584434fb169a521c8b7aa481f355810d9400" + integrity sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.1.0, debug@^4.3.4, debug@^4.3.5, debug@~4.3.1, debug@~4.3.2, debug@~4.3.4: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +default-gateway@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" + integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== + dependencies: + execa "^5.0.0" + +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-node@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + +di@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" + integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA== + +diff@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== + +dns-packet@^5.2.2: + version "5.6.1" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.1.tgz#ae888ad425a9d1478a0674256ab866de1012cf2f" + integrity sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + +dom-serialize@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" + integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ== + dependencies: + custom-event "~1.0.0" + ent "~2.2.0" + extend "^3.0.0" + void-elements "^2.0.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.5.28: + version "1.5.32" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.32.tgz#4a05ee78e29e240aabaf73a67ce9fe73f52e1bc7" + integrity sha512-M+7ph0VGBQqqpTT2YrabjNKSQ2fEl9PVx6AK3N558gDH9NO8O6XN9SXXFWRo9u9PbEg/bWq+tjXQr+eXmxubCw== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +engine.io-parser@~5.2.1: + version "5.2.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f" + integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q== + +engine.io@~6.6.0: + version "6.6.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.6.1.tgz#a82b1e5511239a0e95fac14516870ee9138febc8" + integrity sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og== + dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" + accepts "~1.3.4" + base64id "2.0.0" + cookie "~0.4.1" + cors "~2.8.5" + debug "~4.3.1" + engine.io-parser "~5.2.1" + ws "~8.17.1" + +enhanced-resolve@^5.17.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +ent@~2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.1.tgz#68dc99a002f115792c26239baedaaea9e70c0ca2" + integrity sha512-QHuXVeZx9d+tIQAz/XztU0ZwZf2Agg9CcXcgE1rurqvdBeDBrpSwjl8/6XUqMg7tw2Y7uAdKb2sRv+bSEFqQ5A== + dependencies: + punycode "^1.4.1" + +envinfo@^7.7.3: + version "7.14.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.14.0.tgz#26dac5db54418f2a4c1159153a0b2ae980838aae" + integrity sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg== + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-module-lexer@^1.2.1: + version "1.5.4" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78" + integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw== + +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +express@^4.17.3: + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.3" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.6.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~2.0.0" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.3.1" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.3" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.10" + proxy-addr "~2.0.7" + qs "6.13.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.19.0" + serve-static "1.16.2" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +extend@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-uri@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.2.tgz#d78b298cf70fd3b752fd951175a3da6a7b48f024" + integrity sha512-GR6f0hD7XXyNJa25Tb9BuIdN0tdr+0BMi6/CJPH3wJO1JjNG3n/VsSw38AwRdKZABm8lGbPfakLRkYzx2V9row== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +faye-websocket@^0.11.3: + version "0.11.4" + resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" + integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== + dependencies: + websocket-driver ">=0.5.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + statuses "~1.5.0" + unpipe "~1.0.0" + +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== + dependencies: + debug "2.6.9" + encodeurl "~2.0.0" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.2.7: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +follow-redirects@^1.0.0: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + +format-util@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" + integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-extra@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + +fs-monkey@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.6.tgz#8ead082953e88d992cf3ff844faa907b26756da2" + integrity sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^7.1.3, glob@^7.1.7: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +hasown@^2.0.0, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hpack.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" + integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== + dependencies: + inherits "^2.0.1" + obuf "^1.0.0" + readable-stream "^2.0.1" + wbuf "^1.1.0" + +html-entities@^2.3.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" + integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== + +http-deceiver@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" + integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + +http-parser-js@>=0.5.1: + version "0.5.8" + resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" + integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== + +http-proxy-middleware@^2.0.3: + version "2.0.7" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz#915f236d92ae98ef48278a95dedf17e991936ec6" + integrity sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA== + dependencies: + "@types/http-proxy" "^1.17.8" + http-proxy "^1.18.1" + is-glob "^4.0.1" + is-plain-obj "^3.0.0" + micromatch "^4.0.2" + +http-proxy@^1.18.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" + integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== + dependencies: + eventemitter3 "^4.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +ipaddr.js@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" + integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + dependencies: + hasown "^2.0.2" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-obj@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" + integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isbinaryfile@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" + integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg== + optionalDependencies: + graceful-fs "^4.1.6" + +karma-chrome-launcher@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz#eb9c95024f2d6dfbb3748d3415ac9b381906b9a9" + integrity sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q== + dependencies: + which "^1.2.1" + +karma-mocha@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d" + integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ== + dependencies: + minimist "^1.2.3" + +karma-sourcemap-loader@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.4.0.tgz#b01d73f8f688f533bcc8f5d273d43458e13b5488" + integrity sha512-xCRL3/pmhAYF3I6qOrcn0uhbQevitc2DERMPH82FMnG+4WReoGcGFZb1pURf2a5apyrOHRdvD+O6K7NljqKHyA== + dependencies: + graceful-fs "^4.2.10" + +karma-webpack@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.1.tgz#4eafd31bbe684a747a6e8f3e4ad373e53979ced4" + integrity sha512-oo38O+P3W2mSPCSUrQdySSPv1LvPpXP+f+bBimNomS5sW+1V4SuhCuW8TfJzV+rDv921w2fDSDw0xJbPe6U+kQ== + dependencies: + glob "^7.1.3" + minimatch "^9.0.3" + webpack-merge "^4.1.5" + +karma@6.4.3: + version "6.4.3" + resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.3.tgz#763e500f99597218bbb536de1a14acc4ceea7ce8" + integrity sha512-LuucC/RE92tJ8mlCwqEoRWXP38UMAqpnq98vktmS9SznSoUPPUJQbc91dHcxcunROvfQjdORVA/YFviH+Xci9Q== + dependencies: + "@colors/colors" "1.5.0" + body-parser "^1.19.0" + braces "^3.0.2" + chokidar "^3.5.1" + connect "^3.7.0" + di "^0.0.1" + dom-serialize "^2.2.1" + glob "^7.1.7" + graceful-fs "^4.2.6" + http-proxy "^1.18.1" + isbinaryfile "^4.0.8" + lodash "^4.17.21" + log4js "^6.4.1" + mime "^2.5.2" + minimatch "^3.0.4" + mkdirp "^0.5.5" + qjobs "^1.2.0" + range-parser "^1.2.1" + rimraf "^3.0.2" + socket.io "^4.7.2" + source-map "^0.6.1" + tmp "^0.2.1" + ua-parser-js "^0.7.30" + yargs "^16.1.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +launch-editor@^2.6.0: + version "2.9.1" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.9.1.tgz#253f173bd441e342d4344b4dae58291abb425047" + integrity sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w== + dependencies: + picocolors "^1.0.0" + shell-quote "^1.8.1" + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash@^4.17.15, lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log4js@^6.4.1: + version "6.9.1" + resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.9.1.tgz#aba5a3ff4e7872ae34f8b4c533706753709e38b6" + integrity sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + flatted "^3.2.7" + rfdc "^1.3.0" + streamroller "^3.1.5" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +memfs@^3.4.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6" + integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ== + dependencies: + fs-monkey "^1.0.4" + +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.2: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +"mime-db@>= 1.43.0 < 2": + version "1.53.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" + integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== + +mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mime@^2.5.2: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1, minimatch@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.3: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.3, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^0.5.5: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mocha@10.7.0: + version "10.7.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.7.0.tgz#9e5cbed8fa9b37537a25bd1f7fb4f6fc45458b9a" + integrity sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.3, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns@^7.2.5: + version "7.2.5" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" + integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== + dependencies: + dns-packet "^5.2.2" + thunky "^1.0.2" + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-fetch@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + +node-forge@^1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" + integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== + +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +obuf@^1.0.0, obuf@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^8.0.9: + version "8.4.2" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-retry@^4.5.0: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parseurl@~1.3.2, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== + +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +qjobs@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" + integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== + +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== + dependencies: + side-channel "^1.0.6" + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@^1.2.1, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^2.0.1: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.0.6: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.20.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +rfdc@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +schema-utils@^3.1.1, schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + +schema-utils@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" + integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + +select-hose@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" + integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== + +selfsigned@^2.1.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0" + integrity sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q== + dependencies: + "@types/node-forge" "^1.3.0" + node-forge "^1" + +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-javascript@^6.0.1, serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + +serve-index@^1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" + integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== + dependencies: + accepts "~1.3.4" + batch "0.6.1" + debug "2.6.9" + escape-html "~1.0.3" + http-errors "~1.6.2" + mime-types "~2.1.17" + parseurl "~1.3.2" + +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== + dependencies: + encodeurl "~2.0.0" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.19.0" + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setprototypeof@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" + integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shell-quote@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" + integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== + +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +socket.io-adapter@~2.5.2: + version "2.5.5" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz#c7a1f9c703d7756844751b6ff9abfc1780664082" + integrity sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg== + dependencies: + debug "~4.3.4" + ws "~8.17.1" + +socket.io-parser@~4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.2.4.tgz#c806966cf7270601e47469ddeec30fbdfda44c83" + integrity sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew== + dependencies: + "@socket.io/component-emitter" "~3.1.0" + debug "~4.3.1" + +socket.io@^4.7.2: + version "4.8.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.8.0.tgz#33d05ae0915fad1670bd0c4efcc07ccfabebe3b1" + integrity sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA== + dependencies: + accepts "~1.3.4" + base64id "~2.0.0" + cors "~2.8.5" + debug "~4.3.2" + engine.io "~6.6.0" + socket.io-adapter "~2.5.2" + socket.io-parser "~4.2.4" + +sockjs@^0.3.24: + version "0.3.24" + resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" + integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== + dependencies: + faye-websocket "^0.11.3" + uuid "^8.3.2" + websocket-driver "^0.7.4" + +source-map-js@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map-loader@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-5.0.0.tgz#f593a916e1cc54471cfc8851b905c8a845fc7e38" + integrity sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA== + dependencies: + iconv-lite "^0.6.3" + source-map-js "^1.0.2" + +source-map-support@0.5.21, source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +spdy-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" + integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== + dependencies: + debug "^4.1.0" + detect-node "^2.0.4" + hpack.js "^2.1.6" + obuf "^1.1.2" + readable-stream "^3.0.6" + wbuf "^1.7.3" + +spdy@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== + dependencies: + debug "^4.1.0" + handle-thing "^2.0.0" + http-deceiver "^1.2.7" + select-hose "^2.0.0" + spdy-transport "^3.0.0" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +"statuses@>= 1.4.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +streamroller@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.5.tgz#1263182329a45def1ffaef58d31b15d13d2ee7ff" + integrity sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw== + dependencies: + date-format "^4.0.14" + debug "^4.3.4" + fs-extra "^8.1.0" + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0, supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terser-webpack-plugin@^5.3.10: + version "5.3.10" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.20" + jest-worker "^27.4.5" + schema-utils "^3.1.1" + serialize-javascript "^6.0.1" + terser "^5.26.0" + +terser@^5.26.0: + version "5.34.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.34.1.tgz#af40386bdbe54af0d063e0670afd55c3105abeb6" + integrity sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +tmp@^0.2.1: + version "0.2.3" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" + integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@5.5.4: + version "5.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.4.tgz#d9852d6c82bad2d2eda4fd74a5762a8f5909e9ba" + integrity sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q== + +ua-parser-js@^0.7.30: + version "0.7.39" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.39.tgz#c71efb46ebeabc461c4612d22d54f88880fabe7e" + integrity sha512-IZ6acm6RhQHNibSt7+c09hhvsKy9WUr4DVbeq9U8o71qxyYtJpQeDxQnMrVqnIFMLcQjHO0I9wgfO2vIahht4w== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" + integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== + +watchpack@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" + integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +wbuf@^1.1.0, wbuf@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" + integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== + dependencies: + minimalistic-assert "^1.0.0" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +webpack-cli@5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-5.1.4.tgz#c8e046ba7eaae4911d7e71e2b25b776fcc35759b" + integrity sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg== + dependencies: + "@discoveryjs/json-ext" "^0.5.0" + "@webpack-cli/configtest" "^2.1.1" + "@webpack-cli/info" "^2.0.2" + "@webpack-cli/serve" "^2.0.5" + colorette "^2.0.14" + commander "^10.0.1" + cross-spawn "^7.0.3" + envinfo "^7.7.3" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^3.1.1" + rechoir "^0.8.0" + webpack-merge "^5.7.3" + +webpack-dev-middleware@^5.3.4: + version "5.3.4" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517" + integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q== + dependencies: + colorette "^2.0.10" + memfs "^3.4.3" + mime-types "^2.1.31" + range-parser "^1.2.1" + schema-utils "^4.0.0" + +webpack-dev-server@4.15.2: + version "4.15.2" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz#9e0c70a42a012560860adb186986da1248333173" + integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g== + dependencies: + "@types/bonjour" "^3.5.9" + "@types/connect-history-api-fallback" "^1.3.5" + "@types/express" "^4.17.13" + "@types/serve-index" "^1.9.1" + "@types/serve-static" "^1.13.10" + "@types/sockjs" "^0.3.33" + "@types/ws" "^8.5.5" + ansi-html-community "^0.0.8" + bonjour-service "^1.0.11" + chokidar "^3.5.3" + colorette "^2.0.10" + compression "^1.7.4" + connect-history-api-fallback "^2.0.0" + default-gateway "^6.0.3" + express "^4.17.3" + graceful-fs "^4.2.6" + html-entities "^2.3.2" + http-proxy-middleware "^2.0.3" + ipaddr.js "^2.0.1" + launch-editor "^2.6.0" + open "^8.0.9" + p-retry "^4.5.0" + rimraf "^3.0.2" + schema-utils "^4.0.0" + selfsigned "^2.1.1" + serve-index "^1.9.1" + sockjs "^0.3.24" + spdy "^4.0.2" + webpack-dev-middleware "^5.3.4" + ws "^8.13.0" + +webpack-merge@^4.1.5: + version "4.2.2" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" + integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== + dependencies: + lodash "^4.17.15" + +webpack-merge@^5.7.3: + version "5.10.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" + integrity sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA== + dependencies: + clone-deep "^4.0.1" + flat "^5.0.2" + wildcard "^2.0.0" + +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack@5.93.0: + version "5.93.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.93.0.tgz#2e89ec7035579bdfba9760d26c63ac5c3462a5e5" + integrity sha512-Y0m5oEY1LRuwly578VqluorkXbvXKh7U3rLoQCEO04M97ScRr44afGVkI0FQFsXzysk5OgFAxjZAb9rsGQVihA== + dependencies: + "@types/eslint-scope" "^3.7.3" + "@types/estree" "^1.0.5" + "@webassemblyjs/ast" "^1.12.1" + "@webassemblyjs/wasm-edit" "^1.12.1" + "@webassemblyjs/wasm-parser" "^1.12.1" + acorn "^8.7.1" + acorn-import-attributes "^1.9.5" + browserslist "^4.21.10" + chrome-trace-event "^1.0.2" + enhanced-resolve "^5.17.0" + es-module-lexer "^1.2.1" + eslint-scope "5.1.1" + events "^3.2.0" + glob-to-regexp "^0.4.1" + graceful-fs "^4.2.11" + json-parse-even-better-errors "^2.3.1" + loader-runner "^4.2.0" + mime-types "^2.1.27" + neo-async "^2.6.2" + schema-utils "^3.2.0" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.10" + watchpack "^2.4.1" + webpack-sources "^3.2.3" + +websocket-driver@>=0.5.1, websocket-driver@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" + integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== + dependencies: + http-parser-js ">=0.5.1" + safe-buffer ">=5.1.0" + websocket-extensions ">=0.1.1" + +websocket-extensions@>=0.1.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" + integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" + integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== + +ws@^8.13.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + +ws@~8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@^20.2.2, yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@^16.1.1, yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/mifospay-android/.gitignore b/mifospay-android/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/mifospay-android/.gitignore @@ -0,0 +1 @@ +/build diff --git a/mifospay/README.md b/mifospay-android/README.md similarity index 100% rename from mifospay/README.md rename to mifospay-android/README.md diff --git a/mifospay/build.gradle.kts b/mifospay-android/build.gradle.kts similarity index 76% rename from mifospay/build.gradle.kts rename to mifospay-android/build.gradle.kts index 5921928a6..cb965ffb9 100644 --- a/mifospay/build.gradle.kts +++ b/mifospay-android/build.gradle.kts @@ -87,36 +87,8 @@ android { } dependencies { + implementation(projects.mifospayShared) implementation(projects.core.data) - implementation(projects.core.ui) - implementation(projects.core.designsystem) - - implementation(projects.feature.receipt) - implementation(projects.feature.profile) - implementation(projects.feature.auth) - implementation(projects.feature.makeTransfer) - implementation(projects.feature.faq) - implementation(projects.feature.editpassword) - implementation(projects.feature.notification) - implementation(projects.feature.requestMoney) - implementation(projects.feature.upiSetup) - implementation(projects.feature.settings) - implementation(projects.feature.savedcards) - implementation(projects.feature.qr) - implementation(projects.feature.invoices) - implementation(projects.feature.merchants) - implementation(projects.feature.history) - implementation(projects.feature.kyc) - implementation(projects.feature.home) - implementation(projects.feature.accounts) - implementation(projects.feature.finance) - implementation(projects.feature.payments) - implementation(projects.feature.sendMoney) - implementation(projects.feature.standingInstruction) - implementation(projects.feature.search) - - implementation(projects.libs.mifosPasscode) - implementation(projects.libs.material3Navigation) // Compose implementation(libs.androidx.core.ktx) @@ -124,14 +96,12 @@ dependencies { implementation(libs.androidx.activity.compose) implementation(libs.androidx.activity.ktx) implementation(libs.androidx.core.splashscreen) - + implementation(libs.androidx.compose.material3) implementation(libs.androidx.compose.material3.adaptive) implementation(libs.androidx.compose.material3.adaptive.layout) implementation(libs.androidx.compose.material3.adaptive.navigation) - implementation(libs.androidx.compose.material3.windowSizeClass) implementation(libs.androidx.compose.runtime.tracing) - implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.coroutines.android) @@ -144,10 +114,14 @@ dependencies { implementation(libs.androidx.profileinstaller) implementation(libs.androidx.tracing.ktx) + implementation(libs.koin.core) + implementation(libs.koin.android) + implementation(libs.koin.compose) + implementation(libs.koin.compose.viewmodel) + runtimeOnly(libs.androidx.compose.runtime) debugImplementation(libs.androidx.compose.ui.tooling) - testImplementation(libs.junit) testImplementation(libs.androidx.compose.ui.test) @@ -155,9 +129,6 @@ dependencies { androidTestImplementation(libs.espresso.core) androidTestImplementation(libs.androidx.test.ext.junit) - implementation(libs.koin.android) - implementation(libs.ktor.client.core) - testImplementation(kotlin("test")) testImplementation(libs.koin.test) testImplementation(libs.koin.test.junit4) diff --git a/mifospay-android/dependencies/prodReleaseRuntimeClasspath.tree.txt b/mifospay-android/dependencies/prodReleaseRuntimeClasspath.tree.txt new file mode 100644 index 000000000..bc79941e6 --- /dev/null +++ b/mifospay-android/dependencies/prodReleaseRuntimeClasspath.tree.txt @@ -0,0 +1,2022 @@ ++--- androidx.databinding:databinding-common:8.5.2 ++--- androidx.databinding:databinding-runtime:8.5.2 +| +--- androidx.collection:collection:1.0.0 -> 1.4.4 +| | \--- androidx.collection:collection-jvm:1.4.4 +| | +--- androidx.annotation:annotation:1.8.1 +| | | \--- androidx.annotation:annotation-jvm:1.8.1 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 +| | | +--- org.jetbrains:annotations:13.0 -> 23.0.0 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.0.20 (c) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0 -> 2.0.20 (c) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:2.0.20 (c) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- androidx.collection:collection-ktx:1.4.4 (c) +| | \--- androidx.collection:collection-ktx:1.3.0 -> 1.4.4 (c) +| +--- androidx.databinding:databinding-common:8.5.2 +| +--- androidx.databinding:viewbinding:8.5.2 +| | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| \--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 +| \--- androidx.lifecycle:lifecycle-runtime-android:2.8.6 +| +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| +--- androidx.arch.core:core-common:2.2.0 +| | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| +--- androidx.arch.core:core-runtime:2.2.0 +| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | \--- androidx.arch.core:core-common:2.2.0 (*) +| +--- androidx.lifecycle:lifecycle-common:2.8.6 +| | \--- androidx.lifecycle:lifecycle-common-jvm:2.8.6 +| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 +| | | +--- org.jetbrains:annotations:23.0.0 +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0 (c) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.9.0 (c) +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.9.0 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 +| | +--- androidx.annotation:annotation:1.8.1 (*) +| | +--- androidx.concurrent:concurrent-futures:1.1.0 +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava +| | +--- androidx.startup:startup-runtime:1.1.1 +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | \--- androidx.tracing:tracing:1.0.0 -> 1.3.0-alpha02 +| | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | \--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (c) +| | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) ++--- androidx.databinding:databinding-adapters:8.5.2 +| +--- androidx.databinding:databinding-runtime:8.5.2 (*) +| \--- androidx.databinding:databinding-common:8.5.2 ++--- androidx.databinding:databinding-ktx:8.5.2 +| +--- androidx.databinding:databinding-runtime:8.5.2 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20 -> 2.0.20 +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1 -> 1.9.0 (*) +| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.6 +| | \--- androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.6 +| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata:2.6.1 -> 2.8.6 +| | +--- androidx.arch.core:core-common:2.2.0 (*) +| | +--- androidx.arch.core:core-runtime:2.2.0 (*) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 +| | | +--- androidx.arch.core:core-common:2.2.0 (*) +| | | +--- androidx.arch.core:core-runtime:2.2.0 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-process:2.6.1 -> 2.8.6 +| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) +| | +--- androidx.startup:startup-runtime:1.1.1 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-service:2.6.1 -> 2.8.6 +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| \--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 +| \--- androidx.lifecycle:lifecycle-viewmodel-android:2.8.6 +| +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) ++--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) ++--- androidx.compose:compose-bom:2024.09.02 +| +--- androidx.compose.material3:material3:1.3.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) +| +--- androidx.compose.runtime:runtime:1.7.2 (c) +| +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| +--- androidx.compose.runtime:runtime-saveable:1.7.2 (c) +| +--- androidx.compose.ui:ui:1.7.2 (c) +| +--- androidx.compose.material3.adaptive:adaptive-android:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 (c) +| +--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 (c) +| +--- androidx.compose.animation:animation:1.7.2 (c) +| +--- androidx.compose.foundation:foundation-layout:1.7.2 (c) +| +--- androidx.compose.material3:material3-android:1.3.0 (c) +| +--- androidx.compose.runtime:runtime-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-tooling-preview-android:1.7.2 (c) +| +--- androidx.compose.foundation:foundation:1.7.2 (c) +| +--- androidx.compose.runtime:runtime-saveable-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| +--- androidx.compose.animation:animation-core:1.7.2 (c) +| +--- androidx.compose.ui:ui-util:1.7.2 (c) +| +--- androidx.compose.animation:animation-android:1.7.2 (c) +| +--- androidx.compose.foundation:foundation-layout-android:1.7.2 (c) +| +--- androidx.compose.material:material-icons-core:1.7.2 (c) +| +--- androidx.compose.material:material-ripple:1.7.2 (c) +| +--- androidx.compose.ui:ui-text:1.7.2 (c) +| +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| +--- androidx.compose.foundation:foundation-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| +--- androidx.compose.material:material-icons-extended:1.7.2 (c) +| +--- androidx.compose.material:material:1.7.2 (c) +| +--- androidx.compose.ui:ui-geometry-android:1.7.2 (c) +| +--- androidx.compose.animation:animation-core-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-util-android:1.7.2 (c) +| +--- androidx.compose.material:material-icons-core-android:1.7.2 (c) +| +--- androidx.compose.material:material-ripple-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-text-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-graphics-android:1.7.2 (c) +| +--- androidx.compose.ui:ui-unit-android:1.7.2 (c) +| +--- androidx.compose.material:material-icons-extended-android:1.7.2 (c) +| \--- androidx.compose.material:material-android:1.7.2 (c) ++--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 +| \--- androidx.compose.ui:ui-tooling-preview-android:1.7.2 +| +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| +--- androidx.compose.runtime:runtime:1.7.2 +| | \--- androidx.compose.runtime:runtime-android:1.7.2 +| | +--- androidx.annotation:annotation-experimental:1.4.1 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) +| | +--- androidx.collection:collection:1.4.4 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | \--- androidx.compose.runtime:runtime-saveable:1.7.2 (c) +| +--- androidx.compose.ui:ui:1.7.2 (c) +| +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| +--- androidx.compose.ui:ui-text:1.7.2 (c) +| +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| \--- androidx.compose.ui:ui-util:1.7.2 (c) ++--- com.google.firebase:firebase-bom:33.3.0 +| +--- com.google.firebase:firebase-perf-ktx:21.0.1 (c) +| +--- com.google.firebase:firebase-crashlytics-ktx:19.1.0 (c) +| +--- com.google.firebase:firebase-analytics-ktx:22.1.0 (c) +| +--- com.google.firebase:firebase-messaging-ktx:24.0.1 (c) +| +--- com.google.firebase:firebase-perf:21.0.1 (c) +| +--- com.google.firebase:firebase-common:21.0.0 (c) +| +--- com.google.firebase:firebase-common-ktx:21.0.0 (c) +| +--- com.google.firebase:firebase-crashlytics:19.1.0 (c) +| +--- com.google.firebase:firebase-analytics:22.1.0 (c) +| +--- com.google.firebase:firebase-messaging:24.0.1 (c) +| +--- com.google.firebase:firebase-config:22.0.0 (c) +| +--- com.google.firebase:firebase-installations:18.0.0 (c) +| \--- com.google.firebase:firebase-encoders:17.0.0 (c) ++--- com.google.firebase:firebase-analytics-ktx -> 22.1.0 +| +--- com.google.firebase:firebase-analytics:22.1.0 +| | +--- com.google.android.gms:play-services-measurement:22.1.0 +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | +--- androidx.legacy:legacy-support-core-utils:1.0.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | +--- androidx.core:core:1.0.0 -> 1.13.1 +| | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) +| | | | | +--- androidx.interpolator:interpolator:1.0.0 +| | | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 -> 2.8.6 (*) +| | | | | +--- androidx.versionedparcelable:versionedparcelable:1.1.1 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | \--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | \--- androidx.core:core-ktx:1.13.1 (c) +| | | | +--- androidx.documentfile:documentfile:1.0.0 +| | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 +| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.8.6 (*) +| | | | | \--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | +--- androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 +| | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | \--- androidx.print:print:1.0.0 +| | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 +| | | | \--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 +| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.2.0 -> 1.13.1 (*) +| | | | \--- androidx.fragment:fragment:1.1.0 -> 1.8.2 +| | | | +--- androidx.activity:activity:1.8.1 -> 1.9.2 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- androidx.core:core:1.13.0 -> 1.13.1 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.6 +| | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 +| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.core:core:1.13.1 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | | \--- androidx.core:core:1.13.1 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) +| | | | | | +--- androidx.savedstate:savedstate:1.2.1 +| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) +| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.8.6 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) +| | | | | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | | | | \--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | +--- androidx.tracing:tracing:1.0.0 -> 1.3.0-alpha02 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- androidx.activity:activity-compose:1.9.2 (c) +| | | | | \--- androidx.activity:activity-ktx:1.9.2 (c) +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 (*) +| | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | +--- androidx.viewpager:viewpager:1.0.0 +| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) +| | | | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | \--- androidx.fragment:fragment-ktx:1.8.2 (c) +| | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 +| | | | \--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | +--- com.google.android.gms:play-services-measurement-impl:22.1.0 +| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.9.0 -> 1.13.1 (*) +| | | | +--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 +| | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core-ktx:1.8.0 -> 1.13.1 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | | | \--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 (c) +| | | | +--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 +| | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | | +--- androidx.concurrent:concurrent-futures:1.1.0 (*) +| | | | | +--- androidx.core:core-ktx:1.8.0 -> 1.13.1 (*) +| | | | | +--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 (*) +| | | | | +--- com.google.guava:guava:31.1-android +| | | | | | +--- com.google.guava:failureaccess:1.0.1 +| | | | | | +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava +| | | | | | +--- com.google.code.findbugs:jsr305:3.0.2 +| | | | | | +--- org.checkerframework:checker-qual:3.12.0 +| | | | | | +--- com.google.errorprone:error_prone_annotations:2.11.0 -> 2.26.0 +| | | | | | \--- com.google.j2objc:j2objc-annotations:1.3 +| | | | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) +| | | | | \--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 (c) +| | | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 (*) +| | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) +| | | | +--- com.google.android.gms:play-services-stats:17.0.2 +| | | | | +--- androidx.legacy:legacy-support-core-utils:1.0.0 (*) +| | | | | \--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) +| | | | \--- com.google.guava:guava:31.1-android (*) +| | | \--- com.google.android.gms:play-services-stats:17.0.2 (*) +| | +--- com.google.android.gms:play-services-measurement-api:22.1.0 +| | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 (*) +| | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) +| | | +--- com.google.android.gms:play-services-measurement-sdk-api:22.1.0 +| | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | | \--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) +| | | +--- com.google.android.gms:play-services-tasks:18.2.0 +| | | | \--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | | +--- com.google.firebase:firebase-common:21.0.0 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4 -> 1.9.0 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | | | | +--- com.google.android.gms:play-services-tasks:16.0.1 -> 18.2.0 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- com.google.firebase:firebase-components:18.0.0 +| | | | | +--- com.google.firebase:firebase-annotations:16.2.0 +| | | | | | \--- javax.inject:javax.inject:1 +| | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) +| | | | | \--- com.google.errorprone:error_prone_annotations:2.26.0 +| | | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) +| | | | +--- androidx.concurrent:concurrent-futures:1.1.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) +| | | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 +| | | | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| | | | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | | | \--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | | +--- com.google.firebase:firebase-installations:17.0.1 -> 18.0.0 +| | | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | | | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | | | +--- com.google.firebase:firebase-installations-interop:17.1.1 -> 17.2.0 +| | | | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | | | | \--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- com.google.firebase:firebase-installations-interop:17.0.0 -> 17.2.0 (*) +| | | +--- com.google.firebase:firebase-measurement-connector:19.0.0 -> 20.0.1 +| | | | +--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) +| | | | \--- com.google.firebase:firebase-annotations:16.0.0 -> 16.2.0 (*) +| | | +--- com.google.guava:guava:31.1-android (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) +| | \--- com.google.android.gms:play-services-measurement-sdk:22.1.0 +| | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | +--- com.google.android.gms:play-services-basement:18.4.0 (*) +| | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) +| | \--- com.google.android.gms:play-services-measurement-impl:22.1.0 (*) +| +--- com.google.firebase:firebase-common:21.0.0 (*) +| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| +--- com.google.firebase:firebase-components:18.0.0 (*) +| \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) ++--- com.google.firebase:firebase-perf-ktx -> 21.0.1 +| +--- com.google.firebase:firebase-perf:21.0.1 +| | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) +| | +--- com.google.firebase:protolite-well-known-types:18.0.0 +| | | \--- com.google.protobuf:protobuf-javalite:3.14.0 -> 4.26.0 +| | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | +--- com.google.firebase:firebase-config:21.5.0 -> 22.0.0 +| | | +--- com.google.firebase:firebase-config-interop:16.0.1 +| | | | +--- com.google.firebase:firebase-encoders-json:18.0.1 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 -> 2.0.20 (*) +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | \--- com.google.firebase:firebase-encoders:17.0.0 +| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | \--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) +| | | +--- com.google.firebase:firebase-abt:21.1.1 +| | | | +--- com.google.firebase:firebase-measurement-connector:18.0.0 -> 20.0.1 (*) +| | | | \--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) +| | | +--- com.google.firebase:firebase-measurement-connector:18.0.0 -> 20.0.1 (*) +| | | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) +| | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) +| | +--- com.google.firebase:firebase-sessions:2.0.0 -> 2.0.4 +| | | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | | +--- com.google.firebase:firebase-installations-interop:17.2.0 (*) +| | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | | +--- com.google.firebase:firebase-encoders-json:18.0.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| | | +--- com.google.firebase:firebase-installations:18.0.0 (*) +| | | +--- com.google.firebase:firebase-datatransport:19.0.0 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- com.google.android.datatransport:transport-api:3.1.0 -> 3.2.0 +| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- com.google.android.datatransport:transport-backend-cct:3.2.0 -> 3.3.0 +| | | | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) +| | | | | +--- com.google.android.datatransport:transport-runtime:3.3.0 +| | | | | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) +| | | | | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| | | | | | +--- javax.inject:javax.inject:1 +| | | | | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | | | | | \--- com.google.firebase:firebase-encoders-proto:16.0.0 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | \--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | | | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | | | | +--- com.google.firebase:firebase-encoders-json:18.0.0 -> 18.0.1 (*) +| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- com.google.android.datatransport:transport-runtime:3.2.0 -> 3.3.0 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.datastore:datastore-preferences:1.0.0 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | +--- androidx.datastore:datastore:1.0.0 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.9.0 (*) +| | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | | \--- androidx.datastore:datastore-core:1.0.0 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.9.0 (*) +| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | \--- androidx.datastore:datastore-preferences-core:1.0.0 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) +| | | | \--- androidx.datastore:datastore-core:1.0.0 (*) +| | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) +| | | \--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) +| | +--- com.google.firebase:firebase-datatransport:18.1.8 -> 19.0.0 (*) +| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | +--- androidx.lifecycle:lifecycle-process:2.3.1 -> 2.8.6 (*) +| | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | +--- com.google.protobuf:protobuf-javalite:3.21.11 -> 4.26.0 +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- androidx.appcompat:appcompat:1.2.0 -> 1.7.0 +| | | +--- androidx.activity:activity:1.7.0 -> 1.9.2 (*) +| | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| | | +--- androidx.appcompat:appcompat-resources:1.7.0 +| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.6.0 -> 1.13.1 (*) +| | | | +--- androidx.vectordrawable:vectordrawable:1.1.0 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.vectordrawable:vectordrawable-animated:1.1.0 +| | | | | +--- androidx.vectordrawable:vectordrawable:1.1.0 (*) +| | | | | +--- androidx.interpolator:interpolator:1.0.0 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | \--- androidx.appcompat:appcompat:1.7.0 (c) +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | +--- androidx.core:core:1.13.0 -> 1.13.1 (*) +| | | +--- androidx.core:core-ktx:1.13.0 -> 1.13.1 (*) +| | | +--- androidx.cursoradapter:cursoradapter:1.0.0 +| | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | +--- androidx.drawerlayout:drawerlayout:1.0.0 +| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) +| | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) +| | | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 (*) +| | | +--- androidx.emoji2:emoji2:1.3.0 +| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-process:2.4.1 -> 2.8.6 (*) +| | | | +--- androidx.startup:startup-runtime:1.0.0 -> 1.1.1 (*) +| | | | \--- androidx.emoji2:emoji2-views-helper:1.3.0 (c) +| | | +--- androidx.emoji2:emoji2-views-helper:1.2.0 -> 1.3.0 +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) +| | | | +--- androidx.emoji2:emoji2:1.3.0 (*) +| | | | \--- androidx.emoji2:emoji2:1.3.0 (c) +| | | +--- androidx.fragment:fragment:1.5.4 -> 1.8.2 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | +--- androidx.resourceinspection:resourceinspection-annotation:1.0.1 +| | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | \--- androidx.appcompat:appcompat-resources:1.7.0 (c) +| | +--- com.google.android.datatransport:transport-api:3.0.0 -> 3.2.0 (*) +| | +--- com.google.dagger:dagger:2.27 +| | | \--- javax.inject:javax.inject:1 +| | \--- com.squareup.okhttp3:okhttp:3.12.1 -> 4.12.0 +| | +--- com.squareup.okio:okio:3.6.0 -> 3.9.1 +| | | \--- com.squareup.okio:okio-jvm:3.9.1 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.25 -> 2.0.20 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 2.0.20 (*) +| +--- com.google.firebase:firebase-common:21.0.0 (*) +| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| \--- com.google.firebase:firebase-components:18.0.0 (*) ++--- com.google.firebase:firebase-crashlytics-ktx -> 19.1.0 +| +--- com.google.firebase:firebase-crashlytics:19.1.0 +| | +--- com.google.firebase:firebase-sessions:2.0.4 (*) +| | +--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | +--- com.google.firebase:firebase-annotations:16.2.0 (*) +| | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | +--- com.google.firebase:firebase-config-interop:16.0.1 (*) +| | +--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | +--- com.google.firebase:firebase-encoders-json:18.0.1 (*) +| | +--- com.google.firebase:firebase-installations:18.0.0 (*) +| | +--- com.google.firebase:firebase-installations-interop:17.2.0 (*) +| | +--- com.google.firebase:firebase-measurement-connector:20.0.1 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| | +--- com.google.android.datatransport:transport-api:3.2.0 (*) +| | +--- com.google.android.datatransport:transport-backend-cct:3.3.0 (*) +| | +--- com.google.android.datatransport:transport-runtime:3.3.0 (*) +| | \--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) +| +--- com.google.firebase:firebase-common:21.0.0 (*) +| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| \--- com.google.firebase:firebase-components:18.0.0 (*) ++--- com.google.firebase:firebase-messaging-ktx -> 24.0.1 +| +--- com.google.firebase:firebase-messaging:24.0.1 +| | +--- com.google.firebase:firebase-common:21.0.0 (*) +| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| | +--- com.google.firebase:firebase-components:18.0.0 (*) +| | +--- com.google.firebase:firebase-datatransport:18.2.0 -> 19.0.0 (*) +| | +--- com.google.firebase:firebase-encoders:17.0.0 (*) +| | +--- com.google.firebase:firebase-encoders-json:18.0.0 -> 18.0.1 (*) +| | +--- com.google.firebase:firebase-encoders-proto:16.0.0 (*) +| | +--- com.google.firebase:firebase-iid-interop:17.1.0 +| | | +--- com.google.android.gms:play-services-basement:17.0.0 -> 18.4.0 (*) +| | | \--- com.google.android.gms:play-services-tasks:17.0.0 -> 18.2.0 (*) +| | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) +| | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) +| | +--- com.google.firebase:firebase-measurement-connector:19.0.0 -> 20.0.1 (*) +| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | +--- com.google.android.datatransport:transport-api:3.1.0 -> 3.2.0 (*) +| | +--- com.google.android.datatransport:transport-backend-cct:3.1.8 -> 3.3.0 (*) +| | +--- com.google.android.datatransport:transport-runtime:3.1.8 -> 3.3.0 (*) +| | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | +--- androidx.core:core:1.2.0 -> 1.13.1 (*) +| | | +--- androidx.fragment:fragment:1.0.0 -> 1.8.2 (*) +| | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) +| | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | +--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) +| | +--- com.google.android.gms:play-services-cloud-messaging:17.2.0 +| | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) +| | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | +--- com.google.android.gms:play-services-stats:17.0.2 (*) +| | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | +--- com.google.errorprone:error_prone_annotations:2.9.0 -> 2.26.0 +| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- com.google.firebase:firebase-common:21.0.0 (*) +| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.20 (*) +| \--- com.google.firebase:firebase-components:18.0.0 (*) ++--- project :mifospay-shared +| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 +| | \--- androidx.lifecycle:lifecycle-runtime-compose-android:2.8.6 +| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | +--- androidx.compose.runtime:runtime:1.7.1 -> 1.7.2 (*) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 +| | \--- androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.6 +| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | +--- androidx.compose.runtime:runtime:1.6.0 -> 1.7.2 (*) +| | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 +| | | \--- androidx.compose.ui:ui-android:1.7.2 +| | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.9.2 +| | | | +--- androidx.activity:activity:1.9.2 (*) +| | | | +--- androidx.core:core-ktx:1.13.0 -> 1.13.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.6 +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 +| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) +| | | | | \--- androidx.savedstate:savedstate:1.2.1 (c) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- androidx.activity:activity:1.9.2 (c) +| | | | \--- androidx.activity:activity-compose:1.9.2 (c) +| | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | +--- androidx.autofill:autofill:1.0.0 +| | | | \--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 +| | | | \--- androidx.compose.runtime:runtime-saveable-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | \--- androidx.compose.runtime:runtime:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-geometry:1.7.2 +| | | | \--- androidx.compose.ui:ui-geometry-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 +| | | | | \--- androidx.compose.ui:ui-util-android:1.7.2 +| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | | \--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-graphics:1.7.2 +| | | | \--- androidx.compose.ui:ui-graphics-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 +| | | | | \--- androidx.compose.ui:ui-unit-android:1.7.2 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | +--- androidx.collection:collection-ktx:1.2.0 -> 1.4.4 +| | | | | | +--- androidx.collection:collection:1.4.4 (*) +| | | | | | \--- androidx.collection:collection:1.4.4 (c) +| | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) +| | | | +--- androidx.graphics:graphics-path:1.0.1 +| | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-text:1.7.2 +| | | | \--- androidx.compose.ui:ui-text-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) +| | | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) +| | | +--- androidx.customview:customview-poolingcontainer:1.0.0 +| | | | +--- androidx.core:core-ktx:1.5.0 -> 1.13.1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) +| | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.3 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-text:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) +| | | +--- androidx.compose.ui:ui-util:1.7.2 (c) +| | | \--- androidx.compose.foundation:foundation:1.7.2 (c) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 +| | +--- androidx.tracing:tracing:1.3.0-alpha02 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | \--- androidx.tracing:tracing:1.3.0-alpha02 (c) +| +--- io.insert-koin:koin-bom:4.0.0-RC2 +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-compose:4.0.0-RC2 (c) +| | +--- io.insert-koin:koin-compose-viewmodel:4.0.0-RC2 (c) +| | \--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (c) +| +--- io.insert-koin:koin-android:4.0.0-RC2 +| | +--- io.insert-koin:koin-core:4.0.0-RC2 +| | | \--- io.insert-koin:koin-core-jvm:4.0.0-RC2 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- co.touchlab:stately-concurrency:2.0.7 +| | | | \--- co.touchlab:stately-concurrency-jvm:2.0.7 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | | | \--- co.touchlab:stately-strict:2.0.7 +| | | | \--- co.touchlab:stately-strict-jvm:2.0.7 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | | \--- co.touchlab:stately-concurrent-collections:2.0.7 +| | | \--- co.touchlab:stately-concurrent-collections-jvm:2.0.7 +| | | +--- co.touchlab:stately-concurrency:2.0.7 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 +| | | \--- io.insert-koin:koin-core-viewmodel-jvm:4.0.0-RC2 +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.0 -> 2.8.3-rc01 +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.5 -> 2.8.6 (*) +| | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 +| | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 -> 2.8.2 +| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) +| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.7.0 -> 2.8.6 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.4 -> 2.8.6 (*) +| | | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 +| | | | | \--- org.jetbrains.androidx.core:core-bundle-android:1.0.1 +| | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 +| | | | | +--- androidx.lifecycle:lifecycle-common:2.8.5 -> 2.8.6 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 +| | | | | +--- androidx.arch.core:core-common:2.2.0 (*) +| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0 -> 1.9.0 (*) +| | | +--- org.jetbrains.androidx.core:core-bundle:1.0.0 -> 1.0.1 (*) +| | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.0 -> 1.2.2 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- androidx.appcompat:appcompat:1.7.0 (*) +| | +--- androidx.activity:activity-ktx:1.9.1 -> 1.9.2 (*) +| | +--- androidx.fragment:fragment-ktx:1.8.2 +| | | +--- androidx.activity:activity-ktx:1.8.1 -> 1.9.2 (*) +| | | +--- androidx.collection:collection-ktx:1.1.0 -> 1.4.4 (*) +| | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) +| | | +--- androidx.fragment:fragment:1.8.2 (*) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.6 (*) +| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | \--- androidx.fragment:fragment:1.8.2 (c) +| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 -> 2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 -> 2.8.6 +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) +| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) +| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) +| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-compose:4.0.0-RC2 +| | | \--- io.insert-koin:koin-compose-jvm:4.0.0-RC2 +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 -> 1.7.0-rc01 +| | | | +--- androidx.compose.runtime:runtime:1.7.1 -> 1.7.2 (*) +| | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 +| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlinx:atomicfu:0.23.2 +| | | | | \--- org.jetbrains.kotlinx:atomicfu-jvm:0.23.2 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:{prefer 1.9.21} -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.9.24 -> 2.0.20 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:atomicfu:0.23.2 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.2 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 -> 2.8.6 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | +--- androidx.navigation:navigation-fragment-ktx:2.7.7 -> 2.8.2 +| | | +--- androidx.navigation:navigation-fragment:2.8.2 +| | | | +--- androidx.fragment:fragment-ktx:1.6.2 -> 1.8.2 (*) +| | | | +--- androidx.navigation:navigation-runtime:2.8.2 +| | | | | +--- androidx.activity:activity-ktx:1.7.1 -> 1.9.2 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.4.2 -> 1.4.4 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.6 (*) +| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.6 (*) +| | | | | +--- androidx.navigation:navigation-common:2.8.2 +| | | | | | +--- androidx.annotation:annotation:1.8.1 (*) +| | | | | | +--- androidx.collection:collection-ktx:1.4.2 -> 1.4.4 (*) +| | | | | | +--- androidx.core:core-ktx:1.1.0 -> 1.13.1 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 -> 2.8.6 (*) +| | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 +| | | | | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 (c) +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (c) +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 (c) +| | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (c) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (c) +| | | | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | | | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | | | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | | | +--- androidx.navigation:navigation-common:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | | +--- androidx.slidingpanelayout:slidingpanelayout:1.2.0 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.customview:customview:1.1.0 (*) +| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | | +--- androidx.window:window:1.0.0 -> 1.3.0 +| | | | | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| | | | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | | | +--- androidx.core:core:1.8.0 -> 1.13.1 (*) +| | | | | | +--- androidx.window.extensions.core:core:1.0.0 +| | | | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.20 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) +| | | | | | \--- androidx.window:window-core:1.3.0 (c) +| | | | | \--- androidx.transition:transition:1.4.1 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | | +--- androidx.navigation:navigation-common:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.2 +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 +| | | | | +--- androidx.navigation:navigation-common:2.8.2 (*) +| | | | | +--- androidx.navigation:navigation-common:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.2 (*) +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | | \--- androidx.navigation:navigation-common:2.8.2 (c) +| | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | +--- androidx.navigation:navigation-compose:2.8.2 (c) +| | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | \--- androidx.navigation:navigation-common:2.8.2 (c) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| +--- project :core:data +| | +--- androidx.core:core-ktx:1.13.1 (*) +| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | +--- project :core:common +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (*) +| | | +--- io.coil-kt.coil3:coil:3.0.0-alpha10 +| | | | \--- io.coil-kt.coil3:coil-android:3.0.0-alpha10 +| | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 +| | | | | \--- io.coil-kt.coil3:coil-core-android:3.0.0-alpha10 +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 -> 2.8.6 (*) +| | | | | +--- androidx.annotation:annotation:1.8.1 (*) +| | | | | +--- androidx.appcompat:appcompat-resources:1.7.0 (*) +| | | | | +--- androidx.core:core-ktx:1.13.1 (*) +| | | | | +--- androidx.exifinterface:exifinterface:1.3.7 +| | | | | | \--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 -> 1.9.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | | | \--- com.squareup.okio:okio:3.9.0 -> 3.9.1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | +--- io.coil-kt.coil3:coil-svg:3.0.0-alpha10 +| | | | \--- io.coil-kt.coil3:coil-svg-android:3.0.0-alpha10 +| | | | +--- androidx.core:core-ktx:1.13.1 (*) +| | | | +--- com.caverock:androidsvg-aar:1.4 +| | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | +--- io.coil-kt.coil3:coil-network-ktor3:3.0.0-alpha10 +| | | | \--- io.coil-kt.coil3:coil-network-ktor3-android:3.0.0-alpha10 +| | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | | +--- io.coil-kt.coil3:coil-network-core:3.0.0-alpha10 +| | | | | \--- io.coil-kt.coil3:coil-network-core-android:3.0.0-alpha10 +| | | | | +--- androidx.core:core-ktx:1.13.1 (*) +| | | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-beta-2 -> 3.0.0-rc-1 +| | | | | \--- io.ktor:ktor-client-core-jvm:3.0.0-rc-1 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 +| | | | | | \--- io.ktor:ktor-http-jvm:3.0.0-rc-1 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-utils:3.0.0-rc-1 +| | | | | | | \--- io.ktor:ktor-utils-jvm:3.0.0-rc-1 +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | | +--- io.ktor:ktor-io:3.0.0-rc-1 +| | | | | | | | \--- io.ktor:ktor-io-jvm:3.0.0-rc-1 +| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-io-core:0.5.3 +| | | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.5.3 +| | | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-io-bytestring:0.5.3 +| | | | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.5.3 +| | | | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | +--- io.ktor:ktor-events:3.0.0-rc-1 +| | | | | | \--- io.ktor:ktor-events-jvm:3.0.0-rc-1 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | | +--- io.ktor:ktor-utils:3.0.0-rc-1 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | +--- io.ktor:ktor-websocket-serialization:3.0.0-rc-1 +| | | | | | \--- io.ktor:ktor-websocket-serialization-jvm:3.0.0-rc-1 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | | +--- io.ktor:ktor-serialization:3.0.0-rc-1 +| | | | | | | \--- io.ktor:ktor-serialization-jvm:3.0.0-rc-1 +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | | | +--- io.ktor:ktor-websockets:3.0.0-rc-1 +| | | | | | | | \--- io.ktor:ktor-websockets-jvm:3.0.0-rc-1 +| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | +--- io.ktor:ktor-sse:3.0.0-rc-1 +| | | | | | \--- io.ktor:ktor-sse-jvm:3.0.0-rc-1 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.8.1 -> 1.9.0 +| | | | | +--- org.slf4j:slf4j-api:1.7.32 -> 2.0.16 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | +--- co.touchlab:kermit:2.0.4 +| | | | \--- co.touchlab:kermit-android:2.0.4 +| | | | +--- co.touchlab:kermit-core:2.0.4 +| | | | | \--- co.touchlab:kermit-core-android:2.0.4 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| | | +--- com.squareup.okio:okio:3.9.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 +| | | | \--- io.insert-koin:koin-annotations-jvm:1.4.0-RC4 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | \--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.20 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- project :core:datastore +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- com.russhwolf:multiplatform-settings-no-arg:1.2.0 +| | | | \--- com.russhwolf:multiplatform-settings-no-arg-android:1.2.0 +| | | | +--- androidx.startup:startup-runtime:1.1.1 (*) +| | | | +--- com.russhwolf:multiplatform-settings:1.2.0 +| | | | | \--- com.russhwolf:multiplatform-settings-android:1.2.0 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | +--- com.russhwolf:multiplatform-settings-serialization:1.2.0 +| | | | \--- com.russhwolf:multiplatform-settings-serialization-android:1.2.0 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- com.russhwolf:multiplatform-settings:1.2.0 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | +--- com.russhwolf:multiplatform-settings-coroutines:1.2.0 +| | | | \--- com.russhwolf:multiplatform-settings-coroutines-android:1.2.0 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- com.russhwolf:multiplatform-settings:1.2.0 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | +--- project :core:model +| | | | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.1 +| | | | | \--- org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1 +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 +| | | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (c) +| | | | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) +| | | +--- project :core:common (*) +| | | \--- project :core:datastore-proto +| | | +--- com.google.protobuf:protobuf-kotlin-lite:4.26.0 +| | | | +--- com.google.protobuf:protobuf-javalite:4.26.0 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.0 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | +--- project :core:network +| | | +--- io.ktor:ktor-client-okhttp:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-okhttp-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | +--- com.squareup.okhttp3:okhttp:4.12.0 (*) +| | | | +--- com.squareup.okhttp3:okhttp-sse:4.12.0 +| | | | | +--- com.squareup.okhttp3:okhttp:4.12.0 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 2.0.20 (*) +| | | | +--- com.squareup.okio:okio:3.9.0 -> 3.9.1 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.1 (*) +| | | +--- project :core:common (*) +| | | +--- project :core:model (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- project :core:datastore (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (*) +| | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | +--- io.ktor:ktor-client-json:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-json-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.ktor:ktor-client-logging:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-logging-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.8.1 -> 1.9.0 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.ktor:ktor-client-serialization:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-serialization-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (*) +| | | | +--- io.ktor:ktor-client-json:3.0.0-rc-1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.ktor:ktor-client-content-negotiation:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-content-negotiation-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | +--- io.ktor:ktor-serialization:3.0.0-rc-1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.ktor:ktor-client-auth:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-client-auth-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-client-core:3.0.0-rc-1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.ktor:ktor-serialization-kotlinx-json:3.0.0-rc-1 +| | | | \--- io.ktor:ktor-serialization-kotlinx-json-jvm:3.0.0-rc-1 +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | +--- io.ktor:ktor-serialization-kotlinx:3.0.0-rc-1 +| | | | | \--- io.ktor:ktor-serialization-kotlinx-jvm:3.0.0-rc-1 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.1 -> 1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:2.0.16 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) +| | | | | +--- io.ktor:ktor-http:3.0.0-rc-1 (*) +| | | | | +--- io.ktor:ktor-serialization:3.0.0-rc-1 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- de.jensklingenberg.ktorfit:ktorfit-lib-ktor-3.0.0-beta-2:2.1.0 +| | | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-ktor-3.0.0-beta-2-android:2.1.0 +| | | | +--- io.ktor:ktor-client-cio-jvm:3.0.0-beta-2 +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | +--- org.slf4j:slf4j-api:2.0.13 -> 2.0.16 +| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | +--- io.ktor:ktor-client-core:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | +--- io.ktor:ktor-http-cio:3.0.0-beta-2 +| | | | | | \--- io.ktor:ktor-http-cio-jvm:3.0.0-beta-2 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.13 -> 2.0.16 +| | | | | | +--- io.ktor:ktor-network:3.0.0-beta-2 +| | | | | | | \--- io.ktor:ktor-network-jvm:3.0.0-beta-2 +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -> 2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 -> 2.0.20 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | | | +--- org.slf4j:slf4j-api:2.0.13 -> 2.0.16 +| | | | | | | +--- io.ktor:ktor-utils:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | +--- io.ktor:ktor-websockets:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | +--- io.ktor:ktor-network-tls:3.0.0-beta-2 +| | | | | | \--- io.ktor:ktor-network-tls-jvm:3.0.0-beta-2 +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 -> 2.0.20 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) +| | | | | | +--- org.slf4j:slf4j-api:2.0.13 -> 2.0.16 +| | | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | | +--- io.ktor:ktor-network:3.0.0-beta-2 (*) +| | | | | | +--- io.ktor:ktor-utils:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | +--- de.jensklingenberg.ktorfit:ktorfit-lib-light-ktor-3.0.0-beta-2:2.1.0 +| | | | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light-ktor-3.0.0-beta-2-android:2.1.0 +| | | | | +--- de.jensklingenberg.ktorfit:ktorfit-annotations:2.1.0 +| | | | | | \--- de.jensklingenberg.ktorfit:ktorfit-annotations-android:2.1.0 +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | | +--- io.ktor:ktor-client-core:3.0.0-beta-2 -> 3.0.0-rc-1 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | \--- com.squareup.okio:okio:3.9.1 (*) +| | +--- project :core:model (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | +--- project :core:analytics +| | | +--- com.google.firebase:firebase-bom:33.3.0 (*) +| | | +--- com.google.firebase:firebase-analytics-ktx -> 22.1.0 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | \--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) +| +--- org.jetbrains.compose.material3:material3:1.7.0-rc01 +| | +--- androidx.compose.material3:material3:1.3.0 +| | | \--- androidx.compose.material3:material3-android:1.3.0 +| | | +--- androidx.activity:activity-compose:1.8.2 -> 1.9.2 +| | | | +--- androidx.activity:activity-ktx:1.9.2 (*) +| | | | +--- androidx.compose.runtime:runtime:1.0.1 -> 1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime-saveable:1.0.1 -> 1.7.2 (*) +| | | | +--- androidx.compose.ui:ui:1.0.1 -> 1.7.2 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- androidx.activity:activity:1.9.2 (c) +| | | | \--- androidx.activity:activity-ktx:1.9.2 (c) +| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | +--- androidx.compose.animation:animation-core:1.6.0 -> 1.7.2 +| | | | \--- androidx.compose.animation:animation-core-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | | \--- androidx.compose.animation:animation:1.7.2 (c) +| | | +--- androidx.compose.foundation:foundation:1.7.0 -> 1.7.2 +| | | | \--- androidx.compose.foundation:foundation-android:1.7.2 +| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.animation:animation:1.7.2 +| | | | | \--- androidx.compose.animation:animation-android:1.7.2 +| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | +--- androidx.compose.animation:animation-core:1.7.2 (*) +| | | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 +| | | | | | \--- androidx.compose.foundation:foundation-layout-android:1.7.2 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | | | +--- androidx.compose.animation:animation-core:1.2.1 -> 1.7.2 (*) +| | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) +| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | | \--- androidx.compose.foundation:foundation:1.7.2 (c) +| | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) +| | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | \--- androidx.compose.animation:animation-core:1.7.2 (c) +| | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-text:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | +--- androidx.core:core:1.13.1 (*) +| | | | +--- androidx.emoji2:emoji2:1.3.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | \--- androidx.compose.foundation:foundation-layout:1.7.2 (c) +| | | +--- androidx.compose.foundation:foundation-layout:1.7.0 -> 1.7.2 (*) +| | | +--- androidx.compose.material:material-icons-core:1.6.0 -> 1.7.2 +| | | | \--- androidx.compose.material:material-icons-core-android:1.7.2 +| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.compose.material:material-ripple:1.7.0 -> 1.7.2 +| | | | \--- androidx.compose.material:material-ripple-android:1.7.2 +| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) +| | | | +--- androidx.compose.animation:animation:1.7.2 (*) +| | | | +--- androidx.compose.foundation:foundation:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.compose.runtime:runtime:1.7.0 -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui-text:1.6.0 -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.2 (*) +| | | \--- androidx.lifecycle:lifecycle-common-java8:2.6.1 -> 2.8.6 (*) +| | +--- org.jetbrains.compose.animation:animation-core:1.7.0-rc01 +| | | +--- androidx.compose.animation:animation-core:1.7.1 -> 1.7.2 (*) +| | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 +| | | | +--- androidx.compose.ui:ui:1.7.1 -> 1.7.2 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.3-rc01 +| | | | | +--- androidx.arch.core:core-common:2.2.0 (*) +| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.5 -> 2.8.6 (*) +| | | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.3-rc01 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.3-rc01 +| | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.5 -> 2.8.6 (*) +| | | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.3-rc01 (*) +| | | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.3-rc01 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.6.11 -> 1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 -> 1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.3-rc01 (*) +| | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.runtime:runtime-saveable:1.7.0-rc01 +| | | | | +--- androidx.compose.runtime:runtime-saveable:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 +| | | | | +--- androidx.compose.ui:ui-geometry:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 +| | | | | \--- androidx.compose.ui:ui-util:1.7.1 -> 1.7.2 (*) +| | | | +--- org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 +| | | | | +--- androidx.compose.ui:ui-graphics:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 +| | | | | | +--- androidx.compose.ui:ui-unit:1.7.1 -> 1.7.2 (*) +| | | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | | +--- org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 (*) +| | | | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui-text:1.7.0-rc01 +| | | | | +--- androidx.compose.ui:ui-text:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime-saveable:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.kotlinx:atomicfu:0.23.2 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | | +--- org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.9.24 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:atomicfu:0.23.2 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | | +--- org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 +| | | +--- androidx.compose.foundation:foundation:1.7.1 -> 1.7.2 (*) +| | | +--- org.jetbrains.compose.animation:animation:1.7.0-rc01 +| | | | +--- androidx.compose.animation:animation:1.7.1 -> 1.7.2 (*) +| | | | +--- org.jetbrains.compose.animation:animation-core:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.foundation:foundation-layout:1.7.0-rc01 +| | | | | +--- androidx.compose.foundation:foundation-layout:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 (*) +| | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.foundation:foundation-layout:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui-text:1.7.0-rc01 (*) +| | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.foundation:foundation-layout:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.material:material-icons-core:1.7.0-rc01 +| | | +--- androidx.compose.material:material-icons-core:1.7.1 -> 1.7.2 (*) +| | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 (*) +| | | \--- org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.material:material-ripple:1.7.0-rc01 +| | | +--- androidx.compose.material:material-ripple:1.7.1 -> 1.7.2 (*) +| | | +--- org.jetbrains.compose.animation:animation:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.ui:ui-text:1.7.0-rc01 (*) +| | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| +--- org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 +| | \--- org.jetbrains.compose.components:components-ui-tooling-preview-android:1.7.0-rc01 +| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| +--- org.jetbrains.compose.components:components-resources:1.7.0-rc01 +| | \--- org.jetbrains.compose.components:components-resources-android:1.7.0-rc01 +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) +| | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) +| +--- dev.chrisbanes.material3:material3-window-size-class-multiplatform:0.5.0 +| | \--- dev.chrisbanes.material3:material3-window-size-class-multiplatform-android:0.5.0 +| | +--- androidx.window:window:1.2.0 -> 1.3.0 (*) +| | +--- org.jetbrains.compose.ui:ui:1.6.0 -> 1.7.0-rc01 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| +--- io.insert-koin:koin-compose:1.2.0-Beta4 -> 4.0.0-RC2 (*) +| +--- io.insert-koin:koin-compose-viewmodel:1.2.0-Beta4 -> 4.0.0-RC2 +| | \--- io.insert-koin:koin-compose-viewmodel-jvm:4.0.0-RC2 +| | +--- io.insert-koin:koin-compose:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0 -> 2.8.2 +| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 -> 2.8.6 (*) +| | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime-saveable:1.6.11 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui:1.6.11 -> 1.7.0-rc01 (*) +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- project :feature:auth +| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) +| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) +| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) +| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) +| | +--- project :libs:country-code-picker +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) +| | | +--- androidx.compose:compose-bom:2024.09.02 (*) +| | | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| | | +--- androidx.compose.foundation:foundation -> 1.7.2 (*) +| | | +--- androidx.compose.foundation:foundation-layout -> 1.7.2 (*) +| | | +--- androidx.compose.material:material-icons-extended -> 1.7.2 +| | | | \--- androidx.compose.material:material-icons-extended-android:1.7.2 +| | | | \--- androidx.compose.material:material-icons-core:1.7.2 (*) +| | | +--- androidx.compose.material3:material3 -> 1.3.0 (*) +| | | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| | | +--- androidx.compose.ui:ui-util -> 1.7.2 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 +| | | | \--- org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.8 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) +| | | \--- io.michaelrocks:libphonenumber-android:8.13.35 +| | +--- androidx.credentials:credentials:1.3.0 +| | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | \--- androidx.credentials:credentials-play-services-auth:1.3.0 (c) +| | +--- androidx.credentials:credentials-play-services-auth:1.3.0 +| | | +--- androidx.credentials:credentials:1.3.0 (*) +| | | +--- com.google.android.gms:play-services-auth:21.1.1 -> 21.2.0 +| | | | +--- androidx.fragment:fragment:1.5.7 -> 1.8.2 (*) +| | | | +--- androidx.loader:loader:1.1.0 (*) +| | | | +--- com.google.android.gms:play-services-auth-api-phone:18.0.2 +| | | | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) +| | | | | +--- com.google.android.gms:play-services-basement:18.0.2 -> 18.4.0 (*) +| | | | | \--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | | | +--- com.google.android.gms:play-services-auth-base:18.0.10 +| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) +| | | | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) +| | | | | +--- com.google.android.gms:play-services-basement:18.2.0 -> 18.4.0 (*) +| | | | | \--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) +| | | | +--- com.google.android.gms:play-services-base:18.3.0 (*) +| | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) +| | | | +--- com.google.android.gms:play-services-fido:20.0.1 -> 21.0.0 +| | | | | +--- com.google.android.gms:play-services-base:18.3.0 (*) +| | | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) +| | | | | +--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0 -> 2.0.20 (*) +| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) +| | | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) +| | | +--- com.google.android.gms:play-services-fido:21.0.0 (*) +| | | +--- com.google.android.libraries.identity.googleid:googleid:1.1.0 -> 1.1.1 +| | | | +--- androidx.credentials:credentials:1.3.0-beta01 -> 1.3.0 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.0 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.0.20 (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | \--- androidx.credentials:credentials:1.3.0 (c) +| | +--- com.google.android.libraries.identity.googleid:googleid:1.1.1 (*) +| | +--- com.google.android.gms:play-services-auth:21.2.0 (*) +| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | +--- project :core:ui +| | | +--- androidx.metrics:metrics-performance:1.0.0-beta01 +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.core:core:1.5.0 -> 1.13.1 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | +--- androidx.browser:browser:1.8.0 +| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) +| | | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) +| | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) +| | | | +--- androidx.interpolator:interpolator:1.0.0 (*) +| | | | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava +| | | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) +| | | +--- com.google.accompanist:accompanist-pager:0.34.0 +| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.9.0 (*) +| | | | +--- androidx.compose.foundation:foundation:1.6.0 -> 1.7.2 (*) +| | | | +--- dev.chrisbanes.snapper:snapper:0.2.2 +| | | | | +--- androidx.compose.foundation:foundation:1.1.1 -> 1.7.2 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.10 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| | | +--- project :core:analytics (*) +| | | +--- project :core:designsystem +| | | | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) +| | | | +--- androidx.activity:activity-compose:1.9.2 (*) +| | | | +--- project :core:model (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | | +--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 +| | | | | \--- io.coil-kt.coil3:coil-compose-core-android:3.0.0-alpha10 +| | | | | +--- com.google.accompanist:accompanist-drawablepainter:0.34.0 +| | | | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) +| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.9.0 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) +| | | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) +| | | | | +--- org.jetbrains.compose.foundation:foundation:1.6.11 -> 1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) +| | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.material:material:1.7.0-rc01 +| | | | | +--- androidx.compose.material:material:1.7.1 -> 1.7.2 +| | | | | | \--- androidx.compose.material:material-android:1.7.2 +| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| | | | | | +--- androidx.compose.animation:animation:1.7.2 (*) +| | | | | | +--- androidx.compose.animation:animation-core:1.7.2 (*) +| | | | | | +--- androidx.compose.foundation:foundation:1.7.2 (*) +| | | | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) +| | | | | | +--- androidx.compose.material:material-ripple:1.7.2 (*) +| | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (*) +| | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) +| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) +| | | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) +| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | | +--- org.jetbrains.compose.animation:animation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.animation:animation-core:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.foundation:foundation-layout:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.material:material-icons-core:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.material:material-ripple:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui-text:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.material3:material3:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.material:material-icons-extended:1.7.0-rc01 +| | | | | +--- androidx.compose.material:material-icons-extended:1.7.1 -> 1.7.2 (*) +| | | | | +--- org.jetbrains.compose.material:material-icons-core:1.7.0-rc01 (*) +| | | | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | | | \--- org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.ui:ui-util:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.components:components-resources:1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 (*) +| | | | \--- com.arkivanov.essenty:back-handler:2.1.0 +| | | | \--- com.arkivanov.essenty:back-handler-android:2.1.0 +| | | | +--- androidx.activity:activity-ktx:1.8.1 -> 1.9.2 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | | \--- com.arkivanov.essenty:utils-internal:2.1.0 +| | | | \--- com.arkivanov.essenty:utils-internal-android:2.1.0 +| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) +| | | +--- project :core:model (*) +| | | +--- project :core:common (*) +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | | +--- io.coil-kt.coil3:coil:3.0.0-alpha10 (*) +| | | +--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) +| | | +--- org.jetbrains.compose.material3:material3:1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.components:components-resources:1.7.0-rc01 (*) +| | | \--- org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 (*) +| | +--- project :core:designsystem (*) +| | +--- project :core:data (*) +| | +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2 (*) +| | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | +--- org.jetbrains.androidx.navigation:navigation-compose:2.8.0-alpha10 +| | | +--- androidx.activity:activity-compose:1.8.0 -> 1.9.2 (*) +| | | +--- androidx.navigation:navigation-compose:2.8.0-rc01 -> 2.8.2 +| | | | +--- androidx.activity:activity-compose:1.8.0 -> 1.9.2 (*) +| | | | +--- androidx.compose.animation:animation:1.7.2 (*) +| | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) +| | | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 (*) +| | | | +--- androidx.compose.ui:ui:1.7.2 (*) +| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2 -> 2.8.6 (*) +| | | | +--- androidx.navigation:navigation-runtime-ktx:2.8.2 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) +| | | | +--- androidx.navigation:navigation-runtime-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-common-ktx:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-runtime:2.8.2 (c) +| | | | +--- androidx.navigation:navigation-fragment:2.8.2 (c) +| | | | \--- androidx.navigation:navigation-common:2.8.2 (c) +| | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2 (*) +| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | | +--- org.jetbrains.androidx.navigation:navigation-common:2.8.0-alpha10 +| | | | +--- androidx.core:core-ktx:1.1.0 -> 1.13.1 (*) +| | | | +--- androidx.navigation:navigation-common:2.8.0-rc01 -> 2.8.2 (*) +| | | | +--- androidx.profileinstaller:profileinstaller:1.3.0 -> 1.4.0 (*) +| | | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.2 -> 1.7.2 (*) +| | | +--- org.jetbrains.androidx.navigation:navigation-runtime:2.8.0-alpha10 +| | | | +--- androidx.activity:activity-ktx:1.7.1 -> 1.9.2 (*) +| | | | +--- androidx.navigation:navigation-runtime:2.8.0-rc01 -> 2.8.2 (*) +| | | | +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| | | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| | | | +--- org.jetbrains.androidx.navigation:navigation-common:2.8.0-alpha10 (*) +| | | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| | | | +--- org.jetbrains.compose.annotation-internal:annotation:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | | +--- org.jetbrains.compose.collection-internal:collection:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) +| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.2 -> 1.7.2 (*) +| | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| | | +--- org.jetbrains.compose.animation:animation:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.animation:animation-core:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.foundation:foundation-layout:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.runtime:runtime-saveable:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | +--- org.jetbrains.compose.ui:ui:1.7.0-beta02 -> 1.7.0-rc01 (*) +| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.2 -> 1.7.2 (*) +| | +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| | +--- project :core:domain +| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) +| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| | | +--- project :core:common (*) +| | | +--- project :core:data (*) +| | | \--- project :core:model (*) +| | +--- org.jetbrains.compose.material3:material3:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.ui:ui:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.components:components-resources:1.7.0-rc01 (*) +| | +--- org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 (*) +| | +--- io.insert-koin:koin-compose-viewmodel:1.2.0-Beta4 -> 4.0.0-RC2 (*) +| | +--- io.insert-koin:koin-compose:1.2.0-Beta4 -> 4.0.0-RC2 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | +--- org.jetbrains.kotlin:kotlin-reflect:2.0.20 +| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) +| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) +| +--- project :core:ui (*) +| +--- project :core:designsystem (*) +| +--- org.jetbrains.compose.runtime:runtime:1.7.0-rc01 (*) +| +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2 (*) +| +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.2 -> 2.8.3-rc01 (*) +| +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 (*) +| +--- org.jetbrains.androidx.savedstate:savedstate:1.2.2 (*) +| +--- org.jetbrains.androidx.core:core-bundle:1.0.1 (*) +| +--- org.jetbrains.androidx.navigation:navigation-compose:2.8.0-alpha10 (*) +| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) +| +--- project :core:domain (*) +| \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) ++--- project :core:data (*) ++--- androidx.core:core-ktx:1.13.1 (*) ++--- androidx.appcompat:appcompat:1.7.0 (*) ++--- androidx.activity:activity-compose:1.9.2 (*) ++--- androidx.activity:activity-ktx:1.9.2 (*) ++--- androidx.core:core-splashscreen:1.0.1 +| +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) +| \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) ++--- androidx.compose.material3:material3 -> 1.3.0 (*) ++--- androidx.compose.material3.adaptive:adaptive:1.0.0 +| \--- androidx.compose.material3.adaptive:adaptive-android:1.0.0 +| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.2 (*) +| +--- androidx.window:window:1.3.0 (*) +| +--- androidx.window:window-core:1.3.0 +| | \--- androidx.window:window-core-android:1.3.0 +| | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) +| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| | \--- androidx.window:window:1.3.0 (c) +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) +| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) +| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) ++--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 +| \--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 +| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| +--- androidx.compose.animation:animation:1.7.0 -> 1.7.2 (*) +| +--- androidx.compose.animation:animation-core:1.7.0 -> 1.7.2 (*) +| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.foundation:foundation-layout:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (*) +| +--- androidx.compose.ui:ui:1.7.0 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.2 (*) +| +--- androidx.window:window-core:1.3.0 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) +| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) ++--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 +| \--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 +| +--- androidx.activity:activity-compose:1.8.2 -> 1.9.2 (*) +| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) +| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) +| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) +| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (*) +| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.2 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) +| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) +| \--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) ++--- androidx.compose.runtime:runtime-tracing:1.0.0-beta01 +| +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| +--- androidx.compose.runtime:runtime:1.3.3 -> 1.7.2 (*) +| +--- androidx.startup:startup-runtime:1.1.1 (*) +| +--- androidx.tracing:tracing-perfetto:1.0.0 +| | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) +| | +--- androidx.startup:startup-runtime:1.1.1 (*) +| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) +| \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) ++--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) ++--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (*) ++--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) ++--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) ++--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (*) ++--- androidx.lifecycle:lifecycle-extensions:2.2.0 +| +--- androidx.lifecycle:lifecycle-runtime:2.2.0 -> 2.8.6 (*) +| +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) +| +--- androidx.arch.core:core-runtime:2.1.0 -> 2.2.0 (*) +| +--- androidx.fragment:fragment:1.2.0 -> 1.8.2 (*) +| +--- androidx.lifecycle:lifecycle-common:2.2.0 -> 2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-livedata:2.2.0 -> 2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-process:2.2.0 -> 2.8.6 (*) +| +--- androidx.lifecycle:lifecycle-service:2.2.0 -> 2.8.6 (*) +| \--- androidx.lifecycle:lifecycle-viewmodel:2.2.0 -> 2.8.6 (*) ++--- androidx.navigation:navigation-compose:2.8.2 (*) ++--- androidx.profileinstaller:profileinstaller:1.4.0 (*) ++--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) ++--- io.insert-koin:koin-core:4.0.0-RC2 (*) ++--- io.insert-koin:koin-android:4.0.0-RC2 (*) ++--- io.insert-koin:koin-compose:1.2.0-Beta4 -> 4.0.0-RC2 (*) ++--- io.insert-koin:koin-compose-viewmodel:1.2.0-Beta4 -> 4.0.0-RC2 (*) +\--- androidx.compose.runtime:runtime -> 1.7.2 (*) diff --git a/mifospay/dependencies/prodReleaseRuntimeClasspath.txt b/mifospay-android/dependencies/prodReleaseRuntimeClasspath.txt similarity index 69% rename from mifospay/dependencies/prodReleaseRuntimeClasspath.txt rename to mifospay-android/dependencies/prodReleaseRuntimeClasspath.txt index d808c3e69..005b3158c 100644 --- a/mifospay/dependencies/prodReleaseRuntimeClasspath.txt +++ b/mifospay-android/dependencies/prodReleaseRuntimeClasspath.txt @@ -4,36 +4,13 @@ :core:datastore :core:datastore-proto :core:designsystem +:core:domain :core:model :core:network :core:ui -:feature:accounts :feature:auth -:feature:editpassword -:feature:faq -:feature:finance -:feature:history -:feature:home -:feature:invoices -:feature:kyc -:feature:make-transfer -:feature:merchants -:feature:notification -:feature:payments -:feature:profile -:feature:qr -:feature:receipt -:feature:request-money -:feature:savedcards -:feature:search -:feature:send-money -:feature:settings -:feature:standing-instruction -:feature:upi-setup :libs:country-code-picker -:libs:material3-navigation -:libs:mifos-passcode -:libs:pullrefresh +:mifospay-shared androidx.activity:activity-compose:1.9.2 androidx.activity:activity-ktx:1.9.2 androidx.activity:activity:1.9.2 @@ -46,18 +23,12 @@ androidx.arch.core:core-common:2.2.0 androidx.arch.core:core-runtime:2.2.0 androidx.autofill:autofill:1.0.0 androidx.browser:browser:1.8.0 -androidx.camera:camera-core:1.3.4 -androidx.camera:camera-lifecycle:1.3.4 -androidx.camera:camera-video:1.3.4 -androidx.camera:camera-view:1.3.4 androidx.collection:collection-jvm:1.4.4 androidx.collection:collection-ktx:1.4.4 androidx.collection:collection:1.4.4 androidx.compose.animation:animation-android:1.7.2 androidx.compose.animation:animation-core-android:1.7.2 androidx.compose.animation:animation-core:1.7.2 -androidx.compose.animation:animation-graphics-android:1.7.2 -androidx.compose.animation:animation-graphics:1.7.2 androidx.compose.animation:animation:1.7.2 androidx.compose.foundation:foundation-android:1.7.2 androidx.compose.foundation:foundation-layout-android:1.7.2 @@ -70,8 +41,6 @@ androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 androidx.compose.material3.adaptive:adaptive:1.0.0 androidx.compose.material3:material3-android:1.3.0 -androidx.compose.material3:material3-window-size-class-android:1.3.0 -androidx.compose.material3:material3-window-size-class:1.3.0 androidx.compose.material3:material3:1.3.0 androidx.compose.material:material-android:1.7.2 androidx.compose.material:material-icons-core-android:1.7.2 @@ -105,8 +74,8 @@ androidx.concurrent:concurrent-futures:1.1.0 androidx.core:core-ktx:1.13.1 androidx.core:core-splashscreen:1.0.1 androidx.core:core:1.13.1 -androidx.credentials:credentials-play-services-auth:1.3.0-beta01 -androidx.credentials:credentials:1.3.0-beta01 +androidx.credentials:credentials-play-services-auth:1.3.0 +androidx.credentials:credentials:1.3.0 androidx.cursoradapter:cursoradapter:1.0.0 androidx.customview:customview-poolingcontainer:1.0.0 androidx.customview:customview:1.1.0 @@ -153,13 +122,13 @@ androidx.lifecycle:lifecycle-viewmodel:2.8.6 androidx.loader:loader:1.1.0 androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 androidx.metrics:metrics-performance:1.0.0-beta01 -androidx.navigation:navigation-common-ktx:2.8.1 -androidx.navigation:navigation-common:2.8.1 -androidx.navigation:navigation-compose:2.8.1 -androidx.navigation:navigation-fragment-ktx:2.8.1 -androidx.navigation:navigation-fragment:2.8.1 -androidx.navigation:navigation-runtime-ktx:2.8.1 -androidx.navigation:navigation-runtime:2.8.1 +androidx.navigation:navigation-common-ktx:2.8.2 +androidx.navigation:navigation-common:2.8.2 +androidx.navigation:navigation-compose:2.8.2 +androidx.navigation:navigation-fragment-ktx:2.8.2 +androidx.navigation:navigation-fragment:2.8.2 +androidx.navigation:navigation-runtime-ktx:2.8.2 +androidx.navigation:navigation-runtime:2.8.2 androidx.print:print:1.0.0 androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 @@ -181,12 +150,20 @@ androidx.window.extensions.core:core:1.0.0 androidx.window:window-core-android:1.3.0 androidx.window:window-core:1.3.0 androidx.window:window:1.3.0 +co.touchlab:kermit-android:2.0.4 +co.touchlab:kermit-core-android:2.0.4 +co.touchlab:kermit-core:2.0.4 +co.touchlab:kermit:2.0.4 co.touchlab:stately-concurrency-jvm:2.0.7 co.touchlab:stately-concurrency:2.0.7 co.touchlab:stately-concurrent-collections-jvm:2.0.7 co.touchlab:stately-concurrent-collections:2.0.7 co.touchlab:stately-strict-jvm:2.0.7 co.touchlab:stately-strict:2.0.7 +com.arkivanov.essenty:back-handler-android:2.1.0 +com.arkivanov.essenty:back-handler:2.1.0 +com.arkivanov.essenty:utils-internal-android:2.1.0 +com.arkivanov.essenty:utils-internal:2.1.0 com.caverock:androidsvg-aar:1.4 com.google.accompanist:accompanist-drawablepainter:0.34.0 com.google.accompanist:accompanist-pager:0.34.0 @@ -200,7 +177,6 @@ com.google.android.gms:play-services-auth:21.2.0 com.google.android.gms:play-services-base:18.3.0 com.google.android.gms:play-services-basement:18.4.0 com.google.android.gms:play-services-cloud-messaging:17.2.0 -com.google.android.gms:play-services-code-scanner:16.1.0 com.google.android.gms:play-services-fido:21.0.0 com.google.android.gms:play-services-measurement-api:22.1.0 com.google.android.gms:play-services-measurement-base:22.1.0 @@ -211,10 +187,7 @@ com.google.android.gms:play-services-measurement:22.1.0 com.google.android.gms:play-services-stats:17.0.2 com.google.android.gms:play-services-tasks:18.2.0 com.google.android.libraries.identity.googleid:googleid:1.1.1 -com.google.android.odml:image:1.0.0-beta1 -com.google.auto.value:auto-value-annotations:1.6.3 com.google.code.findbugs:jsr305:3.0.2 -com.google.code.gson:gson:2.10.1 com.google.dagger:dagger:2.27 com.google.errorprone:error_prone_annotations:2.26.0 com.google.firebase:firebase-abt:21.1.1 @@ -247,14 +220,8 @@ com.google.guava:failureaccess:1.0.1 com.google.guava:guava:31.1-android com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava com.google.j2objc:j2objc-annotations:1.3 -com.google.mlkit:barcode-scanning-common:17.0.0 -com.google.mlkit:common:18.9.0 -com.google.mlkit:vision-common:17.0.0 com.google.protobuf:protobuf-javalite:4.26.0 com.google.protobuf:protobuf-kotlin-lite:4.26.0 -com.google.zxing:core:3.5.3 -com.maxkeppeler.sheets-compose-dialogs:calendar:1.3.0 -com.maxkeppeler.sheets-compose-dialogs:core:1.3.0 com.russhwolf:multiplatform-settings-android:1.2.0 com.russhwolf:multiplatform-settings-coroutines-android:1.2.0 com.russhwolf:multiplatform-settings-coroutines:1.2.0 @@ -263,22 +230,19 @@ com.russhwolf:multiplatform-settings-no-arg:1.2.0 com.russhwolf:multiplatform-settings-serialization-android:1.2.0 com.russhwolf:multiplatform-settings-serialization:1.2.0 com.russhwolf:multiplatform-settings:1.2.0 +com.squareup.okhttp3:okhttp-sse:4.12.0 com.squareup.okhttp3:okhttp:4.12.0 -com.squareup.okio:okio-jvm:3.9.0 -com.squareup.okio:okio:3.9.0 -com.squareup.retrofit2:converter-gson:2.11.0 -com.squareup.retrofit2:retrofit:2.11.0 +com.squareup.okio:okio-jvm:3.9.1 +com.squareup.okio:okio:3.9.1 de.jensklingenberg.ktorfit:ktorfit-annotations-android:2.1.0 de.jensklingenberg.ktorfit:ktorfit-annotations:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-converters-call-android:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-converters-call:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-converters-flow-android:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-converters-flow:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-lib-android:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-lib-light-android:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 -de.jensklingenberg.ktorfit:ktorfit-lib:2.1.0 -dev.chrisbanes.snapper:snapper:0.3.0 +de.jensklingenberg.ktorfit:ktorfit-lib-ktor-3.0.0-beta-2-android:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-lib-ktor-3.0.0-beta-2:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-lib-light-ktor-3.0.0-beta-2-android:2.1.0 +de.jensklingenberg.ktorfit:ktorfit-lib-light-ktor-3.0.0-beta-2:2.1.0 +dev.chrisbanes.material3:material3-window-size-class-multiplatform-android:0.5.0 +dev.chrisbanes.material3:material3-window-size-class-multiplatform:0.5.0 +dev.chrisbanes.snapper:snapper:0.2.2 io.coil-kt.coil3:coil-android:3.0.0-alpha10 io.coil-kt.coil3:coil-compose-core-android:3.0.0-alpha10 io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 @@ -298,75 +262,101 @@ io.insert-koin:koin-annotations-jvm:1.4.0-RC4 io.insert-koin:koin-annotations:1.4.0-RC4 io.insert-koin:koin-bom:4.0.0-RC2 io.insert-koin:koin-compose-jvm:4.0.0-RC2 +io.insert-koin:koin-compose-viewmodel-jvm:4.0.0-RC2 +io.insert-koin:koin-compose-viewmodel:4.0.0-RC2 io.insert-koin:koin-compose:4.0.0-RC2 io.insert-koin:koin-core-jvm:4.0.0-RC2 io.insert-koin:koin-core-viewmodel-jvm:4.0.0-RC2 io.insert-koin:koin-core-viewmodel:4.0.0-RC2 io.insert-koin:koin-core:4.0.0-RC2 -io.ktor:ktor-client-android-jvm:2.3.4 -io.ktor:ktor-client-android:2.3.4 -io.ktor:ktor-client-cio-jvm:2.3.12 -io.ktor:ktor-client-content-negotiation-jvm:2.3.4 -io.ktor:ktor-client-content-negotiation:2.3.4 -io.ktor:ktor-client-core-jvm:3.0.0-beta-2 -io.ktor:ktor-client-core:3.0.0-beta-2 -io.ktor:ktor-client-json-jvm:2.3.4 -io.ktor:ktor-client-json:2.3.4 -io.ktor:ktor-client-logging-jvm:2.3.4 -io.ktor:ktor-client-logging:2.3.4 -io.ktor:ktor-client-serialization-jvm:2.3.4 -io.ktor:ktor-client-serialization:2.3.4 -io.ktor:ktor-events-jvm:3.0.0-beta-2 -io.ktor:ktor-events:3.0.0-beta-2 -io.ktor:ktor-http-cio-jvm:2.3.12 -io.ktor:ktor-http-cio:2.3.12 -io.ktor:ktor-http-jvm:3.0.0-beta-2 -io.ktor:ktor-http:3.0.0-beta-2 -io.ktor:ktor-io-jvm:3.0.0-beta-2 -io.ktor:ktor-io:3.0.0-beta-2 -io.ktor:ktor-network-jvm:2.3.12 -io.ktor:ktor-network-tls-jvm:2.3.12 -io.ktor:ktor-network-tls:2.3.12 -io.ktor:ktor-network:2.3.12 -io.ktor:ktor-serialization-jvm:3.0.0-beta-2 -io.ktor:ktor-serialization-kotlinx-json-jvm:2.3.4 -io.ktor:ktor-serialization-kotlinx-json:2.3.4 -io.ktor:ktor-serialization-kotlinx-jvm:2.3.4 -io.ktor:ktor-serialization-kotlinx:2.3.4 -io.ktor:ktor-serialization:3.0.0-beta-2 -io.ktor:ktor-sse-jvm:3.0.0-beta-2 -io.ktor:ktor-sse:3.0.0-beta-2 -io.ktor:ktor-utils-jvm:3.0.0-beta-2 -io.ktor:ktor-utils:3.0.0-beta-2 -io.ktor:ktor-websocket-serialization-jvm:3.0.0-beta-2 -io.ktor:ktor-websocket-serialization:3.0.0-beta-2 -io.ktor:ktor-websockets-jvm:3.0.0-beta-2 -io.ktor:ktor-websockets:3.0.0-beta-2 +io.ktor:ktor-client-auth-jvm:3.0.0-rc-1 +io.ktor:ktor-client-auth:3.0.0-rc-1 +io.ktor:ktor-client-cio-jvm:3.0.0-beta-2 +io.ktor:ktor-client-content-negotiation-jvm:3.0.0-rc-1 +io.ktor:ktor-client-content-negotiation:3.0.0-rc-1 +io.ktor:ktor-client-core-jvm:3.0.0-rc-1 +io.ktor:ktor-client-core:3.0.0-rc-1 +io.ktor:ktor-client-json-jvm:3.0.0-rc-1 +io.ktor:ktor-client-json:3.0.0-rc-1 +io.ktor:ktor-client-logging-jvm:3.0.0-rc-1 +io.ktor:ktor-client-logging:3.0.0-rc-1 +io.ktor:ktor-client-okhttp-jvm:3.0.0-rc-1 +io.ktor:ktor-client-okhttp:3.0.0-rc-1 +io.ktor:ktor-client-serialization-jvm:3.0.0-rc-1 +io.ktor:ktor-client-serialization:3.0.0-rc-1 +io.ktor:ktor-events-jvm:3.0.0-rc-1 +io.ktor:ktor-events:3.0.0-rc-1 +io.ktor:ktor-http-cio-jvm:3.0.0-beta-2 +io.ktor:ktor-http-cio:3.0.0-beta-2 +io.ktor:ktor-http-jvm:3.0.0-rc-1 +io.ktor:ktor-http:3.0.0-rc-1 +io.ktor:ktor-io-jvm:3.0.0-rc-1 +io.ktor:ktor-io:3.0.0-rc-1 +io.ktor:ktor-network-jvm:3.0.0-beta-2 +io.ktor:ktor-network-tls-jvm:3.0.0-beta-2 +io.ktor:ktor-network-tls:3.0.0-beta-2 +io.ktor:ktor-network:3.0.0-beta-2 +io.ktor:ktor-serialization-jvm:3.0.0-rc-1 +io.ktor:ktor-serialization-kotlinx-json-jvm:3.0.0-rc-1 +io.ktor:ktor-serialization-kotlinx-json:3.0.0-rc-1 +io.ktor:ktor-serialization-kotlinx-jvm:3.0.0-rc-1 +io.ktor:ktor-serialization-kotlinx:3.0.0-rc-1 +io.ktor:ktor-serialization:3.0.0-rc-1 +io.ktor:ktor-sse-jvm:3.0.0-rc-1 +io.ktor:ktor-sse:3.0.0-rc-1 +io.ktor:ktor-utils-jvm:3.0.0-rc-1 +io.ktor:ktor-utils:3.0.0-rc-1 +io.ktor:ktor-websocket-serialization-jvm:3.0.0-rc-1 +io.ktor:ktor-websocket-serialization:3.0.0-rc-1 +io.ktor:ktor-websockets-jvm:3.0.0-rc-1 +io.ktor:ktor-websockets:3.0.0-rc-1 io.michaelrocks:libphonenumber-android:8.13.35 javax.inject:javax.inject:1 org.checkerframework:checker-qual:3.12.0 -org.jetbrains.androidx.core:core-bundle-android:1.0.0 -org.jetbrains.androidx.core:core-bundle:1.0.0 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 -org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.0 -org.jetbrains.androidx.savedstate:savedstate:1.2.0 -org.jetbrains.compose.components:components-resources-android:1.6.11 -org.jetbrains.compose.components:components-resources:1.6.11 -org.jetbrains.compose.components:components-ui-tooling-preview-android:1.6.11 -org.jetbrains.compose.components:components-ui-tooling-preview:1.6.11 -org.jetbrains.compose.foundation:foundation:1.6.11 -org.jetbrains.compose.material3:material3:1.6.11 -org.jetbrains.compose.material:material-icons-extended:1.6.11 -org.jetbrains.compose.material:material:1.6.11 -org.jetbrains.compose.runtime:runtime:1.6.11 -org.jetbrains.compose.ui:ui-util:1.6.11 -org.jetbrains.compose.ui:ui:1.6.11 +org.jetbrains.androidx.core:core-bundle-android:1.0.1 +org.jetbrains.androidx.core:core-bundle:1.0.1 +org.jetbrains.androidx.lifecycle:lifecycle-common:2.8.3-rc01 +org.jetbrains.androidx.lifecycle:lifecycle-runtime-compose:2.8.3-rc01 +org.jetbrains.androidx.lifecycle:lifecycle-runtime:2.8.3-rc01 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose:2.8.2 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2 +org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.3-rc01 +org.jetbrains.androidx.navigation:navigation-common:2.8.0-alpha10 +org.jetbrains.androidx.navigation:navigation-compose:2.8.0-alpha10 +org.jetbrains.androidx.navigation:navigation-runtime:2.8.0-alpha10 +org.jetbrains.androidx.savedstate:savedstate:1.2.2 +org.jetbrains.compose.animation:animation-core:1.7.0-rc01 +org.jetbrains.compose.animation:animation:1.7.0-rc01 +org.jetbrains.compose.annotation-internal:annotation:1.7.0-rc01 +org.jetbrains.compose.collection-internal:collection:1.7.0-rc01 +org.jetbrains.compose.components:components-resources-android:1.7.0-rc01 +org.jetbrains.compose.components:components-resources:1.7.0-rc01 +org.jetbrains.compose.components:components-ui-tooling-preview-android:1.7.0-rc01 +org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 +org.jetbrains.compose.foundation:foundation-layout:1.7.0-rc01 +org.jetbrains.compose.foundation:foundation:1.7.0-rc01 +org.jetbrains.compose.material3:material3:1.7.0-rc01 +org.jetbrains.compose.material:material-icons-core:1.7.0-rc01 +org.jetbrains.compose.material:material-icons-extended:1.7.0-rc01 +org.jetbrains.compose.material:material-ripple:1.7.0-rc01 +org.jetbrains.compose.material:material:1.7.0-rc01 +org.jetbrains.compose.runtime:runtime-saveable:1.7.0-rc01 +org.jetbrains.compose.runtime:runtime:1.7.0-rc01 +org.jetbrains.compose.ui:ui-geometry:1.7.0-rc01 +org.jetbrains.compose.ui:ui-graphics:1.7.0-rc01 +org.jetbrains.compose.ui:ui-text:1.7.0-rc01 +org.jetbrains.compose.ui:ui-unit:1.7.0-rc01 +org.jetbrains.compose.ui:ui-util:1.7.0-rc01 +org.jetbrains.compose.ui:ui:1.7.0-rc01 org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.20 org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 +org.jetbrains.kotlin:kotlin-reflect:2.0.20 org.jetbrains.kotlin:kotlin-stdlib-common:2.0.20 -org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.20 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20 org.jetbrains.kotlin:kotlin-stdlib:2.0.20 +org.jetbrains.kotlinx:atomicfu-jvm:0.23.2 +org.jetbrains.kotlinx:atomicfu:0.23.2 org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.8 org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 @@ -376,16 +366,16 @@ org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.9.0 org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0 org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.9.0 -org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.0 -org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 -org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.5.1 -org.jetbrains.kotlinx:kotlinx-io-bytestring:0.5.1 -org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.5.1 -org.jetbrains.kotlinx:kotlinx-io-core:0.5.1 +org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.1 +org.jetbrains.kotlinx:kotlinx-datetime:0.6.1 +org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.5.3 +org.jetbrains.kotlinx:kotlinx-io-bytestring:0.5.3 +org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.5.3 +org.jetbrains.kotlinx:kotlinx-io-core:0.5.3 org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 org.jetbrains:annotations:23.0.0 -org.slf4j:slf4j-api:2.0.13 +org.slf4j:slf4j-api:2.0.16 diff --git a/mifospay/google-services.json b/mifospay-android/google-services.json similarity index 100% rename from mifospay/google-services.json rename to mifospay-android/google-services.json diff --git a/mifospay/lint-baseline.xml b/mifospay-android/lint-baseline.xml similarity index 100% rename from mifospay/lint-baseline.xml rename to mifospay-android/lint-baseline.xml diff --git a/mifospay/prodRelease-badging.txt b/mifospay-android/prodRelease-badging.txt similarity index 81% rename from mifospay/prodRelease-badging.txt rename to mifospay-android/prodRelease-badging.txt index 0b23830ab..7d11a2720 100644 --- a/mifospay/prodRelease-badging.txt +++ b/mifospay-android/prodRelease-badging.txt @@ -1,4 +1,4 @@ -package: name='org.mifospay' versionCode='1' versionName='0.0.2-beta.0.2' platformBuildVersionName='14' platformBuildVersionCode='34' compileSdkVersion='34' compileSdkVersionCodename='14' +package: name='org.mifospay' versionCode='1' versionName='0.0.4-beta.0.7' platformBuildVersionName='14' platformBuildVersionCode='34' compileSdkVersion='34' compileSdkVersionCodename='14' sdkVersion:'26' targetSdkVersion:'34' uses-permission: name='android.permission.INTERNET' @@ -7,7 +7,6 @@ uses-permission: name='android.permission.READ_EXTERNAL_STORAGE' uses-permission: name='android.permission.WRITE_EXTERNAL_STORAGE' uses-permission: name='android.permission.READ_CONTACTS' uses-permission: name='android.permission.ACCESS_NETWORK_STATE' -uses-permission: name='android.permission.VIBRATE' uses-permission: name='android.permission.POST_NOTIFICATIONS' uses-permission: name='android.permission.WAKE_LOCK' uses-permission: name='com.google.android.c2dm.permission.RECEIVE' @@ -29,14 +28,12 @@ application-label-ca:'Mifos Pay' application-label-cs:'Mifos Pay' application-label-da:'Mifos Pay' application-label-de:'Mifos Pay' -application-label-de-DE:'Mifos Pay' application-label-el:'Mifos Pay' application-label-en-AU:'Mifos Pay' application-label-en-CA:'Mifos Pay' application-label-en-GB:'Mifos Pay' application-label-en-IN:'Mifos Pay' application-label-en-XC:'Mifos Pay' -application-label-eo:'Mifos Pay' application-label-es:'Mifos Pay' application-label-es-US:'Mifos Pay' application-label-et:'Mifos Pay' @@ -45,8 +42,6 @@ application-label-fa:'Mifos Pay' application-label-fi:'Mifos Pay' application-label-fr:'Mifos Pay' application-label-fr-CA:'Mifos Pay' -application-label-ga:'Mifos Pay' -application-label-gd:'Mifos Pay' application-label-gl:'Mifos Pay' application-label-gu:'Mifos Pay' application-label-hi:'Mifos Pay' @@ -54,21 +49,17 @@ application-label-hr:'Mifos Pay' application-label-hu:'Mifos Pay' application-label-hy:'Mifos Pay' application-label-in:'Mifos Pay' -application-label-in-ID:'Mifos Pay' application-label-is:'Mifos Pay' application-label-it:'Mifos Pay' application-label-it-IT:'Mifos Pay' application-label-iw:'Mifos Pay' application-label-ja:'Mifos Pay' -application-label-jv:'Mifos Pay' application-label-ka:'Mifos Pay' application-label-kk:'Mifos Pay' application-label-km:'Mifos Pay' application-label-kn:'Mifos Pay' application-label-ko:'Mifos Pay' -application-label-ku:'Mifos Pay' application-label-ky:'Mifos Pay' -application-label-lb:'Mifos Pay' application-label-lo:'Mifos Pay' application-label-lt:'Mifos Pay' application-label-lv:'Mifos Pay' @@ -81,7 +72,6 @@ application-label-my:'Mifos Pay' application-label-nb:'Mifos Pay' application-label-ne:'Mifos Pay' application-label-nl:'Mifos Pay' -application-label-no:'Mifos Pay' application-label-or:'Mifos Pay' application-label-pa:'Mifos Pay' application-label-pl:'Mifos Pay' @@ -130,14 +120,12 @@ feature-group: label='' uses-feature-not-required: name='android.hardware.camera' uses-feature: name='android.hardware.faketouch' uses-implied-feature: name='android.hardware.faketouch' reason='default feature for all apps' - uses-feature: name='android.hardware.screen.portrait' - uses-implied-feature: name='android.hardware.screen.portrait' reason='one or more activities have specified a portrait orientation' main other-activities other-receivers other-services supports-screens: 'small' 'normal' 'large' 'xlarge' supports-any-density: 'true' -locales: '--_--' 'af' 'am' 'ar' 'as' 'az' 'be' 'bg' 'bn' 'bs' 'ca' 'cs' 'da' 'de' 'de-DE' 'el' 'en-AU' 'en-CA' 'en-GB' 'en-IN' 'en-XC' 'eo' 'es' 'es-US' 'et' 'eu' 'fa' 'fi' 'fr' 'fr-CA' 'ga' 'gd' 'gl' 'gu' 'hi' 'hr' 'hu' 'hy' 'in' 'in-ID' 'is' 'it' 'it-IT' 'iw' 'ja' 'jv' 'ka' 'kk' 'km' 'kn' 'ko' 'ku' 'ky' 'lb' 'lo' 'lt' 'lv' 'mk' 'ml' 'mn' 'mr' 'ms' 'my' 'nb' 'ne' 'nl' 'no' 'or' 'pa' 'pl' 'pt' 'pt-BR' 'pt-PT' 'ro' 'ru' 'ru-RU' 'si' 'sk' 'sl' 'so' 'sq' 'sr' 'sr-Latn' 'sv' 'sw' 'ta' 'te' 'th' 'tl' 'tr' 'tr-TR' 'uk' 'ur' 'uz' 'vi' 'zh' 'zh-CN' 'zh-HK' 'zh-TW' 'zu' +locales: '--_--' 'af' 'am' 'ar' 'as' 'az' 'be' 'bg' 'bn' 'bs' 'ca' 'cs' 'da' 'de' 'el' 'en-AU' 'en-CA' 'en-GB' 'en-IN' 'en-XC' 'es' 'es-US' 'et' 'eu' 'fa' 'fi' 'fr' 'fr-CA' 'gl' 'gu' 'hi' 'hr' 'hu' 'hy' 'in' 'is' 'it' 'it-IT' 'iw' 'ja' 'ka' 'kk' 'km' 'kn' 'ko' 'ky' 'lo' 'lt' 'lv' 'mk' 'ml' 'mn' 'mr' 'ms' 'my' 'nb' 'ne' 'nl' 'or' 'pa' 'pl' 'pt' 'pt-BR' 'pt-PT' 'ro' 'ru' 'ru-RU' 'si' 'sk' 'sl' 'so' 'sq' 'sr' 'sr-Latn' 'sv' 'sw' 'ta' 'te' 'th' 'tl' 'tr' 'tr-TR' 'uk' 'ur' 'uz' 'vi' 'zh' 'zh-CN' 'zh-HK' 'zh-TW' 'zu' densities: '160' '240' '320' '480' '640' native-code: 'arm64-v8a' 'armeabi-v7a' 'x86' 'x86_64' diff --git a/mifospay/proguard-rules.pro b/mifospay-android/proguard-rules.pro similarity index 100% rename from mifospay/proguard-rules.pro rename to mifospay-android/proguard-rules.pro diff --git a/mifospay/release_keystore.keystore b/mifospay-android/release_keystore.keystore similarity index 100% rename from mifospay/release_keystore.keystore rename to mifospay-android/release_keystore.keystore diff --git a/mifospay/src/androidTest/java/org/mifospay/ExampleInstrumentedTest.kt b/mifospay-android/src/androidTest/java/org/mifospay/ExampleInstrumentedTest.kt similarity index 100% rename from mifospay/src/androidTest/java/org/mifospay/ExampleInstrumentedTest.kt rename to mifospay-android/src/androidTest/java/org/mifospay/ExampleInstrumentedTest.kt diff --git a/mifospay/src/main/AndroidManifest.xml b/mifospay-android/src/main/AndroidManifest.xml similarity index 94% rename from mifospay/src/main/AndroidManifest.xml rename to mifospay-android/src/main/AndroidManifest.xml index c2e70fff0..7e621eda9 100644 --- a/mifospay/src/main/AndroidManifest.xml +++ b/mifospay-android/src/main/AndroidManifest.xml @@ -73,10 +73,6 @@ - - true + is MainUiState.Success -> false + } + } + + setContent { + MifosPaySharedApp( + networkMonitor = networkMonitor, + timeZoneMonitor = timeZoneMonitor, + ) + } + } +} diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/MyApplication.kt b/mifospay-android/src/main/kotlin/org/mifospay/MifosPayApp.kt similarity index 58% rename from shared/src/androidMain/kotlin/org/mifospay/shared/MyApplication.kt rename to mifospay-android/src/main/kotlin/org/mifospay/MifosPayApp.kt index 6fccb03bf..de10c0aba 100644 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/MyApplication.kt +++ b/mifospay-android/src/main/kotlin/org/mifospay/MifosPayApp.kt @@ -7,18 +7,22 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.shared +package org.mifospay import android.app.Application import org.koin.android.ext.koin.androidContext -import org.mifospay.shared.di.initKoin - -class MyApplication : Application() { +import org.koin.android.ext.koin.androidLogger +import org.koin.core.context.GlobalContext.startKoin +import org.mifospay.shared.di.KoinModules +class MifosPayApp : Application() { override fun onCreate() { super.onCreate() - initKoin { - androidContext(this@MyApplication) + + startKoin { + androidContext(this@MifosPayApp) + androidLogger() + modules(KoinModules.allModules) } } } diff --git a/mifospay/src/main/java/org/mifospay/data/firebase/api/services/MifosPayMessagingService.kt b/mifospay-android/src/main/kotlin/org/mifospay/data/firebase/api/services/MifosPayMessagingService.kt similarity index 100% rename from mifospay/src/main/java/org/mifospay/data/firebase/api/services/MifosPayMessagingService.kt rename to mifospay-android/src/main/kotlin/org/mifospay/data/firebase/api/services/MifosPayMessagingService.kt diff --git a/mifospay/src/main/java/org/mifospay/utils/NotificationUtils.kt b/mifospay-android/src/main/kotlin/org/mifospay/utils/NotificationUtils.kt similarity index 100% rename from mifospay/src/main/java/org/mifospay/utils/NotificationUtils.kt rename to mifospay-android/src/main/kotlin/org/mifospay/utils/NotificationUtils.kt diff --git a/mifospay/src/main/res/drawable/bg_splash.xml b/mifospay-android/src/main/res/drawable/bg_splash.xml similarity index 100% rename from mifospay/src/main/res/drawable/bg_splash.xml rename to mifospay-android/src/main/res/drawable/bg_splash.xml diff --git a/mifospay/src/main/res/drawable/bg_splash_12.xml b/mifospay-android/src/main/res/drawable/bg_splash_12.xml similarity index 100% rename from mifospay/src/main/res/drawable/bg_splash_12.xml rename to mifospay-android/src/main/res/drawable/bg_splash_12.xml diff --git a/mifospay-android/src/main/res/drawable/feature_accounts_ic_bank.xml b/mifospay-android/src/main/res/drawable/feature_accounts_ic_bank.xml new file mode 100644 index 000000000..a7856762d --- /dev/null +++ b/mifospay-android/src/main/res/drawable/feature_accounts_ic_bank.xml @@ -0,0 +1,28 @@ + + + + + + \ No newline at end of file diff --git a/mifospay-android/src/main/res/drawable/feature_receipt_mifospay_round_logo.png b/mifospay-android/src/main/res/drawable/feature_receipt_mifospay_round_logo.png new file mode 100644 index 000000000..38b8ada8c Binary files /dev/null and b/mifospay-android/src/main/res/drawable/feature_receipt_mifospay_round_logo.png differ diff --git a/mifospay/src/main/res/drawable/ic_finance.xml b/mifospay-android/src/main/res/drawable/ic_finance.xml similarity index 100% rename from mifospay/src/main/res/drawable/ic_finance.xml rename to mifospay-android/src/main/res/drawable/ic_finance.xml diff --git a/mifospay/src/main/res/drawable/ic_home.xml b/mifospay-android/src/main/res/drawable/ic_home.xml similarity index 100% rename from mifospay/src/main/res/drawable/ic_home.xml rename to mifospay-android/src/main/res/drawable/ic_home.xml diff --git a/mifospay/src/main/res/drawable/ic_person.xml b/mifospay-android/src/main/res/drawable/ic_person.xml similarity index 100% rename from mifospay/src/main/res/drawable/ic_person.xml rename to mifospay-android/src/main/res/drawable/ic_person.xml diff --git a/mifospay/src/main/res/drawable/ic_swap_horiz.xml b/mifospay-android/src/main/res/drawable/ic_swap_horiz.xml similarity index 100% rename from mifospay/src/main/res/drawable/ic_swap_horiz.xml rename to mifospay-android/src/main/res/drawable/ic_swap_horiz.xml diff --git a/mifospay/src/main/res/drawable/logo_axis.png b/mifospay-android/src/main/res/drawable/logo_axis.png similarity index 100% rename from mifospay/src/main/res/drawable/logo_axis.png rename to mifospay-android/src/main/res/drawable/logo_axis.png diff --git a/mifospay/src/main/res/drawable/logo_hdfc.png b/mifospay-android/src/main/res/drawable/logo_hdfc.png similarity index 100% rename from mifospay/src/main/res/drawable/logo_hdfc.png rename to mifospay-android/src/main/res/drawable/logo_hdfc.png diff --git a/mifospay/src/main/res/drawable/logo_icici.png b/mifospay-android/src/main/res/drawable/logo_icici.png similarity index 100% rename from mifospay/src/main/res/drawable/logo_icici.png rename to mifospay-android/src/main/res/drawable/logo_icici.png diff --git a/mifospay/src/main/res/drawable/logo_pnb.png b/mifospay-android/src/main/res/drawable/logo_pnb.png similarity index 100% rename from mifospay/src/main/res/drawable/logo_pnb.png rename to mifospay-android/src/main/res/drawable/logo_pnb.png diff --git a/mifospay/src/main/res/drawable/logo_rbl.png b/mifospay-android/src/main/res/drawable/logo_rbl.png similarity index 100% rename from mifospay/src/main/res/drawable/logo_rbl.png rename to mifospay-android/src/main/res/drawable/logo_rbl.png diff --git a/mifospay/src/main/res/drawable/logo_sbi.png b/mifospay-android/src/main/res/drawable/logo_sbi.png similarity index 100% rename from mifospay/src/main/res/drawable/logo_sbi.png rename to mifospay-android/src/main/res/drawable/logo_sbi.png diff --git a/mifospay-android/src/main/res/drawable/mifospay_round_logo.png b/mifospay-android/src/main/res/drawable/mifospay_round_logo.png new file mode 100644 index 000000000..38b8ada8c Binary files /dev/null and b/mifospay-android/src/main/res/drawable/mifospay_round_logo.png differ diff --git a/mifospay/src/main/res/drawable/money_in.png b/mifospay-android/src/main/res/drawable/money_in.png similarity index 100% rename from mifospay/src/main/res/drawable/money_in.png rename to mifospay-android/src/main/res/drawable/money_in.png diff --git a/mifospay/src/main/res/drawable/money_out.png b/mifospay-android/src/main/res/drawable/money_out.png similarity index 100% rename from mifospay/src/main/res/drawable/money_out.png rename to mifospay-android/src/main/res/drawable/money_out.png diff --git a/mifospay/src/main/res/drawable/splash_icon.png b/mifospay-android/src/main/res/drawable/splash_icon.png similarity index 100% rename from mifospay/src/main/res/drawable/splash_icon.png rename to mifospay-android/src/main/res/drawable/splash_icon.png diff --git a/mifospay/src/main/res/drawable/splash_screen_background.xml b/mifospay-android/src/main/res/drawable/splash_screen_background.xml similarity index 100% rename from mifospay/src/main/res/drawable/splash_screen_background.xml rename to mifospay-android/src/main/res/drawable/splash_screen_background.xml diff --git a/mifospay/src/main/res/mipmap/ic_launcher.png b/mifospay-android/src/main/res/mipmap/ic_launcher.png similarity index 100% rename from mifospay/src/main/res/mipmap/ic_launcher.png rename to mifospay-android/src/main/res/mipmap/ic_launcher.png diff --git a/mifospay/src/main/res/mipmap/ic_launcher_round.png b/mifospay-android/src/main/res/mipmap/ic_launcher_round.png similarity index 100% rename from mifospay/src/main/res/mipmap/ic_launcher_round.png rename to mifospay-android/src/main/res/mipmap/ic_launcher_round.png diff --git a/mifospay/src/main/res/values/colors.xml b/mifospay-android/src/main/res/values/colors.xml similarity index 100% rename from mifospay/src/main/res/values/colors.xml rename to mifospay-android/src/main/res/values/colors.xml diff --git a/mifospay/src/main/res/values/splash.xml b/mifospay-android/src/main/res/values/splash.xml similarity index 100% rename from mifospay/src/main/res/values/splash.xml rename to mifospay-android/src/main/res/values/splash.xml diff --git a/mifospay/src/main/res/values/strings.xml b/mifospay-android/src/main/res/values/strings.xml similarity index 100% rename from mifospay/src/main/res/values/strings.xml rename to mifospay-android/src/main/res/values/strings.xml diff --git a/mifospay/src/main/res/xml/provider_paths.xml b/mifospay-android/src/main/res/xml/provider_paths.xml similarity index 100% rename from mifospay/src/main/res/xml/provider_paths.xml rename to mifospay-android/src/main/res/xml/provider_paths.xml diff --git a/mifospay/src/test/java/org/mifospay/KoinModulesCheck.kt b/mifospay-android/src/test/java/org/mifospay/KoinModulesCheck.kt similarity index 100% rename from mifospay/src/test/java/org/mifospay/KoinModulesCheck.kt rename to mifospay-android/src/test/java/org/mifospay/KoinModulesCheck.kt diff --git a/mifospay-desktop/.gitignore b/mifospay-desktop/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/mifospay-desktop/.gitignore @@ -0,0 +1 @@ +/build diff --git a/mifospay-desktop/README.md b/mifospay-desktop/README.md new file mode 100644 index 000000000..8890fe470 --- /dev/null +++ b/mifospay-desktop/README.md @@ -0,0 +1 @@ +To run in desktop mode, choose the `mifospay-desktop` profile and click run. \ No newline at end of file diff --git a/desktop/build.gradle.kts b/mifospay-desktop/build.gradle.kts similarity index 69% rename from desktop/build.gradle.kts rename to mifospay-desktop/build.gradle.kts index 9d19e838c..50acb149a 100644 --- a/desktop/build.gradle.kts +++ b/mifospay-desktop/build.gradle.kts @@ -10,23 +10,33 @@ import org.jetbrains.compose.desktop.application.dsl.TargetFormat plugins { - kotlin("multiplatform") + alias(libs.plugins.kotlinMultiplatform) alias(libs.plugins.compose.compiler) alias(libs.plugins.jetbrainsCompose) + alias(libs.plugins.kotlin.serialization) } kotlin { - jvm { + jvm("desktop") { withJava() } jvmToolchain(21) sourceSets { - val jvmMain by getting { + val desktopMain by getting { dependencies { - implementation(project(":shared")) + implementation(projects.core.common) + implementation(projects.core.data) + implementation(projects.core.model) + implementation(projects.core.datastore) + + implementation(projects.mifospayShared) + + implementation(libs.kotlinx.coroutines.swing) implementation(compose.desktop.currentOs) + implementation(libs.jb.kotlin.stdlib) + implementation(libs.kotlin.reflect) } } } diff --git a/desktop/src/jvmMain/kotlin/Main.kt b/mifospay-desktop/src/desktopMain/kotlin/main.kt similarity index 90% rename from desktop/src/jvmMain/kotlin/Main.kt rename to mifospay-desktop/src/desktopMain/kotlin/main.kt index da0e58814..cc41a30a2 100644 --- a/desktop/src/jvmMain/kotlin/Main.kt +++ b/mifospay-desktop/src/desktopMain/kotlin/main.kt @@ -7,10 +7,11 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ + import androidx.compose.ui.window.Window import androidx.compose.ui.window.application import androidx.compose.ui.window.rememberWindowState -import org.mifospay.shared.MainView +import org.mifospay.shared.MifosPaySharedApp import org.mifospay.shared.di.initKoin fun main() { @@ -22,7 +23,7 @@ fun main() { state = windowState, title = "MifosWallet", ) { - MainView() + MifosPaySharedApp() } } } diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/mifospay-ios/iosApp.xcodeproj/project.pbxproj similarity index 100% rename from iosApp/iosApp.xcodeproj/project.pbxproj rename to mifospay-ios/iosApp.xcodeproj/project.pbxproj diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mifospay-ios/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to mifospay-ios/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/mifospay-ios/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to mifospay-ios/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate b/mifospay-ios/iosApp.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate similarity index 100% rename from iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate rename to mifospay-ios/iosApp.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist b/mifospay-ios/iosApp.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist similarity index 100% rename from iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist rename to mifospay-ios/iosApp.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/iosApp/iosApp.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/iosApp.xcscheme b/mifospay-ios/iosApp.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/iosApp.xcscheme similarity index 100% rename from iosApp/iosApp.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/iosApp.xcscheme rename to mifospay-ios/iosApp.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/iosApp.xcscheme diff --git a/iosApp/iosApp.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist b/mifospay-ios/iosApp.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist similarity index 100% rename from iosApp/iosApp.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist rename to mifospay-ios/iosApp.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist diff --git a/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json b/mifospay-ios/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json rename to mifospay-ios/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/mifospay-ios/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json rename to mifospay-ios/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/iosApp/iosApp/Assets.xcassets/Contents.json b/mifospay-ios/iosApp/Assets.xcassets/Contents.json similarity index 100% rename from iosApp/iosApp/Assets.xcassets/Contents.json rename to mifospay-ios/iosApp/Assets.xcassets/Contents.json diff --git a/iosApp/iosApp/ContentView.swift b/mifospay-ios/iosApp/ContentView.swift similarity index 93% rename from iosApp/iosApp/ContentView.swift rename to mifospay-ios/iosApp/ContentView.swift index db5219cba..6c5b7759f 100644 --- a/iosApp/iosApp/ContentView.swift +++ b/mifospay-ios/iosApp/ContentView.swift @@ -1,6 +1,6 @@ // // ContentView.swift -// iosApp +// mifospay-ios // // Created by Apple on 14/08/24. // diff --git a/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json b/mifospay-ios/iosApp/Preview Content/Preview Assets.xcassets/Contents.json similarity index 100% rename from iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json rename to mifospay-ios/iosApp/Preview Content/Preview Assets.xcassets/Contents.json diff --git a/iosApp/iosApp/iosAppApp.swift b/mifospay-ios/iosApp/iosAppApp.swift similarity index 92% rename from iosApp/iosApp/iosAppApp.swift rename to mifospay-ios/iosApp/iosAppApp.swift index 3efc48a9d..c3f629220 100644 --- a/iosApp/iosApp/iosAppApp.swift +++ b/mifospay-ios/iosApp/iosAppApp.swift @@ -1,6 +1,6 @@ // // iosAppApp.swift -// iosApp +// mifospay-ios // // Created by Apple on 14/08/24. // diff --git a/mifospay-shared/build.gradle.kts b/mifospay-shared/build.gradle.kts new file mode 100644 index 000000000..241131218 --- /dev/null +++ b/mifospay-shared/build.gradle.kts @@ -0,0 +1,70 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ + +plugins { + alias(libs.plugins.mifospay.kmp.library) + alias(libs.plugins.mifospay.cmp.feature) + alias(libs.plugins.android.library) + alias(libs.plugins.compose.compiler) + alias(libs.plugins.jetbrainsCompose) + alias(libs.plugins.kotlin.parcelize) +} + +kotlin { + sourceSets { + commonMain.dependencies { + implementation(projects.core.domain) + api(projects.core.data) + //put your multiplatform dependencies here + api(compose.material3) + api(compose.foundation) + api(compose.ui) + api(compose.components.uiToolingPreview) + api(compose.components.resources) + api(libs.window.size) + api(libs.koin.core) + api(libs.koin.compose) + api(libs.koin.compose.viewmodel) + + api(projects.feature.auth) + } + + desktopMain.dependencies { + // Desktop specific dependencies + implementation(compose.desktop.currentOs) + implementation(compose.desktop.common) + } + } +} + +android { + namespace = "org.mifospay.shared" + compileSdk = 34 + + defaultConfig { + minSdk = 24 + } + + packaging { + resources { + excludes += "/META-INF/{AL2.0,LGPL2.1}" + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } +} + +compose.resources { + publicResClass = true + generateResClass = always +} \ No newline at end of file diff --git a/mifospay-shared/src/commonMain/composeResources/values/strings.xml b/mifospay-shared/src/commonMain/composeResources/values/strings.xml new file mode 100644 index 000000000..a06f851ad --- /dev/null +++ b/mifospay-shared/src/commonMain/composeResources/values/strings.xml @@ -0,0 +1,21 @@ + + + + Mifos Pay + Home + Payments + Finance + Profile + Settings + āš ļø You arenā€™t connected to the internet + FAQ + + \ No newline at end of file diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt new file mode 100644 index 000000000..20ae14177 --- /dev/null +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayApp.kt @@ -0,0 +1,89 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.shared + +import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi +import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.navigation.compose.rememberNavController +import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel +import org.mifospay.core.data.util.NetworkMonitor +import org.mifospay.core.data.util.TimeZoneMonitor +import org.mifospay.core.designsystem.theme.MifosTheme +import org.mifospay.core.ui.LocalTimeZone +import org.mifospay.shared.MainUiState.Success +import org.mifospay.shared.navigation.MifosNavGraph.LOGIN_GRAPH +import org.mifospay.shared.navigation.MifosNavGraph.MAIN_GRAPH +import org.mifospay.shared.navigation.RootNavGraph +import org.mifospay.shared.ui.rememberMifosAppState + +@Composable +fun MifosPaySharedApp( + modifier: Modifier = Modifier, + networkMonitor: NetworkMonitor = koinInject(), + timeZoneMonitor: TimeZoneMonitor = koinInject(), +) { + MifosPayApp(modifier, networkMonitor, timeZoneMonitor) +} + +@OptIn(ExperimentalMaterial3WindowSizeClassApi::class) +@Composable +private fun MifosPayApp( + modifier: Modifier = Modifier, + networkMonitor: NetworkMonitor, + timeZoneMonitor: TimeZoneMonitor, + viewModel: MifosPayViewModel = koinViewModel(), +) { + val uiState by viewModel.uiState.collectAsStateWithLifecycle() + val navController = rememberNavController() + + val appState = rememberMifosAppState( + windowSizeClass = calculateWindowSizeClass(), + networkMonitor = networkMonitor, + timeZoneMonitor = timeZoneMonitor, + ) + + val currentTimeZone by appState.currentTimeZone.collectAsStateWithLifecycle() + + val navDestination = when (uiState) { + is MainUiState.Loading -> LOGIN_GRAPH + is Success -> if ((uiState as Success).userData.authenticated) { + MAIN_GRAPH + } else { + LOGIN_GRAPH + } + } + + CompositionLocalProvider( + LocalTimeZone provides currentTimeZone, + ) { + MifosTheme { + RootNavGraph( + appState = appState, + navHostController = navController, + startDestination = navDestination, + modifier = modifier, + onClickLogout = { + viewModel.logOut() + navController.navigate(LOGIN_GRAPH) { + popUpTo(navController.graph.id) { + inclusive = true + } + } + }, + ) + } + } +} diff --git a/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt similarity index 54% rename from mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt index 165bf0451..634d6eb60 100644 --- a/mifospay/src/main/java/org/mifospay/MainActivityViewModel.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/MifosPayViewModel.kt @@ -7,41 +7,38 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay +package org.mifospay.shared import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import org.mifospay.core.model.UserData import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch -import org.mifos.library.passcode.data.PasscodeManager -import org.mifospay.core.data.repository.auth.UserDataRepository +import org.mifospay.core.datastore.UserPreferencesRepository +import org.mifospay.core.model.UserInfo -class MainActivityViewModel( - private val userDataRepository: UserDataRepository, - private val passcodeManager: PasscodeManager, +class MifosPayViewModel( + private val userDataRepository: UserPreferencesRepository, ) : ViewModel() { - - val uiState: StateFlow = userDataRepository.userData.map { - MainActivityUiState.Success(it) + val uiState: StateFlow = userDataRepository.userInfo.map { + MainUiState.Success(it) }.stateIn( scope = viewModelScope, - initialValue = MainActivityUiState.Loading, + initialValue = MainUiState.Loading, started = SharingStarted.WhileSubscribed(5_000), ) fun logOut() { viewModelScope.launch { userDataRepository.logOut() - passcodeManager.clearPasscode() +// passcodeManager.clearPasscode() } } } -sealed interface MainActivityUiState { - data object Loading : MainActivityUiState - data class Success(val userData: UserData) : MainActivityUiState +sealed interface MainUiState { + data object Loading : MainUiState + data class Success(val userData: UserInfo) : MainUiState } diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt new file mode 100644 index 000000000..042388040 --- /dev/null +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/di/KoinModules.kt @@ -0,0 +1,71 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.shared.di + +import org.koin.core.context.startKoin +import org.koin.core.module.dsl.viewModelOf +import org.koin.dsl.KoinAppDeclaration +import org.koin.dsl.koinApplication +import org.koin.dsl.module +import org.mifospay.core.common.di.DispatchersModule +import org.mifospay.core.data.di.RepositoryModule +import org.mifospay.core.datastore.di.PreferencesModule +import org.mifospay.core.domain.di.DomainModule +import org.mifospay.core.network.di.LocalModule +import org.mifospay.core.network.di.NetworkModule +import org.mifospay.feature.auth.di.AuthModule +import org.mifospay.shared.MifosPayViewModel + +object KoinModules { + private val commonModules = module { + includes(DispatchersModule) + } + private val dataModules = module { + includes(RepositoryModule) + } + private val domainModules = module { + includes(DomainModule) + } + private val coreDataStoreModules = module { + includes(PreferencesModule) + } + private val networkModules = module { + includes(LocalModule, NetworkModule) + } + private val sharedModule = module { + viewModelOf(::MifosPayViewModel) + } + private val featureModules = module { + includes( + AuthModule, + ) + } + + val allModules = listOf( + commonModules, + dataModules, + domainModules, + coreDataStoreModules, + networkModules, + featureModules, + sharedModule, + ) +} + +fun koinConfiguration() = koinApplication { + modules(KoinModules.allModules) +} + +fun initKoin(config: KoinAppDeclaration? = null) { + startKoin { + config?.invoke(this) + modules(KoinModules.allModules) + } +} diff --git a/mifospay/src/main/java/org/mifospay/navigation/LoginNavGraph.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/LoginNavGraph.kt similarity index 55% rename from mifospay/src/main/java/org/mifospay/navigation/LoginNavGraph.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/LoginNavGraph.kt index 4daf2ca6b..fdf8ac1de 100644 --- a/mifospay/src/main/java/org/mifospay/navigation/LoginNavGraph.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/LoginNavGraph.kt @@ -7,18 +7,19 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.navigation +package org.mifospay.shared.navigation import androidx.navigation.NavController import androidx.navigation.NavGraphBuilder import androidx.navigation.navigation -import org.mifos.library.passcode.navigateToPasscodeScreen -import org.mifospay.core.common.Constants import org.mifospay.feature.auth.navigation.LOGIN_ROUTE import org.mifospay.feature.auth.navigation.loginScreen import org.mifospay.feature.auth.navigation.mobileVerificationScreen +import org.mifospay.feature.auth.navigation.navigateToLogin import org.mifospay.feature.auth.navigation.navigateToSignup import org.mifospay.feature.auth.navigation.signupScreen +import org.mifospay.feature.auth.socialSignup.navigateToSignupMethod +import org.mifospay.feature.auth.socialSignup.signupMethodScreen internal fun NavGraphBuilder.loginNavGraph(navController: NavController) { navigation( @@ -26,26 +27,28 @@ internal fun NavGraphBuilder.loginNavGraph(navController: NavController) { startDestination = LOGIN_ROUTE, ) { loginScreen( - onNavigateToPasscodeScreen = navController::navigateToPasscodeScreen, - onNavigateToSignupScreen = navController::navigateToSignup, + onNavigateBack = navController::popBackStack, + // TODO:: we should navigate to passcode graph + onNavigateToPasscodeScreen = navController::navigateToMainGraph, + onNavigateToSignupScreen = navController::navigateToSignupMethod, + ) + + signupMethodScreen( + onNavigateBack = navController::popBackStack, + onNavigateToSignUp = { + navController.navigateToSignup(savingsProductId = it) + }, ) signupScreen( - onLoginSuccess = navController::navigateToPasscodeScreen, - onRegisterSuccess = navController::navigateToPasscodeScreen, + onNavigateBack = navController::popBackStack, + onNavigateToLogin = navController::navigateToLogin, ) mobileVerificationScreen( - onOtpVerificationSuccess = { fullNumber, extraData -> - navController.navigateToSignup( - savingProductId = extraData[Constants.MIFOS_SAVINGS_PRODUCT_ID] as Int, - mobileNumber = fullNumber, - country = "Canada", - email = extraData[Constants.GOOGLE_EMAIL] as? String ?: "", - firstName = extraData[Constants.GOOGLE_GIVEN_NAME] as? String ?: "", - lastName = extraData[Constants.GOOGLE_FAMILY_NAME] as? String ?: "", - businessName = extraData[Constants.GOOGLE_DISPLAY_NAME] as? String ?: "", - ) + onNavigateBack = navController::popBackStack, + onOtpVerificationSuccess = { fullNumber -> + navController.navigateToSignup(mobileNumber = fullNumber) }, ) } diff --git a/mifospay/src/main/java/org/mifospay/navigation/MifosNavGraph.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavGraph.kt similarity index 93% rename from mifospay/src/main/java/org/mifospay/navigation/MifosNavGraph.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavGraph.kt index ffb539627..e3b852f6f 100644 --- a/mifospay/src/main/java/org/mifospay/navigation/MifosNavGraph.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavGraph.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.navigation +package org.mifospay.shared.navigation internal object MifosNavGraph { const val ROOT_GRAPH = "root_graph" diff --git a/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavHost.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavHost.kt new file mode 100644 index 000000000..c11c5236f --- /dev/null +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/MifosNavHost.kt @@ -0,0 +1,85 @@ +/* + * Copyright 2024 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md + */ +package org.mifospay.shared.navigation + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.navigation.NavController +import androidx.navigation.NavGraph.Companion.findStartDestination +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import androidx.navigation.navOptions +import org.mifospay.shared.ui.MifosAppState + +@Composable +internal fun MifosNavHost( + appState: MifosAppState, + onClickLogout: () -> Unit, + modifier: Modifier = Modifier, +) { + val navController = rememberNavController() + + NavHost( + route = MifosNavGraph.MAIN_GRAPH, + // HOME_ROUTE, + startDestination = "home_route", + navController = navController, + modifier = modifier, + ) { + composable(route = "home_route") { + HomeScreen( + modifier = Modifier, + onClickLogout = onClickLogout, + ) + } + } +} + +// TODO:: This could be removed, just added for testing +@Composable +private fun HomeScreen( + modifier: Modifier = Modifier, + onClickLogout: () -> Unit, +) { + Box( + modifier = modifier + .fillMaxSize(), + contentAlignment = Alignment.Center, + ) { + Text(text = "Home Screen") + } +} + +internal fun NavController.navigateToHomeScreen() { + this.navigate("home_route") +} + +internal fun NavController.navigateToMainGraph() { + val options = navOptions { + // Pop up to the start destination of the graph to + // avoid building up a large stack of destinations + // on the back stack as users select items + popUpTo(graph.findStartDestination().id) { + saveState = false + } + // Avoid multiple copies of the same destination when + // reselecting the same item + launchSingleTop = true + // Restore state when reselecting a previously selected item + restoreState = false + } + + navigate(MifosNavGraph.MAIN_GRAPH, options) +} diff --git a/mifospay/src/main/java/org/mifospay/navigation/RootNavGraph.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/RootNavGraph.kt similarity index 87% rename from mifospay/src/main/java/org/mifospay/navigation/RootNavGraph.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/RootNavGraph.kt index 1a0735b28..be68108c2 100644 --- a/mifospay/src/main/java/org/mifospay/navigation/RootNavGraph.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/navigation/RootNavGraph.kt @@ -7,15 +7,15 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.navigation +package org.mifospay.shared.navigation import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable -import org.mifospay.ui.MifosApp -import org.mifospay.ui.MifosAppState +import org.mifospay.shared.ui.MifosApp +import org.mifospay.shared.ui.MifosAppState @Composable internal fun RootNavGraph( @@ -33,7 +33,7 @@ internal fun RootNavGraph( ) { loginNavGraph(navHostController) - passcodeNavGraph(navHostController) +// passcodeNavGraph(navHostController) composable(MifosNavGraph.MAIN_GRAPH) { MifosApp( diff --git a/mifospay/src/main/java/org/mifospay/ui/MifosApp.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosApp.kt similarity index 72% rename from mifospay/src/main/java/org/mifospay/ui/MifosApp.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosApp.kt index 49dcccfc9..628385980 100644 --- a/mifospay/src/main/java/org/mifospay/ui/MifosApp.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosApp.kt @@ -7,9 +7,8 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.ui +package org.mifospay.shared.ui -import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -18,17 +17,17 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.safeDrawingPadding import androidx.compose.foundation.layout.windowInsetsPadding -import androidx.compose.foundation.layout.wrapContentSize +import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.DropdownMenu import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarDuration.Indefinite @@ -43,55 +42,45 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier import androidx.compose.ui.composed import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.geometry.Offset import androidx.compose.ui.graphics.Color import androidx.compose.ui.platform.testTag -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.semantics.semantics -import androidx.compose.ui.semantics.testTagsAsResourceId import androidx.compose.ui.unit.dp import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.navigation.NavDestination import androidx.navigation.NavDestination.Companion.hierarchy -import org.mifospay.R +import mobile_wallet.mifospay_shared.generated.resources.Res +import mobile_wallet.mifospay_shared.generated.resources.faq +import mobile_wallet.mifospay_shared.generated.resources.not_connected +import mobile_wallet.mifospay_shared.generated.resources.settings +import org.jetbrains.compose.resources.stringResource import org.mifospay.core.designsystem.component.MifosBackground import org.mifospay.core.designsystem.component.MifosGradientBackground import org.mifospay.core.designsystem.component.MifosNavigationBar import org.mifospay.core.designsystem.component.MifosNavigationBarItem import org.mifospay.core.designsystem.component.MifosNavigationRail import org.mifospay.core.designsystem.component.MifosNavigationRailItem -import org.mifospay.core.designsystem.component.MifosTopAppBar import org.mifospay.core.designsystem.icon.MifosIcons import org.mifospay.core.designsystem.theme.GradientColors import org.mifospay.core.designsystem.theme.LocalGradientColors -import org.mifospay.feature.faq.navigation.navigateToFAQ -import org.mifospay.feature.settings.navigation.navigateToSettings -import org.mifospay.navigation.MifosNavHost -import org.mifospay.navigation.TopLevelDestination +import org.mifospay.shared.navigation.MifosNavHost +import org.mifospay.shared.utils.TopLevelDestination -@OptIn( - ExperimentalMaterial3Api::class, - ExperimentalComposeUiApi::class, -) @Composable -fun MifosApp( +internal fun MifosApp( appState: MifosAppState, onClickLogout: () -> Unit, modifier: Modifier = Modifier, ) { val shouldShowGradientBackground = appState.currentTopLevelDestination == TopLevelDestination.HOME - var showHomeMenuOption by rememberSaveable { mutableStateOf(false) } MifosBackground(modifier) { MifosGradientBackground( - gradientColors = - if (shouldShowGradientBackground) { + gradientColors = if (shouldShowGradientBackground) { LocalGradientColors.current } else { GradientColors() @@ -102,7 +91,7 @@ fun MifosApp( val isOffline by appState.isOffline.collectAsStateWithLifecycle() // If user is not connected to the internet show a snack bar to inform them. - val notConnectedMessage = stringResource(R.string.not_connected) + val notConnectedMessage = stringResource(Res.string.not_connected) LaunchedEffect(isOffline) { if (isOffline) { snackbarHostState.showSnackbar( @@ -112,54 +101,8 @@ fun MifosApp( } } - if (showHomeMenuOption) { - AnimatedVisibility(true) { - Box( - modifier = - Modifier - .fillMaxWidth() - .wrapContentSize(Alignment.TopEnd) - .padding(end = 24.dp) - .background(color = MaterialTheme.colorScheme.surface), - ) { - DropdownMenu( - modifier = Modifier.background(color = MaterialTheme.colorScheme.surface), - expanded = showHomeMenuOption, - onDismissRequest = { showHomeMenuOption = false }, - ) { - DropdownMenuItem( - text = { - Text( - stringResource(id = R.string.faq), - color = MaterialTheme.colorScheme.onSurface, - ) - }, - onClick = { - showHomeMenuOption = false - appState.navController.navigateToFAQ() - }, - ) - DropdownMenuItem( - text = { - Text( - stringResource(id = R.string.feature_profile_settings), - color = MaterialTheme.colorScheme.onSurface, - ) - }, - onClick = { - showHomeMenuOption = false - appState.navController.navigateToSettings() - }, - ) - } - } - } - } - Scaffold( - modifier = Modifier.semantics { - testTagsAsResourceId = true - }, + modifier = Modifier, containerColor = Color.Transparent, contentColor = MaterialTheme.colorScheme.onBackground, snackbarHost = { SnackbarHost(snackbarHostState) }, @@ -203,18 +146,11 @@ fun MifosApp( // Show the top app bar on top level destinations. val destination = appState.currentTopLevelDestination if (destination != null) { - MifosTopAppBar( - titleRes = destination.titleTextId, - actionIcon = MifosIcons.MoreVert, - actionIconContentDescription = - stringResource( - id = R.string.feature_profile_settings, - ), - colors = - TopAppBarDefaults.centerAlignedTopAppBarColors( - containerColor = Color.Transparent, - ), - onActionClick = { showHomeMenuOption = true }, + MifosAppBar( + title = stringResource(destination.titleText), + onClickLogout = onClickLogout, + onNavigateToFaq = {}, + onNavigateToSettings = {}, ) } @@ -229,6 +165,101 @@ fun MifosApp( } } +@Composable +private fun HomeMenu( + showHomeMenuOption: Boolean, + onDismissRequest: () -> Unit, + onClickLogout: () -> Unit, + onNavigateToFaq: () -> Unit, + onNavigateToSettings: () -> Unit, + modifier: Modifier = Modifier, +) { + DropdownMenu( + modifier = modifier.background(color = MaterialTheme.colorScheme.surface), + expanded = showHomeMenuOption, + onDismissRequest = onDismissRequest, + ) { + DropdownMenuItem( + text = { + Text( + text = stringResource(Res.string.faq), + color = MaterialTheme.colorScheme.onSurface, + ) + }, + onClick = { + onDismissRequest() + onNavigateToFaq() + }, + ) + + DropdownMenuItem( + text = { + Text( + text = stringResource(Res.string.settings), + color = MaterialTheme.colorScheme.onSurface, + ) + }, + onClick = { + onDismissRequest() + onNavigateToSettings() + }, + ) + + // TODO:: this could be removed, just added for testing + DropdownMenuItem( + text = { + Text( + text = "Logout", + color = MaterialTheme.colorScheme.onSurface, + ) + }, + onClick = { + onDismissRequest() + onClickLogout() + }, + ) + } +} + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +private fun MifosAppBar( + title: String, + onClickLogout: () -> Unit, + onNavigateToFaq: () -> Unit, + onNavigateToSettings: () -> Unit, + modifier: Modifier = Modifier, +) { + var showHomeMenuOption by rememberSaveable { mutableStateOf(false) } + + CenterAlignedTopAppBar( + title = { Text(text = title) }, + actions = { + Box { + IconButton(onClick = { showHomeMenuOption = true }) { + Icon( + imageVector = MifosIcons.MoreVert, + contentDescription = "View More", + tint = MaterialTheme.colorScheme.onSurface, + ) + } + + HomeMenu( + showHomeMenuOption = showHomeMenuOption, + onDismissRequest = { showHomeMenuOption = false }, + onClickLogout = onClickLogout, + onNavigateToFaq = onNavigateToFaq, + onNavigateToSettings = onNavigateToSettings, + ) + } + }, + colors = TopAppBarDefaults.centerAlignedTopAppBarColors( + containerColor = Color.Transparent, + ), + modifier = modifier.testTag("mifosTopAppBar"), + ) +} + @Composable private fun MifosNavRail( destinations: List, @@ -257,7 +288,7 @@ private fun MifosNavRail( contentDescription = null, ) }, - label = { Text(stringResource(destination.iconTextId)) }, + label = { Text(stringResource(destination.iconText)) }, ) } } @@ -293,7 +324,7 @@ private fun MifosBottomBar( contentDescription = null, ) }, - label = { Text(stringResource(destination.iconTextId)) }, + label = { Text(stringResource(destination.iconText)) }, ) } } diff --git a/mifospay/src/main/java/org/mifospay/ui/MifosAppState.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosAppState.kt similarity index 57% rename from mifospay/src/main/java/org/mifospay/ui/MifosAppState.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosAppState.kt index e155ef1bd..a599ab6e1 100644 --- a/mifospay/src/main/java/org/mifospay/ui/MifosAppState.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/ui/MifosAppState.kt @@ -7,7 +7,7 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.ui +package org.mifospay.shared.ui import androidx.compose.material3.windowsizeclass.WindowSizeClass import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass @@ -15,16 +15,13 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.navigation.NavController +import androidx.compose.ui.util.trace import androidx.navigation.NavDestination import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavHostController import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.rememberNavController import androidx.navigation.navOptions -import androidx.tracing.trace -import com.mifos.library.material3.navigation.BottomSheetNavigator -import com.mifos.library.material3.navigation.rememberBottomSheetNavigator import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.map @@ -32,30 +29,18 @@ import kotlinx.coroutines.flow.stateIn import kotlinx.datetime.TimeZone import org.mifospay.core.data.util.NetworkMonitor import org.mifospay.core.data.util.TimeZoneMonitor -import org.mifospay.core.ui.TrackDisposableJank -import org.mifospay.feature.finance.navigation.FINANCE_ROUTE -import org.mifospay.feature.finance.navigation.navigateToFinance -import org.mifospay.feature.home.navigation.HOME_ROUTE -import org.mifospay.feature.home.navigation.navigateToHome -import org.mifospay.feature.payments.PAYMENTS_ROUTE -import org.mifospay.feature.payments.navigateToPayments -import org.mifospay.feature.profile.navigation.PROFILE_ROUTE -import org.mifospay.feature.profile.navigation.navigateToProfile -import org.mifospay.navigation.TopLevelDestination +import org.mifospay.shared.utils.TopLevelDestination @Composable -fun rememberMifosAppState( +internal fun rememberMifosAppState( windowSizeClass: WindowSizeClass, networkMonitor: NetworkMonitor, timeZoneMonitor: TimeZoneMonitor, coroutineScope: CoroutineScope = rememberCoroutineScope(), - bottomSheetNavigator: BottomSheetNavigator = rememberBottomSheetNavigator(), - navController: NavHostController = rememberNavController(bottomSheetNavigator), + navController: NavHostController = rememberNavController(), ): MifosAppState { - NavigationTrackingSideEffect(navController) return remember( navController, - bottomSheetNavigator, coroutineScope, windowSizeClass, networkMonitor, @@ -63,7 +48,6 @@ fun rememberMifosAppState( ) { MifosAppState( navController = navController, - bottomSheetNavigator = bottomSheetNavigator, coroutineScope = coroutineScope, windowSizeClass = windowSizeClass, networkMonitor = networkMonitor, @@ -73,9 +57,8 @@ fun rememberMifosAppState( } @Stable -class MifosAppState( +internal class MifosAppState( val navController: NavHostController, - val bottomSheetNavigator: BottomSheetNavigator, coroutineScope: CoroutineScope, val windowSizeClass: WindowSizeClass, networkMonitor: NetworkMonitor, @@ -87,11 +70,11 @@ class MifosAppState( val currentTopLevelDestination: TopLevelDestination? @Composable get() = when (currentDestination?.route) { - HOME_ROUTE -> TopLevelDestination.HOME - PAYMENTS_ROUTE -> TopLevelDestination.PAYMENTS - FINANCE_ROUTE -> TopLevelDestination.FINANCE - PROFILE_ROUTE -> TopLevelDestination.PROFILE - else -> null +// HOME_ROUTE -> TopLevelDestination.HOME +// PAYMENTS_ROUTE -> TopLevelDestination.PAYMENTS +// FINANCE_ROUTE -> TopLevelDestination.FINANCE +// PROFILE_ROUTE -> TopLevelDestination.PROFILE + else -> TopLevelDestination.HOME } val shouldShowBottomBar: Boolean @@ -108,10 +91,6 @@ class MifosAppState( initialValue = false, ) - /** - * Map of top level destinations to be used in the TopBar, BottomBar and NavRail. The key is the - * route. - */ val topLevelDestinations: List = TopLevelDestination.entries val currentTimeZone = timeZoneMonitor.currentTimeZone @@ -121,13 +100,6 @@ class MifosAppState( TimeZone.currentSystemDefault(), ) - /** - * UI logic for navigating to a top level destination in the app. Top level destinations have - * only one copy of the destination of the back stack, and save and restore state whenever you - * navigate to and from it. - * - * @param topLevelDestination: The destination the app needs to navigate to. - */ fun navigateToTopLevelDestination(topLevelDestination: TopLevelDestination) { trace("Navigation: ${topLevelDestination.name}") { val topLevelNavOptions = navOptions { @@ -145,29 +117,12 @@ class MifosAppState( } when (topLevelDestination) { - TopLevelDestination.HOME -> navController.navigateToHome(topLevelNavOptions) - TopLevelDestination.PAYMENTS -> navController.navigateToPayments(topLevelNavOptions) - TopLevelDestination.FINANCE -> navController.navigateToFinance(topLevelNavOptions) - TopLevelDestination.PROFILE -> navController.navigateToProfile(topLevelNavOptions) +// TopLevelDestination.HOME -> navController.navigateToHome(topLevelNavOptions) +// TopLevelDestination.PAYMENTS -> navController.navigateToPayments(topLevelNavOptions) +// TopLevelDestination.FINANCE -> navController.navigateToFinance(topLevelNavOptions) +// TopLevelDestination.PROFILE -> navController.navigateToProfile(topLevelNavOptions) + else -> Unit } } } } - -/** - * Stores information about navigation events to be used with JankStats - */ -@Composable -private fun NavigationTrackingSideEffect(navController: NavHostController) { - TrackDisposableJank(navController) { metricsHolder -> - val listener = NavController.OnDestinationChangedListener { _, destination, _ -> - metricsHolder.state?.putState("Navigation", destination.route.toString()) - } - - navController.addOnDestinationChangedListener(listener) - - onDispose { - navController.removeOnDestinationChangedListener(listener) - } - } -} diff --git a/mifospay/src/main/java/org/mifospay/navigation/TopLevelDestination.kt b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/utils/TopLevelDestination.kt similarity index 57% rename from mifospay/src/main/java/org/mifospay/navigation/TopLevelDestination.kt rename to mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/utils/TopLevelDestination.kt index 84f0d3462..907fb0092 100644 --- a/mifospay/src/main/java/org/mifospay/navigation/TopLevelDestination.kt +++ b/mifospay-shared/src/commonMain/kotlin/org/mifospay/shared/utils/TopLevelDestination.kt @@ -7,10 +7,16 @@ * * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md */ -package org.mifospay.navigation +package org.mifospay.shared.utils import androidx.compose.ui.graphics.vector.ImageVector -import org.mifospay.R +import mobile_wallet.mifospay_shared.generated.resources.Res +import mobile_wallet.mifospay_shared.generated.resources.app_name +import mobile_wallet.mifospay_shared.generated.resources.finance +import mobile_wallet.mifospay_shared.generated.resources.home +import mobile_wallet.mifospay_shared.generated.resources.payments +import mobile_wallet.mifospay_shared.generated.resources.profile +import org.jetbrains.compose.resources.StringResource import org.mifospay.core.designsystem.icon.MifosIcons /** @@ -18,34 +24,34 @@ import org.mifospay.core.designsystem.icon.MifosIcons * can contain one or more screens (based on the window size). Navigation from one screen to the * next within a single destination will be handled directly in composables. */ -enum class TopLevelDestination( +internal enum class TopLevelDestination( val selectedIcon: ImageVector, val unselectedIcon: ImageVector, - val iconTextId: Int, - val titleTextId: Int, + val iconText: StringResource, + val titleText: StringResource, ) { HOME( selectedIcon = MifosIcons.Home, unselectedIcon = MifosIcons.HomeBoarder, - iconTextId = R.string.home, - titleTextId = R.string.app_name, + iconText = Res.string.home, + titleText = Res.string.app_name, ), PAYMENTS( selectedIcon = MifosIcons.Payment, unselectedIcon = MifosIcons.Payment, - iconTextId = R.string.payments, - titleTextId = R.string.payments, + iconText = Res.string.payments, + titleText = Res.string.payments, ), FINANCE( selectedIcon = MifosIcons.Finance, unselectedIcon = MifosIcons.FinanceBoarder, - iconTextId = R.string.finance, - titleTextId = R.string.finance, + iconText = Res.string.finance, + titleText = Res.string.finance, ), PROFILE( selectedIcon = MifosIcons.Profile, unselectedIcon = MifosIcons.ProfileBoarder, - iconTextId = R.string.profile, - titleTextId = R.string.profile, + iconText = Res.string.profile, + titleText = Res.string.profile, ), } diff --git a/mifospay-web/.gitignore b/mifospay-web/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/mifospay-web/.gitignore @@ -0,0 +1 @@ +/build diff --git a/mifospay-web/README.md b/mifospay-web/README.md new file mode 100644 index 000000000..1dd276e64 --- /dev/null +++ b/mifospay-web/README.md @@ -0,0 +1,3 @@ +To run in web mode, choose the `mifospay-web-js` or `mifospay-web-wasm` profile and click run. + +_When running as WasmJs it will take some time to compile the webpack, so be patient._ \ No newline at end of file diff --git a/mifospay-web/build.gradle.kts b/mifospay-web/build.gradle.kts new file mode 100644 index 000000000..3be809017 --- /dev/null +++ b/mifospay-web/build.gradle.kts @@ -0,0 +1,62 @@ +import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl +import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig + +plugins { + alias(libs.plugins.kotlinMultiplatform) + alias(libs.plugins.jetbrainsCompose) + alias(libs.plugins.compose.compiler) +} + +kotlin { + js(IR) { + moduleName = "mifospay-web" + browser { + commonWebpackConfig { + outputFileName = "mifospay-web.js" + } + } + binaries.executable() + } + + @OptIn(ExperimentalWasmDsl::class) + wasmJs { + moduleName = "mifoswasmapp" + val rootProject = project.rootDir.path + browser { + commonWebpackConfig { + outputFileName = "mifoswasmapp.js" + devServer = (devServer ?: KotlinWebpackConfig.DevServer(port = 8081)).apply { + static = (static ?: mutableListOf()).apply { + // Serve sources to debug inside browser + add("$rootProject/mifospay-web/") + } + } + } + } + binaries.executable() + } + + applyDefaultHierarchyTemplate() + + sourceSets { + val jsWasmMain by creating { + dependsOn(commonMain.get()) + dependencies { + implementation(projects.mifospayShared) + implementation(compose.runtime) + implementation(compose.ui) + implementation(compose.foundation) + implementation(compose.material3) + implementation(compose.components.resources) + } + } + + jsMain.get().dependsOn(jsWasmMain) + wasmJsMain.get().dependsOn(jsWasmMain) + } +} + +compose.resources { + publicResClass = true + generateResClass = always +} \ No newline at end of file diff --git a/mifospay-web/src/jsMain/kotlin/Application.kt b/mifospay-web/src/jsMain/kotlin/Application.kt new file mode 100644 index 000000000..a3d5d4954 --- /dev/null +++ b/mifospay-web/src/jsMain/kotlin/Application.kt @@ -0,0 +1,15 @@ + +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.window.ComposeViewport +import kotlinx.browser.document +import org.mifospay.shared.MifosPaySharedApp +import org.mifospay.shared.di.initKoin + +@OptIn(ExperimentalComposeUiApi::class) +fun main() { + initKoin() + + ComposeViewport(document.body!!) { + MifosPaySharedApp() + } +} \ No newline at end of file diff --git a/mifospay-web/src/jsMain/resources/index.html b/mifospay-web/src/jsMain/resources/index.html new file mode 100644 index 000000000..5df6be6fb --- /dev/null +++ b/mifospay-web/src/jsMain/resources/index.html @@ -0,0 +1,15 @@ + + + + + Mifos Wallet + + + + +
+ + +
+ + \ No newline at end of file diff --git a/mifospay-web/src/jsMain/resources/styles.css b/mifospay-web/src/jsMain/resources/styles.css new file mode 100644 index 000000000..3e82a3d56 --- /dev/null +++ b/mifospay-web/src/jsMain/resources/styles.css @@ -0,0 +1,14 @@ +html, body { + height: 100%; + margin: 0px; + padding: 0px; +} + +canvas { + width: 100vw; + height: 100vh; + display: block; + position: fixed; + top: 0; + left: 0; +} \ No newline at end of file diff --git a/mifospay-web/src/wasmJsMain/kotlin/Main.kt b/mifospay-web/src/wasmJsMain/kotlin/Main.kt new file mode 100644 index 000000000..8c3a22232 --- /dev/null +++ b/mifospay-web/src/wasmJsMain/kotlin/Main.kt @@ -0,0 +1,16 @@ +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.window.CanvasBasedWindow +import org.mifospay.shared.MifosPaySharedApp +import org.mifospay.shared.di.initKoin + +@OptIn(ExperimentalComposeUiApi::class) +fun main() { + initKoin() + + CanvasBasedWindow( + title = "MifosWallet", + canvasElementId = "root", + ) { + MifosPaySharedApp() + } +} \ No newline at end of file diff --git a/mifospay-web/src/wasmJsMain/resources/index.html b/mifospay-web/src/wasmJsMain/resources/index.html new file mode 100644 index 000000000..dc3ff4f8c --- /dev/null +++ b/mifospay-web/src/wasmJsMain/resources/index.html @@ -0,0 +1,27 @@ + + + + + + Mifos Wallet + + + + + + + + \ No newline at end of file diff --git a/mifospay-web/src/wasmJsMain/resources/load.mjs b/mifospay-web/src/wasmJsMain/resources/load.mjs new file mode 100644 index 000000000..eada049a3 --- /dev/null +++ b/mifospay-web/src/wasmJsMain/resources/load.mjs @@ -0,0 +1,5 @@ +import { instantiate } from './mifoswasmapp.uninstantiated.mjs'; + +await wasmSetup; + +instantiate({ skia: Module['asm'] }); \ No newline at end of file diff --git a/mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt b/mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt deleted file mode 100644 index 9abd02dd6..000000000 --- a/mifospay/dependencies/prodReleaseRuntimeClasspath.tree.txt +++ /dev/null @@ -1,2352 +0,0 @@ -+--- androidx.databinding:databinding-common:8.5.2 -+--- androidx.databinding:databinding-runtime:8.5.2 -| +--- androidx.collection:collection:1.0.0 -> 1.4.4 -| | \--- androidx.collection:collection-jvm:1.4.4 -| | +--- androidx.annotation:annotation:1.8.1 -| | | \--- androidx.annotation:annotation-jvm:1.8.1 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 -| | | +--- org.jetbrains:annotations:13.0 -> 23.0.0 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.0.0 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0 -> 2.0.0 (c) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-common:2.0.20 (c) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.collection:collection-ktx:1.4.4 (c) -| | \--- androidx.collection:collection-ktx:1.3.0 -> 1.4.4 (c) -| +--- androidx.databinding:databinding-common:8.5.2 -| +--- androidx.databinding:viewbinding:8.5.2 -| | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| \--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 -| \--- androidx.lifecycle:lifecycle-runtime-android:2.8.6 -| +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| +--- androidx.arch.core:core-common:2.2.0 -| | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| +--- androidx.arch.core:core-runtime:2.2.0 -| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | \--- androidx.arch.core:core-common:2.2.0 (*) -| +--- androidx.lifecycle:lifecycle-common:2.8.6 -| | \--- androidx.lifecycle:lifecycle-common-jvm:2.8.6 -| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 -| | | +--- org.jetbrains:annotations:23.0.0 -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.9.0 (c) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.9.0 (c) -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.9.0 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 -| | +--- androidx.annotation:annotation:1.8.1 (*) -| | +--- androidx.concurrent:concurrent-futures:1.1.0 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| | +--- androidx.startup:startup-runtime:1.1.1 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | \--- androidx.tracing:tracing:1.0.0 -> 1.3.0-alpha02 -| | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | \--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (c) -| | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -+--- androidx.databinding:databinding-adapters:8.5.2 -| +--- androidx.databinding:databinding-runtime:8.5.2 (*) -| \--- androidx.databinding:databinding-common:8.5.2 -+--- androidx.databinding:databinding-ktx:8.5.2 -| +--- androidx.databinding:databinding-runtime:8.5.2 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.20 -> 2.0.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1 -> 1.9.0 (*) -| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.6 -| | \--- androidx.lifecycle:lifecycle-runtime-ktx-android:2.8.6 -| | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata:2.6.1 -> 2.8.6 -| | +--- androidx.arch.core:core-common:2.2.0 (*) -| | +--- androidx.arch.core:core-runtime:2.2.0 (*) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 -| | | +--- androidx.arch.core:core-common:2.2.0 (*) -| | | +--- androidx.arch.core:core-runtime:2.2.0 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-process:2.6.1 -> 2.8.6 -| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) -| | +--- androidx.startup:startup-runtime:1.1.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-service:2.6.1 -> 2.8.6 -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| \--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 -| \--- androidx.lifecycle:lifecycle-viewmodel-android:2.8.6 -| +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -+--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -+--- androidx.compose:compose-bom:2024.09.02 -| +--- androidx.compose.material3:material3-window-size-class:1.3.0 (c) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) -| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) -| +--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) -| +--- androidx.compose.runtime:runtime:1.7.2 (c) -| +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| +--- androidx.compose.foundation:foundation:1.7.2 (c) -| +--- androidx.compose.foundation:foundation-layout:1.7.2 (c) -| +--- androidx.compose.material:material-icons-extended:1.7.2 (c) -| +--- androidx.compose.material3:material3:1.3.0 (c) -| +--- androidx.compose.ui:ui-util:1.7.2 (c) -| +--- androidx.compose.runtime:runtime-saveable:1.7.2 (c) -| +--- androidx.compose.ui:ui:1.7.2 (c) -| +--- androidx.compose.material3.adaptive:adaptive-android:1.0.0 (c) -| +--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 (c) -| +--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 (c) -| +--- androidx.compose.animation:animation:1.7.2 (c) -| +--- androidx.compose.material3:material3-window-size-class-android:1.3.0 (c) -| +--- androidx.compose.runtime:runtime-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-tooling-preview-android:1.7.2 (c) -| +--- androidx.compose.material:material:1.7.2 (c) -| +--- androidx.compose.animation:animation-graphics:1.7.2 (c) -| +--- androidx.compose.foundation:foundation-layout-android:1.7.2 (c) -| +--- androidx.compose.runtime:runtime-saveable-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-android:1.7.2 (c) -| +--- androidx.compose.foundation:foundation-android:1.7.2 (c) -| +--- androidx.compose.material:material-icons-extended-android:1.7.2 (c) -| +--- androidx.compose.material3:material3-android:1.3.0 (c) -| +--- androidx.compose.ui:ui-util-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| +--- androidx.compose.animation:animation-core:1.7.2 (c) -| +--- androidx.compose.animation:animation-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| +--- androidx.compose.material:material-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-geometry-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-unit-android:1.7.2 (c) -| +--- androidx.compose.animation:animation-graphics-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| +--- androidx.compose.ui:ui-text:1.7.2 (c) -| +--- androidx.compose.material:material-icons-core:1.7.2 (c) -| +--- androidx.compose.material:material-ripple:1.7.2 (c) -| +--- androidx.compose.animation:animation-core-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-graphics-android:1.7.2 (c) -| +--- androidx.compose.ui:ui-text-android:1.7.2 (c) -| +--- androidx.compose.material:material-icons-core-android:1.7.2 (c) -| \--- androidx.compose.material:material-ripple-android:1.7.2 (c) -+--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 -| \--- androidx.compose.ui:ui-tooling-preview-android:1.7.2 -| +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| +--- androidx.compose.runtime:runtime:1.7.2 -| | \--- androidx.compose.runtime:runtime-android:1.7.2 -| | +--- androidx.annotation:annotation-experimental:1.4.1 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) -| | +--- androidx.collection:collection:1.4.4 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | \--- androidx.compose.runtime:runtime-saveable:1.7.2 (c) -| +--- androidx.compose.ui:ui:1.7.2 (c) -| +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| +--- androidx.compose.ui:ui-util:1.7.2 (c) -| +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| \--- androidx.compose.ui:ui-text:1.7.2 (c) -+--- com.google.firebase:firebase-bom:33.3.0 -| +--- com.google.firebase:firebase-perf-ktx:21.0.1 (c) -| +--- com.google.firebase:firebase-crashlytics-ktx:19.1.0 (c) -| +--- com.google.firebase:firebase-analytics-ktx:22.1.0 (c) -| +--- com.google.firebase:firebase-messaging-ktx:24.0.1 (c) -| +--- com.google.firebase:firebase-perf:21.0.1 (c) -| +--- com.google.firebase:firebase-common:21.0.0 (c) -| +--- com.google.firebase:firebase-common-ktx:21.0.0 (c) -| +--- com.google.firebase:firebase-crashlytics:19.1.0 (c) -| +--- com.google.firebase:firebase-analytics:22.1.0 (c) -| +--- com.google.firebase:firebase-messaging:24.0.1 (c) -| +--- com.google.firebase:firebase-encoders:17.0.0 (c) -| +--- com.google.firebase:firebase-config:22.0.0 (c) -| \--- com.google.firebase:firebase-installations:18.0.0 (c) -+--- com.google.firebase:firebase-analytics-ktx -> 22.1.0 -| +--- com.google.firebase:firebase-analytics:22.1.0 -| | +--- com.google.android.gms:play-services-measurement:22.1.0 -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | +--- androidx.legacy:legacy-support-core-utils:1.0.0 -| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | +--- androidx.core:core:1.0.0 -> 1.13.1 -| | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) -| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | | | | +--- androidx.interpolator:interpolator:1.0.0 -| | | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.2 -> 2.8.6 (*) -| | | | | +--- androidx.versionedparcelable:versionedparcelable:1.1.1 -| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | \--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | \--- androidx.core:core-ktx:1.13.1 (c) -| | | | +--- androidx.documentfile:documentfile:1.0.0 -| | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 -| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.0.0 -> 2.8.6 (*) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.0.0 -> 2.8.6 (*) -| | | | | \--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | +--- androidx.localbroadcastmanager:localbroadcastmanager:1.0.0 -| | | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | \--- androidx.print:print:1.0.0 -| | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 -| | | | \--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core:1.2.0 -> 1.13.1 (*) -| | | | \--- androidx.fragment:fragment:1.1.0 -> 1.8.2 -| | | | +--- androidx.activity:activity:1.8.1 -> 1.9.2 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | | +--- androidx.core:core:1.13.0 -> 1.13.1 (*) -| | | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.6 -| | | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.core:core:1.13.1 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | \--- androidx.core:core:1.13.1 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) -| | | | | | +--- androidx.savedstate:savedstate:1.2.1 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.1 -> 2.8.6 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) -| | | | | | | \--- androidx.savedstate:savedstate-ktx:1.2.1 (c) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | | | | \--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | | +--- androidx.tracing:tracing:1.0.0 -> 1.3.0-alpha02 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- androidx.activity:activity-compose:1.9.2 (c) -| | | | | \--- androidx.activity:activity-ktx:1.9.2 (c) -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) -| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.6.1 -> 2.8.6 (*) -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.1 -> 2.8.6 (*) -| | | | +--- androidx.loader:loader:1.0.0 -> 1.1.0 (*) -| | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | +--- androidx.viewpager:viewpager:1.0.0 -| | | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | | | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) -| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | \--- androidx.fragment:fragment-ktx:1.8.2 (c) -| | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 -| | | | \--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-impl:22.1.0 -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core:1.9.0 -> 1.13.1 (*) -| | | | +--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 -| | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core-ktx:1.8.0 -> 1.13.1 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | | \--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 (c) -| | | | +--- androidx.privacysandbox.ads:ads-adservices-java:1.0.0-beta05 -| | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | | +--- androidx.concurrent:concurrent-futures:1.1.0 (*) -| | | | | +--- androidx.core:core-ktx:1.8.0 -> 1.13.1 (*) -| | | | | +--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 (*) -| | | | | +--- com.google.guava:guava:31.1-android -| | | | | | +--- com.google.guava:failureaccess:1.0.1 -| | | | | | +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava -| | | | | | +--- com.google.code.findbugs:jsr305:3.0.2 -| | | | | | +--- org.checkerframework:checker-qual:3.12.0 -| | | | | | +--- com.google.errorprone:error_prone_annotations:2.11.0 -> 2.26.0 -| | | | | | \--- com.google.j2objc:j2objc-annotations:1.3 -| | | | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.21 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | | \--- androidx.privacysandbox.ads:ads-adservices:1.0.0-beta05 (c) -| | | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 (*) -| | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) -| | | | +--- com.google.android.gms:play-services-stats:17.0.2 -| | | | | +--- androidx.legacy:legacy-support-core-utils:1.0.0 (*) -| | | | | \--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) -| | | | \--- com.google.guava:guava:31.1-android (*) -| | | \--- com.google.android.gms:play-services-stats:17.0.2 (*) -| | +--- com.google.android.gms:play-services-measurement-api:22.1.0 -| | | +--- com.google.android.gms:play-services-ads-identifier:18.0.0 (*) -| | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) -| | | +--- com.google.android.gms:play-services-measurement-sdk-api:22.1.0 -| | | | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | | \--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) -| | | +--- com.google.android.gms:play-services-tasks:18.2.0 -| | | | \--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | | +--- com.google.firebase:firebase-common:21.0.0 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.6.4 -> 1.9.0 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) -| | | | | +--- com.google.android.gms:play-services-tasks:16.0.1 -> 18.2.0 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- com.google.firebase:firebase-components:18.0.0 -| | | | | +--- com.google.firebase:firebase-annotations:16.2.0 -| | | | | | \--- javax.inject:javax.inject:1 -| | | | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) -| | | | | \--- com.google.errorprone:error_prone_annotations:2.26.0 -| | | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) -| | | | +--- androidx.concurrent:concurrent-futures:1.1.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) -| | | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 -| | | | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | | | \--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | | +--- com.google.firebase:firebase-installations:17.0.1 -> 18.0.0 -| | | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | | | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | | | +--- com.google.firebase:firebase-installations-interop:17.1.1 -> 17.2.0 -| | | | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | | | | \--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- com.google.firebase:firebase-installations-interop:17.0.0 -> 17.2.0 (*) -| | | +--- com.google.firebase:firebase-measurement-connector:19.0.0 -> 20.0.1 -| | | | +--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) -| | | | \--- com.google.firebase:firebase-annotations:16.0.0 -> 16.2.0 (*) -| | | +--- com.google.guava:guava:31.1-android (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) -| | \--- com.google.android.gms:play-services-measurement-sdk:22.1.0 -| | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | +--- com.google.android.gms:play-services-basement:18.4.0 (*) -| | +--- com.google.android.gms:play-services-measurement-base:22.1.0 (*) -| | \--- com.google.android.gms:play-services-measurement-impl:22.1.0 (*) -| +--- com.google.firebase:firebase-common:21.0.0 (*) -| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- com.google.firebase:firebase-components:18.0.0 (*) -| \--- org.jetbrains.kotlin:kotlin-stdlib:1.7.10 -> 2.0.20 (*) -+--- com.google.firebase:firebase-perf-ktx -> 21.0.1 -| +--- com.google.firebase:firebase-perf:21.0.1 -| | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) -| | +--- com.google.firebase:protolite-well-known-types:18.0.0 -| | | \--- com.google.protobuf:protobuf-javalite:3.14.0 -> 4.26.0 -| | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | +--- com.google.firebase:firebase-config:21.5.0 -> 22.0.0 -| | | +--- com.google.firebase:firebase-config-interop:16.0.1 -| | | | +--- com.google.firebase:firebase-encoders-json:18.0.1 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.10 -> 2.0.0 (*) -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | \--- com.google.firebase:firebase-encoders:17.0.0 -| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | \--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) -| | | +--- com.google.firebase:firebase-abt:21.1.1 -| | | | +--- com.google.firebase:firebase-measurement-connector:18.0.0 -> 20.0.1 (*) -| | | | \--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) -| | | +--- com.google.firebase:firebase-measurement-connector:18.0.0 -> 20.0.1 (*) -| | | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) -| | | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) -| | +--- com.google.firebase:firebase-sessions:2.0.0 -> 2.0.4 -| | | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | | +--- com.google.firebase:firebase-installations-interop:17.2.0 (*) -| | | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | | +--- com.google.firebase:firebase-encoders-json:18.0.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- com.google.firebase:firebase-installations:18.0.0 (*) -| | | +--- com.google.firebase:firebase-datatransport:19.0.0 -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- com.google.android.datatransport:transport-api:3.1.0 -> 3.2.0 -| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- com.google.android.datatransport:transport-backend-cct:3.2.0 -> 3.3.0 -| | | | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) -| | | | | +--- com.google.android.datatransport:transport-runtime:3.3.0 -| | | | | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) -| | | | | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| | | | | | +--- javax.inject:javax.inject:1 -| | | | | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | | | | | \--- com.google.firebase:firebase-encoders-proto:16.0.0 -| | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | \--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | | | | +--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | | | | +--- com.google.firebase:firebase-encoders-json:18.0.0 -> 18.0.1 (*) -| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- com.google.android.datatransport:transport-runtime:3.2.0 -> 3.3.0 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- androidx.datastore:datastore-preferences:1.0.0 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) -| | | | +--- androidx.datastore:datastore:1.0.0 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.9.0 (*) -| | | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | | \--- androidx.datastore:datastore-core:1.0.0 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0 -> 1.9.0 (*) -| | | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | \--- androidx.datastore:datastore-preferences-core:1.0.0 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.5.10 -> 2.0.20 (*) -| | | | \--- androidx.datastore:datastore-core:1.0.0 (*) -| | | +--- com.google.android.datatransport:transport-api:3.2.0 (*) -| | | \--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) -| | +--- com.google.firebase:firebase-datatransport:18.1.8 -> 19.0.0 (*) -| | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | +--- androidx.lifecycle:lifecycle-process:2.3.1 -> 2.8.6 (*) -| | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | +--- com.google.protobuf:protobuf-javalite:3.21.11 -> 4.26.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- androidx.appcompat:appcompat:1.2.0 -> 1.7.0 -| | | +--- androidx.activity:activity:1.7.0 -> 1.9.2 (*) -| | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| | | +--- androidx.appcompat:appcompat-resources:1.7.0 -| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core:1.6.0 -> 1.13.1 (*) -| | | | +--- androidx.vectordrawable:vectordrawable:1.1.0 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- androidx.vectordrawable:vectordrawable-animated:1.1.0 -| | | | | +--- androidx.vectordrawable:vectordrawable:1.1.0 (*) -| | | | | +--- androidx.interpolator:interpolator:1.0.0 (*) -| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | \--- androidx.appcompat:appcompat:1.7.0 (c) -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | +--- androidx.core:core:1.13.0 -> 1.13.1 (*) -| | | +--- androidx.core:core-ktx:1.13.0 -> 1.13.1 (*) -| | | +--- androidx.cursoradapter:cursoradapter:1.0.0 -| | | | \--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | +--- androidx.drawerlayout:drawerlayout:1.0.0 -| | | | +--- androidx.annotation:annotation:1.0.0 -> 1.8.1 (*) -| | | | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | | | \--- androidx.customview:customview:1.0.0 -> 1.1.0 (*) -| | | +--- androidx.emoji2:emoji2:1.3.0 -| | | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) -| | | | +--- androidx.lifecycle:lifecycle-process:2.4.1 -> 2.8.6 (*) -| | | | +--- androidx.startup:startup-runtime:1.0.0 -> 1.1.1 (*) -| | | | \--- androidx.emoji2:emoji2-views-helper:1.3.0 (c) -| | | +--- androidx.emoji2:emoji2-views-helper:1.2.0 -> 1.3.0 -| | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- androidx.core:core:1.3.0 -> 1.13.1 (*) -| | | | +--- androidx.emoji2:emoji2:1.3.0 (*) -| | | | \--- androidx.emoji2:emoji2:1.3.0 (c) -| | | +--- androidx.fragment:fragment:1.5.4 -> 1.8.2 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | +--- androidx.resourceinspection:resourceinspection-annotation:1.0.1 -| | | | \--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.appcompat:appcompat-resources:1.7.0 (c) -| | +--- com.google.android.datatransport:transport-api:3.0.0 -> 3.2.0 (*) -| | +--- com.google.dagger:dagger:2.27 -| | | \--- javax.inject:javax.inject:1 -| | \--- com.squareup.okhttp3:okhttp:3.12.1 -> 4.12.0 -| | +--- com.squareup.okio:okio:3.6.0 -> 3.9.0 -| | | \--- com.squareup.okio:okio-jvm:3.9.0 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.21 -> 2.0.0 (*) -| +--- com.google.firebase:firebase-common:21.0.0 (*) -| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| \--- com.google.firebase:firebase-components:18.0.0 (*) -+--- com.google.firebase:firebase-crashlytics-ktx -> 19.1.0 -| +--- com.google.firebase:firebase-crashlytics:19.1.0 -| | +--- com.google.firebase:firebase-sessions:2.0.4 (*) -| | +--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | +--- com.google.firebase:firebase-annotations:16.2.0 (*) -| | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | +--- com.google.firebase:firebase-config-interop:16.0.1 (*) -| | +--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | +--- com.google.firebase:firebase-encoders-json:18.0.1 (*) -| | +--- com.google.firebase:firebase-installations:18.0.0 (*) -| | +--- com.google.firebase:firebase-installations-interop:17.2.0 (*) -| | +--- com.google.firebase:firebase-measurement-connector:20.0.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | +--- com.google.android.datatransport:transport-api:3.2.0 (*) -| | +--- com.google.android.datatransport:transport-backend-cct:3.3.0 (*) -| | +--- com.google.android.datatransport:transport-runtime:3.3.0 (*) -| | \--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) -| +--- com.google.firebase:firebase-common:21.0.0 (*) -| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| \--- com.google.firebase:firebase-components:18.0.0 (*) -+--- com.google.firebase:firebase-messaging-ktx -> 24.0.1 -| +--- com.google.firebase:firebase-messaging:24.0.1 -| | +--- com.google.firebase:firebase-common:21.0.0 (*) -| | +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| | +--- com.google.firebase:firebase-components:18.0.0 (*) -| | +--- com.google.firebase:firebase-datatransport:18.2.0 -> 19.0.0 (*) -| | +--- com.google.firebase:firebase-encoders:17.0.0 (*) -| | +--- com.google.firebase:firebase-encoders-json:18.0.0 -> 18.0.1 (*) -| | +--- com.google.firebase:firebase-encoders-proto:16.0.0 (*) -| | +--- com.google.firebase:firebase-iid-interop:17.1.0 -| | | +--- com.google.android.gms:play-services-basement:17.0.0 -> 18.4.0 (*) -| | | \--- com.google.android.gms:play-services-tasks:17.0.0 -> 18.2.0 (*) -| | +--- com.google.firebase:firebase-installations:17.2.0 -> 18.0.0 (*) -| | +--- com.google.firebase:firebase-installations-interop:17.1.0 -> 17.2.0 (*) -| | +--- com.google.firebase:firebase-measurement-connector:19.0.0 -> 20.0.1 (*) -| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | +--- com.google.android.datatransport:transport-api:3.1.0 -> 3.2.0 (*) -| | +--- com.google.android.datatransport:transport-backend-cct:3.1.8 -> 3.3.0 (*) -| | +--- com.google.android.datatransport:transport-runtime:3.1.8 -> 3.3.0 (*) -| | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 -| | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | +--- androidx.core:core:1.2.0 -> 1.13.1 (*) -| | | +--- androidx.fragment:fragment:1.0.0 -> 1.8.2 (*) -| | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) -| | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | +--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) -| | +--- com.google.android.gms:play-services-cloud-messaging:17.2.0 -| | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) -| | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | +--- com.google.android.gms:play-services-stats:17.0.2 (*) -| | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | +--- com.google.errorprone:error_prone_annotations:2.9.0 -> 2.26.0 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- com.google.firebase:firebase-common:21.0.0 (*) -| +--- com.google.firebase:firebase-common-ktx:21.0.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| \--- com.google.firebase:firebase-components:18.0.0 (*) -+--- project :core:data -| +--- androidx.core:core-ktx:1.13.1 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 -| | +--- androidx.tracing:tracing:1.3.0-alpha02 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | \--- androidx.tracing:tracing:1.3.0-alpha02 (c) -| +--- io.insert-koin:koin-android:4.0.0-RC2 -| | +--- io.insert-koin:koin-core:4.0.0-RC2 -| | | \--- io.insert-koin:koin-core-jvm:4.0.0-RC2 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | +--- co.touchlab:stately-concurrency:2.0.7 -| | | | \--- co.touchlab:stately-concurrency-jvm:2.0.7 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | | | \--- co.touchlab:stately-strict:2.0.7 -| | | | \--- co.touchlab:stately-strict-jvm:2.0.7 -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | | \--- co.touchlab:stately-concurrent-collections:2.0.7 -| | | \--- co.touchlab:stately-concurrent-collections-jvm:2.0.7 -| | | +--- co.touchlab:stately-concurrency:2.0.7 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 -| | | \--- io.insert-koin:koin-core-viewmodel-jvm:4.0.0-RC2 -| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel:2.8.0 -| | | | \--- androidx.lifecycle:lifecycle-viewmodel:2.8.0 -> 2.8.6 (*) -| | | +--- org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 -| | | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.0 -> 2.8.6 (*) -| | | +--- org.jetbrains.androidx.core:core-bundle:1.0.0 -| | | | \--- org.jetbrains.androidx.core:core-bundle-android:1.0.0 -| | | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | | +--- org.jetbrains.androidx.savedstate:savedstate:1.2.0 -| | | | \--- androidx.savedstate:savedstate:1.2.1 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- androidx.appcompat:appcompat:1.7.0 (*) -| | +--- androidx.activity:activity-ktx:1.9.1 -> 1.9.2 -| | | +--- androidx.activity:activity:1.9.2 (*) -| | | +--- androidx.core:core-ktx:1.13.0 -> 1.13.1 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.6 -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 -| | | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.10 -> 2.0.20 (*) -| | | | \--- androidx.savedstate:savedstate:1.2.1 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.activity:activity:1.9.2 (c) -| | | \--- androidx.activity:activity-compose:1.9.2 (c) -| | +--- androidx.fragment:fragment-ktx:1.8.2 -| | | +--- androidx.activity:activity-ktx:1.8.1 -> 1.9.2 (*) -| | | +--- androidx.collection:collection-ktx:1.1.0 -> 1.4.4 -| | | | +--- androidx.collection:collection:1.4.4 (*) -| | | | \--- androidx.collection:collection:1.4.4 (c) -| | | +--- androidx.core:core-ktx:1.2.0 -> 1.13.1 (*) -| | | +--- androidx.fragment:fragment:1.8.2 (*) -| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.fragment:fragment:1.8.2 (c) -| | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.4 -> 2.8.6 (*) -| | +--- androidx.lifecycle:lifecycle-common-java8:2.8.4 -> 2.8.6 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | \--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- project :core:common -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (*) -| | +--- io.coil-kt.coil3:coil:3.0.0-alpha10 -| | | \--- io.coil-kt.coil3:coil-android:3.0.0-alpha10 -| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 -| | | | \--- io.coil-kt.coil3:coil-core-android:3.0.0-alpha10 -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.4 -> 2.8.6 (*) -| | | | +--- androidx.annotation:annotation:1.8.1 (*) -| | | | +--- androidx.appcompat:appcompat-resources:1.7.0 (*) -| | | | +--- androidx.core:core-ktx:1.13.1 (*) -| | | | +--- androidx.exifinterface:exifinterface:1.3.7 -| | | | | \--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1 -> 1.9.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.1 -> 1.9.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | | | \--- com.squareup.okio:okio:3.9.0 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) -| | +--- io.coil-kt.coil3:coil-svg:3.0.0-alpha10 -| | | \--- io.coil-kt.coil3:coil-svg-android:3.0.0-alpha10 -| | | +--- androidx.core:core-ktx:1.13.1 (*) -| | | +--- com.caverock:androidsvg-aar:1.4 -| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | +--- io.coil-kt.coil3:coil-network-ktor3:3.0.0-alpha10 -| | | \--- io.coil-kt.coil3:coil-network-ktor3-android:3.0.0-alpha10 -| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) -| | | +--- io.coil-kt.coil3:coil-network-core:3.0.0-alpha10 -| | | | \--- io.coil-kt.coil3:coil-network-core-android:3.0.0-alpha10 -| | | | +--- androidx.core:core-ktx:1.13.1 (*) -| | | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | | +--- io.ktor:ktor-client-core:3.0.0-beta-2 -| | | | \--- io.ktor:ktor-client-core-jvm:3.0.0-beta-2 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| | | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) -| | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | +--- io.ktor:ktor-http:3.0.0-beta-2 -| | | | | \--- io.ktor:ktor-http-jvm:3.0.0-beta-2 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | +--- io.ktor:ktor-utils:3.0.0-beta-2 -| | | | | | \--- io.ktor:ktor-utils-jvm:3.0.0-beta-2 -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | | +--- io.ktor:ktor-io:3.0.0-beta-2 -| | | | | | | \--- io.ktor:ktor-io-jvm:3.0.0-beta-2 -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-io-core:0.5.1 -| | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-io-core-jvm:0.5.1 -| | | | | | | | +--- org.jetbrains.kotlinx:kotlinx-io-bytestring:0.5.1 -| | | | | | | | | \--- org.jetbrains.kotlinx:kotlinx-io-bytestring-jvm:0.5.1 -| | | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- io.ktor:ktor-events:3.0.0-beta-2 -| | | | | \--- io.ktor:ktor-events-jvm:3.0.0-beta-2 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) -| | | | | +--- io.ktor:ktor-utils:3.0.0-beta-2 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- io.ktor:ktor-websocket-serialization:3.0.0-beta-2 -| | | | | \--- io.ktor:ktor-websocket-serialization-jvm:3.0.0-beta-2 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) -| | | | | +--- io.ktor:ktor-serialization:3.0.0-beta-2 -| | | | | | \--- io.ktor:ktor-serialization-jvm:3.0.0-beta-2 -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) -| | | | | | +--- io.ktor:ktor-websockets:3.0.0-beta-2 -| | | | | | | \--- io.ktor:ktor-websockets-jvm:3.0.0-beta-2 -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) -| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- io.ktor:ktor-sse:3.0.0-beta-2 -| | | | | \--- io.ktor:ktor-sse-jvm:3.0.0-beta-2 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.8.0 -> 1.9.0 (*) -| | | | | +--- org.slf4j:slf4j-api:2.0.13 -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | | | | +--- io.ktor:ktor-http:3.0.0-beta-2 (*) -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-slf4j:1.8.0 -> 1.9.0 -| | | | +--- org.slf4j:slf4j-api:1.7.32 -> 2.0.13 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 -| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (c) -| | | +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (c) -| | | +--- io.insert-koin:koin-android:4.0.0-RC2 (c) -| | | +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (c) -| | | +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (c) -| | | \--- io.insert-koin:koin-compose:4.0.0-RC2 (c) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 -| | | \--- io.insert-koin:koin-annotations-jvm:1.4.0-RC4 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.24 -> 2.0.20 (*) -| | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| +--- project :core:datastore -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | +--- com.russhwolf:multiplatform-settings-no-arg:1.2.0 -| | | \--- com.russhwolf:multiplatform-settings-no-arg-android:1.2.0 -| | | +--- androidx.startup:startup-runtime:1.1.1 (*) -| | | +--- com.russhwolf:multiplatform-settings:1.2.0 -| | | | \--- com.russhwolf:multiplatform-settings-android:1.2.0 -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | +--- com.russhwolf:multiplatform-settings-serialization:1.2.0 -| | | \--- com.russhwolf:multiplatform-settings-serialization-android:1.2.0 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | +--- com.russhwolf:multiplatform-settings:1.2.0 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 -| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core-jvm:1.7.2 (c) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (c) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 (c) -| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (c) -| | +--- com.russhwolf:multiplatform-settings-coroutines:1.2.0 -| | | \--- com.russhwolf:multiplatform-settings-coroutines-android:1.2.0 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | +--- com.russhwolf:multiplatform-settings:1.2.0 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) -| | +--- project :core:model -| | | +--- com.squareup.retrofit2:converter-gson:2.11.0 -| | | | +--- com.squareup.retrofit2:retrofit:2.11.0 -| | | | | \--- com.squareup.okhttp3:okhttp:3.14.9 -> 4.12.0 (*) -| | | | \--- com.google.code.gson:gson:2.10.1 -| | | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 -| | | | \--- org.jetbrains.kotlinx:kotlinx-datetime-jvm:0.6.0 -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 -| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.7.2 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-bom:1.7.2 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (c) -| | | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-android-extensions-runtime:2.0.20 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- project :core:common (*) -| | \--- project :core:datastore-proto -| | +--- com.google.protobuf:protobuf-kotlin-lite:4.26.0 -| | | +--- com.google.protobuf:protobuf-javalite:4.26.0 -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.0 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.2 (*) -| +--- project :core:network -| | +--- io.ktor:ktor-client-android:2.3.4 -| | | \--- io.ktor:ktor-client-android-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-datetime:0.6.0 (*) -| | +--- project :core:common (*) -| | +--- project :core:model (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2 (*) -| | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | +--- io.ktor:ktor-client-json:2.3.4 -| | | \--- io.ktor:ktor-client-json-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | \--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | +--- io.ktor:ktor-client-logging:2.3.4 -| | | \--- io.ktor:ktor-client-logging-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | \--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | +--- io.ktor:ktor-client-serialization:2.3.4 -| | | \--- io.ktor:ktor-client-serialization-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1 -> 1.7.2 (*) -| | | \--- io.ktor:ktor-client-json:2.3.4 (*) -| | +--- io.ktor:ktor-client-content-negotiation:2.3.4 -| | | \--- io.ktor:ktor-client-content-negotiation-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | +--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -| | | \--- io.ktor:ktor-serialization:2.3.4 -> 3.0.0-beta-2 (*) -| | +--- io.ktor:ktor-serialization-kotlinx-json:2.3.4 -| | | \--- io.ktor:ktor-serialization-kotlinx-json-jvm:2.3.4 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | +--- io.ktor:ktor-http:2.3.4 -> 3.0.0-beta-2 (*) -| | | +--- io.ktor:ktor-serialization-kotlinx:2.3.4 -| | | | \--- io.ktor:ktor-serialization-kotlinx-jvm:2.3.4 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | +--- io.ktor:ktor-http:2.3.4 -> 3.0.0-beta-2 (*) -| | | | +--- io.ktor:ktor-serialization:2.3.4 -> 3.0.0-beta-2 (*) -| | | | \--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.5.1 -> 1.7.2 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1 -> 1.7.2 (*) -| | +--- de.jensklingenberg.ktorfit:ktorfit-lib:2.1.0 -| | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-android:2.1.0 -| | | +--- io.ktor:ktor-client-cio-jvm:2.3.12 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | +--- io.ktor:ktor-client-core:2.3.12 -> 3.0.0-beta-2 (*) -| | | | +--- io.ktor:ktor-http-cio:2.3.12 -| | | | | \--- io.ktor:ktor-http-cio-jvm:2.3.12 -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | | | +--- io.ktor:ktor-network:2.3.12 -| | | | | | \--- io.ktor:ktor-network-jvm:2.3.12 -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | | | \--- io.ktor:ktor-utils:2.3.12 -> 3.0.0-beta-2 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | | \--- io.ktor:ktor-http:2.3.12 -> 3.0.0-beta-2 (*) -| | | | +--- io.ktor:ktor-websockets:2.3.12 -> 3.0.0-beta-2 (*) -| | | | \--- io.ktor:ktor-network-tls:2.3.12 -| | | | \--- io.ktor:ktor-network-tls-jvm:2.3.12 -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22 -> 2.0.0 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.7.1 -> 1.9.0 (*) -| | | | +--- org.slf4j:slf4j-api:1.7.36 -> 2.0.13 -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1 -> 1.9.0 (*) -| | | | +--- io.ktor:ktor-http:2.3.12 -> 3.0.0-beta-2 (*) -| | | | +--- io.ktor:ktor-network:2.3.12 (*) -| | | | \--- io.ktor:ktor-utils:2.3.12 -> 3.0.0-beta-2 (*) -| | | +--- de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 -| | | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light-android:2.1.0 -| | | | +--- de.jensklingenberg.ktorfit:ktorfit-annotations:2.1.0 -| | | | | \--- de.jensklingenberg.ktorfit:ktorfit-annotations-android:2.1.0 -| | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | | +--- io.ktor:ktor-client-core:2.3.12 -> 3.0.0-beta-2 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | +--- de.jensklingenberg.ktorfit:ktorfit-converters-call:2.1.0 -| | | \--- de.jensklingenberg.ktorfit:ktorfit-converters-call-android:2.1.0 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 (*) -| | \--- de.jensklingenberg.ktorfit:ktorfit-converters-flow:2.1.0 -| | \--- de.jensklingenberg.ktorfit:ktorfit-converters-flow-android:2.1.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.0 -> 2.0.20 (*) -| | \--- de.jensklingenberg.ktorfit:ktorfit-lib-light:2.1.0 (*) -| +--- project :core:model (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- project :core:analytics -| | +--- com.google.firebase:firebase-bom:33.3.0 (*) -| | +--- com.google.firebase:firebase-analytics-ktx -> 22.1.0 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | \--- org.jetbrains.compose.runtime:runtime:1.6.11 -| | \--- androidx.compose.runtime:runtime:1.6.7 -> 1.7.2 (*) -| \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.0.20 (*) -+--- project :core:ui -| +--- androidx.metrics:metrics-performance:1.0.0-beta01 -| | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | +--- androidx.core:core:1.5.0 -> 1.13.1 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- androidx.browser:browser:1.8.0 -| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | +--- androidx.interpolator:interpolator:1.0.0 (*) -| | \--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| +--- com.google.accompanist:accompanist-pager:0.34.0 -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.9.0 (*) -| | +--- androidx.compose.foundation:foundation:1.6.0 -> 1.7.2 -| | | \--- androidx.compose.foundation:foundation-android:1.7.2 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | +--- androidx.compose.animation:animation:1.7.2 -| | | | \--- androidx.compose.animation:animation-android:1.7.2 -| | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | +--- androidx.compose.animation:animation-core:1.7.2 -| | | | | \--- androidx.compose.animation:animation-core-android:1.7.2 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui:1.7.2 -| | | | | | \--- androidx.compose.ui:ui-android:1.7.2 -| | | | | | +--- androidx.activity:activity-ktx:1.7.0 -> 1.9.2 (*) -| | | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | | +--- androidx.autofill:autofill:1.0.0 -| | | | | | | \--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 -| | | | | | | \--- androidx.compose.runtime:runtime-saveable-android:1.7.2 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | \--- androidx.compose.runtime:runtime:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 -| | | | | | | \--- androidx.compose.ui:ui-geometry-android:1.7.2 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 -| | | | | | | | \--- androidx.compose.ui:ui-util-android:1.7.2 -| | | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | | | \--- androidx.compose.ui:ui-unit:1.7.2 (c) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 -| | | | | | | \--- androidx.compose.ui:ui-graphics-android:1.7.2 -| | | | | | | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 -| | | | | | | | \--- androidx.compose.ui:ui-unit-android:1.7.2 -| | | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | | | | +--- androidx.collection:collection-ktx:1.2.0 -> 1.4.4 (*) -| | | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) -| | | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) -| | | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) -| | | | | | | +--- androidx.graphics:graphics-path:1.0.1 -| | | | | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) -| | | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-text:1.7.2 -| | | | | | | \--- androidx.compose.ui:ui-text-android:1.7.2 -| | | | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 (*) -| | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) -| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) -| | | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) -| | | | | | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) -| | | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | | | | | | +--- androidx.compose.ui:ui:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| | | | | | | \--- androidx.compose.ui:ui-util:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) -| | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | | +--- androidx.core:core:1.12.0 -> 1.13.1 (*) -| | | | | | +--- androidx.customview:customview-poolingcontainer:1.0.0 -| | | | | | | +--- androidx.core:core-ktx:1.5.0 -> 1.13.1 (*) -| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) -| | | | | | +--- androidx.emoji2:emoji2:1.2.0 -> 1.3.0 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.3 -> 2.8.6 -| | | | | | | \--- androidx.lifecycle:lifecycle-runtime-compose-android:2.8.6 -| | | | | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | | | | | | +--- androidx.compose.runtime:runtime:1.7.1 -> 1.7.2 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (*) -| | | | | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | | | | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | | | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | | | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-text:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-tooling-preview:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (c) -| | | | | | +--- androidx.compose.ui:ui-util:1.7.2 (c) -| | | | | | \--- androidx.compose.foundation:foundation:1.7.2 (c) -| | | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | | | | +--- androidx.compose.animation:animation:1.7.2 (c) -| | | | | \--- androidx.compose.animation:animation-graphics:1.7.2 (c) -| | | | +--- androidx.compose.foundation:foundation-layout:1.7.2 -| | | | | \--- androidx.compose.foundation:foundation-layout-android:1.7.2 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | | +--- androidx.compose.animation:animation-core:1.2.1 -> 1.7.2 (*) -| | | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui-unit:1.7.2 (*) -| | | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | | +--- androidx.core:core:1.7.0 -> 1.13.1 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | \--- androidx.compose.foundation:foundation:1.7.2 (c) -| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) -| | | | +--- androidx.compose.ui:ui-graphics:1.7.2 (*) -| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- androidx.compose.animation:animation-core:1.7.2 (c) -| | | | \--- androidx.compose.animation:animation-graphics:1.7.2 (c) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-text:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | +--- androidx.core:core:1.13.1 (*) -| | | +--- androidx.emoji2:emoji2:1.3.0 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | \--- androidx.compose.foundation:foundation-layout:1.7.2 (c) -| | +--- dev.chrisbanes.snapper:snapper:0.2.2 -> 0.3.0 -| | | +--- androidx.compose.foundation:foundation:1.2.1 -> 1.7.2 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.21 -> 2.0.0 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) -| +--- project :core:analytics (*) -| +--- project :core:designsystem -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| | +--- androidx.activity:activity-compose:1.9.2 -| | | +--- androidx.activity:activity-ktx:1.9.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.0.1 -> 1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime-saveable:1.0.1 -> 1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.0.1 -> 1.7.2 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.activity:activity:1.9.2 (c) -| | | \--- androidx.activity:activity-ktx:1.9.2 (c) -| | +--- project :core:model (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | +--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 -| | | \--- io.coil-kt.coil3:coil-compose-core-android:3.0.0-alpha10 -| | | +--- com.google.accompanist:accompanist-drawablepainter:0.34.0 -| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4 -> 1.9.0 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.22 -> 2.0.20 (*) -| | | +--- io.coil-kt.coil3:coil-core:3.0.0-alpha10 (*) -| | | +--- org.jetbrains.compose.foundation:foundation:1.6.11 -| | | | \--- androidx.compose.foundation:foundation:1.6.7 -> 1.7.2 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.10 -> 2.0.20 (*) -| | +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) -| | +--- org.jetbrains.compose.foundation:foundation:1.6.11 (*) -| | +--- org.jetbrains.compose.material:material:1.6.11 -| | | \--- androidx.compose.material:material:1.6.7 -> 1.7.2 -| | | \--- androidx.compose.material:material-android:1.7.2 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.compose.animation:animation:1.7.2 (*) -| | | +--- androidx.compose.animation:animation-core:1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation:1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) -| | | +--- androidx.compose.material:material-ripple:1.7.2 -| | | | \--- androidx.compose.material:material-ripple-android:1.7.2 -| | | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | | +--- androidx.compose.animation:animation:1.7.2 (*) -| | | | +--- androidx.compose.foundation:foundation:1.7.2 (*) -| | | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-text:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | +--- androidx.lifecycle:lifecycle-runtime:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel:2.6.1 -> 2.8.6 (*) -| | | +--- androidx.savedstate:savedstate:1.2.1 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.compose.material3:material3:1.6.11 -| | | \--- androidx.compose.material3:material3:1.2.1 -> 1.3.0 -| | | \--- androidx.compose.material3:material3-android:1.3.0 -| | | +--- androidx.activity:activity-compose:1.8.2 -> 1.9.2 (*) -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | +--- androidx.compose.animation:animation-core:1.6.0 -> 1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation:1.7.0 -> 1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.0 -> 1.7.2 (*) -| | | +--- androidx.compose.material:material-icons-core:1.6.0 -> 1.7.2 -| | | | \--- androidx.compose.material:material-icons-core-android:1.7.2 -| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) -| | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.compose.material:material-ripple:1.7.0 -> 1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.0 -> 1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) -| | | +--- androidx.compose.ui:ui-text:1.6.0 -> 1.7.2 (*) -| | | +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.2 (*) -| | | +--- androidx.lifecycle:lifecycle-common-java8:2.6.1 -> 2.8.6 (*) -| | | \--- androidx.compose.material3:material3-window-size-class:1.3.0 (c) -| | +--- org.jetbrains.compose.material:material-icons-extended:1.6.11 -| | | \--- androidx.compose.material:material-icons-extended:1.6.7 -> 1.7.2 -| | | \--- androidx.compose.material:material-icons-extended-android:1.7.2 -| | | \--- androidx.compose.material:material-icons-core:1.7.2 (*) -| | +--- org.jetbrains.compose.ui:ui:1.6.11 -| | | \--- androidx.compose.ui:ui:1.6.7 -> 1.7.2 (*) -| | +--- org.jetbrains.compose.ui:ui-util:1.6.11 -| | | \--- androidx.compose.ui:ui-util:1.6.7 -> 1.7.2 (*) -| | +--- org.jetbrains.compose.components:components-resources:1.6.11 -| | | \--- org.jetbrains.compose.components:components-resources-android:1.6.11 -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) -| | | +--- org.jetbrains.compose.foundation:foundation:1.6.11 (*) -| | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.8.0 -> 1.9.0 (*) -| | \--- org.jetbrains.compose.components:components-ui-tooling-preview:1.6.11 -| | \--- org.jetbrains.compose.components:components-ui-tooling-preview-android:1.6.11 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.23 -> 2.0.20 (*) -| +--- project :core:model (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- io.coil-kt.coil3:coil:3.0.0-alpha10 (*) -| +--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) -| +--- org.jetbrains.compose.material3:material3:1.6.11 (*) -| +--- org.jetbrains.compose.components:components-resources:1.6.11 (*) -| \--- org.jetbrains.compose.components:components-ui-tooling-preview:1.6.11 (*) -+--- project :core:designsystem (*) -+--- project :feature:receipt -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | +--- androidx.compose:compose-bom:2024.09.02 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| | +--- androidx.navigation:navigation-compose:2.8.1 -| | | +--- androidx.activity:activity-compose:1.8.0 -> 1.9.2 (*) -| | | +--- androidx.compose.animation:animation:1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime-saveable:1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2 -> 2.8.6 -| | | | \--- androidx.lifecycle:lifecycle-viewmodel-compose-android:2.8.6 -| | | | +--- androidx.annotation:annotation:1.8.0 -> 1.8.1 (*) -| | | | +--- androidx.compose.runtime:runtime:1.6.0 -> 1.7.2 (*) -| | | | +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) -| | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (*) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (*) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- androidx.lifecycle:lifecycle-common:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-common-java8:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-livedata:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-process:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-service:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.6 (c) -| | | | +--- androidx.lifecycle:lifecycle-livedata-core:2.8.6 (c) -| | | | \--- androidx.lifecycle:lifecycle-livedata-core-ktx:2.8.6 (c) -| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 -| | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 -| | | | | +--- androidx.navigation:navigation-common:2.8.1 -| | | | | | +--- androidx.annotation:annotation:1.8.1 (*) -| | | | | | +--- androidx.collection:collection-ktx:1.4.2 -> 1.4.4 (*) -| | | | | | +--- androidx.core:core-ktx:1.1.0 -> 1.13.1 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-common:2.6.2 -> 2.8.6 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.6 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.6 (*) -| | | | | | +--- androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2 -> 2.8.6 (*) -| | | | | | +--- androidx.profileinstaller:profileinstaller:1.3.1 -> 1.4.0 (*) -| | | | | | +--- androidx.savedstate:savedstate-ktx:1.2.1 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) -| | | | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-common:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-runtime:2.8.1 -| | | | | +--- androidx.activity:activity-ktx:1.7.1 -> 1.9.2 (*) -| | | | | +--- androidx.annotation:annotation-experimental:1.4.1 (*) -| | | | | +--- androidx.collection:collection:1.4.2 -> 1.4.4 (*) -| | | | | +--- androidx.lifecycle:lifecycle-runtime-ktx:2.6.2 -> 2.8.6 (*) -| | | | | +--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2 -> 2.8.6 (*) -| | | | | +--- androidx.navigation:navigation-common:2.8.1 (*) -| | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) -| | | | | +--- androidx.navigation:navigation-common:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | | \--- androidx.navigation:navigation-common:2.8.1 (c) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) -| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | \--- androidx.navigation:navigation-common:2.8.1 (c) -| | +--- androidx.compose.material3:material3 -> 1.3.0 (*) -| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| | \--- androidx.compose.ui:ui-util -> 1.7.2 (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 -| | \--- org.jetbrains.kotlinx:kotlinx-collections-immutable-jvm:0.3.8 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.21 -> 2.0.20 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 -| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-compose:4.0.0-RC2 -| | | \--- io.insert-koin:koin-compose-jvm:4.0.0-RC2 -| | | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | | +--- org.jetbrains.compose.runtime:runtime:1.6.11 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- androidx.compose.runtime:runtime:1.6.8 -> 1.7.2 (*) -| | +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4 -> 2.8.6 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 -| | +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| | +--- androidx.navigation:navigation-fragment-ktx:2.7.7 -> 2.8.1 -| | | +--- androidx.navigation:navigation-fragment:2.8.1 -| | | | +--- androidx.fragment:fragment-ktx:1.6.2 -> 1.8.2 (*) -| | | | +--- androidx.navigation:navigation-runtime:2.8.1 (*) -| | | | +--- androidx.slidingpanelayout:slidingpanelayout:1.2.0 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.customview:customview:1.1.0 (*) -| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | | | +--- androidx.window:window:1.0.0 -> 1.3.0 -| | | | | | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| | | | | | +--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | | | +--- androidx.core:core:1.8.0 -> 1.13.1 (*) -| | | | | | +--- androidx.window.extensions.core:core:1.0.0 -| | | | | | | +--- androidx.annotation:annotation:1.6.0 -> 1.8.1 (*) -| | | | | | | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.20 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | | | +--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3 -> 1.9.0 (*) -| | | | | | \--- androidx.window:window-core:1.3.0 (c) -| | | | | \--- androidx.transition:transition:1.4.1 -| | | | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | | | \--- androidx.collection:collection:1.1.0 -> 1.4.4 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | | +--- org.jetbrains.kotlinx:kotlinx-serialization-core:1.6.3 -> 1.7.2 (*) -| | | | +--- androidx.navigation:navigation-common:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-fragment-ktx:2.8.1 (c) -| | | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | | \--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 (*) -| | | +--- androidx.navigation:navigation-common-ktx:2.8.1 (c) -| | | +--- androidx.navigation:navigation-compose:2.8.1 (c) -| | | +--- androidx.navigation:navigation-fragment:2.8.1 (c) -| | | +--- androidx.navigation:navigation-runtime:2.8.1 (c) -| | | +--- androidx.navigation:navigation-runtime-ktx:2.8.1 (c) -| | | \--- androidx.navigation:navigation-common:2.8.1 (c) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- com.squareup.okhttp3:okhttp:4.12.0 (*) -+--- project :feature:profile -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- project :libs:country-code-picker -| | +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| | +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| | +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| | +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| | +--- androidx.compose:compose-bom:2024.09.02 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| | +--- androidx.compose.foundation:foundation -> 1.7.2 (*) -| | +--- androidx.compose.foundation:foundation-layout -> 1.7.2 (*) -| | +--- androidx.compose.material:material-icons-extended -> 1.7.2 (*) -| | +--- androidx.compose.material3:material3 -> 1.3.0 (*) -| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| | +--- androidx.compose.ui:ui-util -> 1.7.2 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| | \--- io.michaelrocks:libphonenumber-android:8.13.35 -| +--- com.squareup.okhttp3:okhttp:4.12.0 (*) -| \--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) -+--- project :feature:auth -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- project :libs:country-code-picker (*) -| +--- androidx.credentials:credentials:1.2.2 -> 1.3.0-beta01 -| | +--- androidx.annotation:annotation:1.5.0 -> 1.8.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | +--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | \--- androidx.credentials:credentials-play-services-auth:1.3.0-beta01 (c) -| +--- androidx.credentials:credentials-play-services-auth:1.2.2 -> 1.3.0-beta01 -| | +--- androidx.credentials:credentials:1.3.0-beta01 (*) -| | +--- com.google.android.gms:play-services-auth:21.1.1 -> 21.2.0 -| | | +--- androidx.fragment:fragment:1.5.7 -> 1.8.2 (*) -| | | +--- androidx.loader:loader:1.1.0 (*) -| | | +--- com.google.android.gms:play-services-auth-api-phone:18.0.2 -| | | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) -| | | | +--- com.google.android.gms:play-services-basement:18.0.2 -> 18.4.0 (*) -| | | | \--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | | +--- com.google.android.gms:play-services-auth-base:18.0.10 -| | | | +--- androidx.collection:collection:1.0.0 -> 1.4.4 (*) -| | | | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) -| | | | +--- com.google.android.gms:play-services-basement:18.2.0 -> 18.4.0 (*) -| | | | \--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | | +--- com.google.android.gms:play-services-base:18.3.0 (*) -| | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) -| | | +--- com.google.android.gms:play-services-fido:20.0.1 -> 21.0.0 -| | | | +--- com.google.android.gms:play-services-base:18.3.0 (*) -| | | | +--- com.google.android.gms:play-services-basement:18.3.0 -> 18.4.0 (*) -| | | | +--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | | | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0 -> 2.0.0 (*) -| | | | \--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3 -> 1.9.0 (*) -| | | \--- com.google.android.gms:play-services-tasks:18.1.0 -> 18.2.0 (*) -| | +--- com.google.android.gms:play-services-fido:21.0.0 (*) -| | +--- com.google.android.libraries.identity.googleid:googleid:1.1.0 -> 1.1.1 -| | | +--- androidx.credentials:credentials:1.3.0-beta01 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.0 -> 2.0.20 (*) -| | | \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0 -> 2.0.0 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | \--- androidx.credentials:credentials:1.3.0-beta01 (c) -| +--- com.google.android.libraries.identity.googleid:googleid:1.1.1 (*) -| \--- com.google.android.gms:play-services-auth:21.2.0 (*) -+--- project :feature:make-transfer -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:faq -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:editpassword -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:notification -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- project :libs:pullrefresh -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- androidx.compose.animation:animation -> 1.7.2 (*) -| +--- androidx.compose.material3:material3 -> 1.3.0 (*) -| +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| \--- androidx.compose.ui:ui-util -> 1.7.2 (*) -+--- project :feature:request-money -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- com.google.zxing:core:3.5.3 -| \--- io.coil-kt.coil3:coil-compose-core:3.0.0-alpha10 (*) -+--- project :feature:upi-setup -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:settings -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:savedcards -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:qr -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- com.google.zxing:core:3.5.3 -| +--- androidx.camera:camera-view:1.3.4 -| | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | +--- androidx.annotation:annotation-experimental:1.3.1 -> 1.4.1 (*) -| | +--- androidx.appcompat:appcompat:1.1.0 -> 1.7.0 (*) -| | +--- androidx.camera:camera-core:1.3.4 -| | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.1.0 -> 1.4.1 (*) -| | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | +--- androidx.exifinterface:exifinterface:1.3.2 -> 1.3.7 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.1.0 -> 2.8.6 (*) -| | | +--- androidx.lifecycle:lifecycle-livedata:2.1.0 -> 2.8.6 (*) -| | | +--- com.google.auto.value:auto-value-annotations:1.6.3 -| | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.camera:camera-lifecycle:1.3.4 (c) -| | | +--- androidx.camera:camera-video:1.3.4 (c) -| | | \--- androidx.camera:camera-view:1.3.4 (c) -| | +--- androidx.camera:camera-lifecycle:1.3.4 -| | | +--- androidx.camera:camera-core:1.3.4 (*) -| | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | +--- androidx.lifecycle:lifecycle-common:2.1.0 -> 2.8.6 (*) -| | | +--- com.google.auto.value:auto-value-annotations:1.6.3 -| | | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| | | +--- androidx.camera:camera-core:1.3.4 (c) -| | | +--- androidx.camera:camera-video:1.3.4 (c) -| | | \--- androidx.camera:camera-view:1.3.4 (c) -| | +--- androidx.camera:camera-video:1.3.4 -| | | +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| | | +--- androidx.camera:camera-core:1.3.4 (*) -| | | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | | +--- androidx.core:core:1.1.0 -> 1.13.1 (*) -| | | +--- com.google.auto.value:auto-value-annotations:1.6.3 -| | | +--- androidx.camera:camera-core:1.3.4 (c) -| | | +--- androidx.camera:camera-lifecycle:1.3.4 (c) -| | | \--- androidx.camera:camera-view:1.3.4 (c) -| | +--- androidx.concurrent:concurrent-futures:1.0.0 -> 1.1.0 (*) -| | +--- androidx.core:core:1.3.2 -> 1.13.1 (*) -| | +--- androidx.lifecycle:lifecycle-common:2.0.0 -> 2.8.6 (*) -| | +--- com.google.auto.value:auto-value-annotations:1.6.3 -| | +--- com.google.guava:listenablefuture:1.0 -> 9999.0-empty-to-avoid-conflict-with-guava -| | +--- androidx.camera:camera-core:1.3.4 (c) -| | +--- androidx.camera:camera-lifecycle:1.3.4 (c) -| | \--- androidx.camera:camera-video:1.3.4 (c) -| +--- androidx.camera:camera-lifecycle:1.3.4 (*) -| \--- com.google.guava:guava:27.0.1-android -> 31.1-android (*) -+--- project :feature:invoices -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:merchants -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- project :libs:pullrefresh (*) -+--- project :feature:history -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- project :libs:pullrefresh (*) -+--- project :feature:kyc -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- project :libs:country-code-picker (*) -| +--- project :libs:pullrefresh (*) -| +--- com.maxkeppeler.sheets-compose-dialogs:core:1.3.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.10 -> 2.0.0 (*) -| | +--- androidx.core:core-ktx:1.9.0 -> 1.13.1 (*) -| | +--- androidx.compose:compose-bom:2024.02.00 -> 2024.09.02 (*) -| | +--- androidx.compose.ui:ui -> 1.7.2 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| | +--- androidx.compose.animation:animation -> 1.7.2 (*) -| | +--- androidx.compose.animation:animation-graphics -> 1.7.2 -| | | \--- androidx.compose.animation:animation-graphics-android:1.7.2 -| | | +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| | | +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| | | +--- androidx.collection:collection:1.4.0 -> 1.4.4 (*) -| | | +--- androidx.compose.animation:animation:1.7.2 (*) -| | | +--- androidx.compose.foundation:foundation-layout:1.7.2 (*) -| | | +--- androidx.compose.runtime:runtime:1.7.2 (*) -| | | +--- androidx.compose.ui:ui:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-geometry:1.7.2 (*) -| | | +--- androidx.compose.ui:ui-util:1.7.2 (*) -| | | +--- androidx.core:core-ktx:1.5.0 -> 1.13.1 (*) -| | | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | | +--- androidx.compose.animation:animation:1.7.2 (c) -| | | \--- androidx.compose.animation:animation-core:1.7.2 (c) -| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| | \--- androidx.compose.material3:material3 -> 1.3.0 (*) -| +--- com.maxkeppeler.sheets-compose-dialogs:calendar:1.3.0 -| | +--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.10 -> 2.0.0 (*) -| | +--- androidx.core:core-ktx:1.9.0 -> 1.13.1 (*) -| | +--- androidx.compose:compose-bom:2024.02.00 -> 2024.09.02 (*) -| | +--- androidx.compose.ui:ui -> 1.7.2 (*) -| | +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| | +--- androidx.compose.animation:animation -> 1.7.2 (*) -| | +--- androidx.compose.animation:animation-graphics -> 1.7.2 (*) -| | +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| | +--- androidx.compose.material3:material3 -> 1.3.0 (*) -| | +--- dev.chrisbanes.snapper:snapper:0.3.0 (*) -| | \--- com.maxkeppeler.sheets-compose-dialogs:core:1.3.0 (*) -| \--- com.squareup.okhttp3:okhttp:4.12.0 (*) -+--- project :feature:home -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :feature:accounts -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- project :libs:pullrefresh (*) -| \--- com.google.android.gms:play-services-auth:21.2.0 (*) -+--- project :feature:finance -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- com.google.accompanist:accompanist-pager:0.34.0 (*) -+--- project :feature:payments -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- com.google.accompanist:accompanist-pager:0.34.0 (*) -+--- project :feature:send-money -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- project :libs:country-code-picker (*) -| \--- com.google.android.gms:play-services-code-scanner:16.1.0 -| +--- androidx.activity:activity:1.3.1 -> 1.9.2 (*) -| +--- com.google.android.datatransport:transport-api:2.2.1 -> 3.2.0 (*) -| +--- com.google.android.datatransport:transport-backend-cct:2.3.3 -> 3.3.0 (*) -| +--- com.google.android.datatransport:transport-runtime:2.2.6 -> 3.3.0 (*) -| +--- com.google.android.gms:play-services-base:18.1.0 -> 18.3.0 (*) -| +--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) -| +--- com.google.android.gms:play-services-tasks:18.0.2 -> 18.2.0 (*) -| +--- com.google.firebase:firebase-components:16.1.0 -> 18.0.0 (*) -| +--- com.google.firebase:firebase-encoders:16.1.0 -> 17.0.0 (*) -| +--- com.google.firebase:firebase-encoders-json:17.1.0 -> 18.0.1 (*) -| +--- com.google.mlkit:barcode-scanning-common:17.0.0 -| | +--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) -| | \--- com.google.mlkit:vision-common:17.0.0 -| | +--- androidx.exifinterface:exifinterface:1.0.0 -> 1.3.7 (*) -| | +--- com.google.android.datatransport:transport-api:2.2.1 -> 3.2.0 (*) -| | +--- com.google.android.datatransport:transport-backend-cct:2.3.3 -> 3.3.0 (*) -| | +--- com.google.android.datatransport:transport-runtime:2.2.6 -> 3.3.0 (*) -| | +--- com.google.android.gms:play-services-base:18.0.1 -> 18.3.0 (*) -| | +--- com.google.android.gms:play-services-basement:18.0.0 -> 18.4.0 (*) -| | +--- com.google.android.gms:play-services-tasks:18.0.1 -> 18.2.0 (*) -| | +--- com.google.android.odml:image:1.0.0-beta1 -| | +--- com.google.firebase:firebase-components:16.1.0 -> 18.0.0 (*) -| | +--- com.google.firebase:firebase-encoders:16.1.0 -> 17.0.0 (*) -| | +--- com.google.firebase:firebase-encoders-json:17.1.0 -> 18.0.1 (*) -| | \--- com.google.mlkit:common:18.0.0 -> 18.9.0 -| | +--- androidx.core:core:1.0.0 -> 1.13.1 (*) -| | +--- com.google.android.datatransport:transport-api:2.2.1 -> 3.2.0 (*) -| | +--- com.google.android.datatransport:transport-backend-cct:2.3.3 -> 3.3.0 (*) -| | +--- com.google.android.datatransport:transport-runtime:2.2.6 -> 3.3.0 (*) -| | +--- com.google.android.gms:play-services-base:18.1.0 -> 18.3.0 (*) -| | +--- com.google.android.gms:play-services-basement:18.1.0 -> 18.4.0 (*) -| | +--- com.google.android.gms:play-services-tasks:18.0.2 -> 18.2.0 (*) -| | +--- com.google.firebase:firebase-components:16.1.0 -> 18.0.0 (*) -| | +--- com.google.firebase:firebase-encoders:16.1.0 -> 17.0.0 (*) -| | \--- com.google.firebase:firebase-encoders-json:17.1.0 -> 18.0.1 (*) -| \--- com.google.mlkit:common:18.9.0 (*) -+--- project :feature:standing-instruction -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| \--- com.google.android.gms:play-services-code-scanner:16.1.0 (*) -+--- project :feature:search -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- project :core:ui (*) -| +--- project :core:designsystem (*) -| +--- project :core:data (*) -| +--- project :libs:material3-navigation (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| \--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -+--- project :libs:mifos-passcode -| +--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- io.insert-koin:koin-bom:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-core:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-annotations:1.4.0-RC4 (*) -| +--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -| +--- androidx.compose:compose-bom:2024.09.02 (*) -| +--- androidx.compose.ui:ui-tooling-preview -> 1.7.2 (*) -| +--- androidx.core:core-ktx:1.13.1 (*) -| +--- androidx.compose.foundation:foundation -> 1.7.2 (*) -| +--- androidx.compose.foundation:foundation-layout -> 1.7.2 (*) -| +--- androidx.compose.material:material-icons-extended -> 1.7.2 (*) -| +--- androidx.compose.material3:material3 -> 1.3.0 (*) -| +--- androidx.compose.runtime:runtime -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-util -> 1.7.2 (*) -| +--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -| +--- androidx.navigation:navigation-compose:2.8.1 (*) -| +--- io.insert-koin:koin-android:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-navigation:4.0.0-RC2 (*) -| +--- io.insert-koin:koin-androidx-compose:4.0.0-RC2 (*) -| \--- io.insert-koin:koin-core-viewmodel:4.0.0-RC2 (*) -+--- project :libs:material3-navigation (*) -+--- androidx.core:core-ktx:1.13.1 (*) -+--- androidx.appcompat:appcompat:1.7.0 (*) -+--- androidx.activity:activity-compose:1.9.2 (*) -+--- androidx.activity:activity-ktx:1.9.2 (*) -+--- androidx.core:core-splashscreen:1.0.1 -| +--- androidx.annotation:annotation:1.2.0 -> 1.8.1 (*) -| \--- org.jetbrains.kotlin:kotlin-stdlib:1.6.21 -> 2.0.20 (*) -+--- androidx.compose.material3.adaptive:adaptive:1.0.0 -| \--- androidx.compose.material3.adaptive:adaptive-android:1.0.0 -| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.2 (*) -| +--- androidx.window:window:1.3.0 (*) -| +--- androidx.window:window-core:1.3.0 -| | \--- androidx.window:window-core-android:1.3.0 -| | +--- androidx.annotation:annotation:1.7.0 -> 1.8.1 (*) -| | +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| | \--- androidx.window:window:1.3.0 (c) -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 -| | \--- org.jetbrains.kotlin:kotlin-stdlib:2.0.20 (*) -| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) -| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) -+--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 -| \--- androidx.compose.material3.adaptive:adaptive-layout-android:1.0.0 -| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.animation:animation:1.7.0 -> 1.7.2 (*) -| +--- androidx.compose.animation:animation-core:1.7.0 -> 1.7.2 (*) -| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) -| +--- androidx.compose.foundation:foundation-layout:1.6.5 -> 1.7.2 (*) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (*) -| +--- androidx.compose.ui:ui:1.7.0 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-geometry:1.6.5 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.2 (*) -| +--- androidx.window:window-core:1.3.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) -| \--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 (c) -+--- androidx.compose.material3.adaptive:adaptive-navigation:1.0.0 -| \--- androidx.compose.material3.adaptive:adaptive-navigation-android:1.0.0 -| +--- androidx.activity:activity-compose:1.8.2 -> 1.9.2 (*) -| +--- androidx.annotation:annotation:1.1.0 -> 1.8.1 (*) -| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.foundation:foundation:1.6.5 -> 1.7.2 (*) -| +--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (*) -| +--- androidx.compose.ui:ui-util:1.6.5 -> 1.7.2 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22 -> 2.0.20 (*) -| +--- androidx.compose.material3.adaptive:adaptive:1.0.0 (c) -| \--- androidx.compose.material3.adaptive:adaptive-layout:1.0.0 (c) -+--- androidx.compose.material3:material3-window-size-class -> 1.3.0 -| \--- androidx.compose.material3:material3-window-size-class-android:1.3.0 -| +--- androidx.annotation:annotation-experimental:1.4.0 -> 1.4.1 (*) -| +--- androidx.compose.runtime:runtime:1.7.0 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui:1.6.0 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-unit:1.6.0 -> 1.7.2 (*) -| +--- androidx.compose.ui:ui-util:1.6.0 -> 1.7.2 (*) -| +--- androidx.window:window:1.0.0 -> 1.3.0 (*) -| +--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| \--- androidx.compose.material3:material3:1.3.0 (c) -+--- androidx.compose.runtime:runtime-tracing:1.0.0-beta01 -| +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| +--- androidx.compose.runtime:runtime:1.3.3 -> 1.7.2 (*) -| +--- androidx.startup:startup-runtime:1.1.1 (*) -| +--- androidx.tracing:tracing-perfetto:1.0.0 -| | +--- androidx.annotation:annotation:1.3.0 -> 1.8.1 (*) -| | +--- androidx.startup:startup-runtime:1.1.1 (*) -| | \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -| \--- org.jetbrains.kotlin:kotlin-stdlib:1.8.22 -> 2.0.20 (*) -+--- org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0 (*) -+--- org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0 (*) -+--- androidx.lifecycle:lifecycle-runtime-compose:2.8.6 (*) -+--- androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6 (*) -+--- androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.6 (*) -+--- androidx.lifecycle:lifecycle-extensions:2.2.0 -| +--- androidx.lifecycle:lifecycle-runtime:2.2.0 -> 2.8.6 (*) -| +--- androidx.arch.core:core-common:2.1.0 -> 2.2.0 (*) -| +--- androidx.arch.core:core-runtime:2.1.0 -> 2.2.0 (*) -| +--- androidx.fragment:fragment:1.2.0 -> 1.8.2 (*) -| +--- androidx.lifecycle:lifecycle-common:2.2.0 -> 2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-livedata:2.2.0 -> 2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-process:2.2.0 -> 2.8.6 (*) -| +--- androidx.lifecycle:lifecycle-service:2.2.0 -> 2.8.6 (*) -| \--- androidx.lifecycle:lifecycle-viewmodel:2.2.0 -> 2.8.6 (*) -+--- androidx.navigation:navigation-compose:2.8.1 (*) -+--- androidx.profileinstaller:profileinstaller:1.4.0 (*) -+--- androidx.tracing:tracing-ktx:1.3.0-alpha02 (*) -+--- io.insert-koin:koin-android:4.0.0-RC2 (*) -+--- io.ktor:ktor-client-core:2.3.4 -> 3.0.0-beta-2 (*) -\--- androidx.compose.runtime:runtime -> 1.7.2 (*) diff --git a/mifospay/src/main/java/org/mifospay/MainActivity.kt b/mifospay/src/main/java/org/mifospay/MainActivity.kt deleted file mode 100644 index e17923bd8..000000000 --- a/mifospay/src/main/java/org/mifospay/MainActivity.kt +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay - -import android.os.Bundle -import android.view.Window -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.activity.enableEdgeToEdge -import androidx.compose.material3.windowsizeclass.ExperimentalMaterial3WindowSizeClassApi -import androidx.compose.material3.windowsizeclass.calculateWindowSizeClass -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.setValue -import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import androidx.metrics.performance.JankStats -import androidx.navigation.compose.rememberNavController -import kotlinx.coroutines.flow.collect -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch -import org.koin.android.ext.android.inject -import org.koin.androidx.viewmodel.ext.android.viewModel -import org.koin.core.parameter.parametersOf -import org.mifospay.MainActivityUiState.Loading -import org.mifospay.MainActivityUiState.Success -import org.mifospay.core.analytics.AnalyticsHelper -import org.mifospay.core.analytics.LocalAnalyticsHelper -import org.mifospay.core.data.util.NetworkMonitor -import org.mifospay.core.data.util.TimeZoneMonitor -import org.mifospay.core.designsystem.theme.MifosTheme -import org.mifospay.core.ui.LocalTimeZone -import org.mifospay.navigation.MifosNavGraph.LOGIN_GRAPH -import org.mifospay.navigation.MifosNavGraph.PASSCODE_GRAPH -import org.mifospay.navigation.RootNavGraph -import org.mifospay.ui.rememberMifosAppState - -@OptIn(ExperimentalMaterial3WindowSizeClassApi::class) -class MainActivity : ComponentActivity() { - - /** - * Lazily inject [JankStats], which is used to track jank throughout the app. - */ - - private val networkMonitor: NetworkMonitor by inject() - - private val timeZoneMonitor: TimeZoneMonitor by inject() - - private val analyticsHelper: AnalyticsHelper by inject() - - private val viewModel: MainActivityViewModel by viewModel() - - private val myWindow: Window by inject { parametersOf(this) } - - private val lazyStats: JankStats by inject { parametersOf(myWindow) } - - override fun onCreate(savedInstanceState: Bundle?) { - val splashScreen = installSplashScreen() - super.onCreate(savedInstanceState) - - var uiState: MainActivityUiState by mutableStateOf(Loading) - - // Update the uiState - lifecycleScope.launch { - lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { - viewModel.uiState - .onEach { uiState = it } - .collect() - } - } - - splashScreen.setKeepOnScreenCondition { - when (uiState) { - Loading -> true - is Success -> false - } - } - - enableEdgeToEdge() - - setContent { - val navController = rememberNavController() - - val appState = rememberMifosAppState( - windowSizeClass = calculateWindowSizeClass(this), - networkMonitor = networkMonitor, - timeZoneMonitor = timeZoneMonitor, - ) - - val currentTimeZone by appState.currentTimeZone.collectAsStateWithLifecycle() - - val navDestination = when (uiState) { - is Success -> if ((uiState as Success).userData.isAuthenticated) { - PASSCODE_GRAPH - } else { - LOGIN_GRAPH - } - - else -> LOGIN_GRAPH - } - - CompositionLocalProvider( - LocalAnalyticsHelper provides analyticsHelper, - LocalTimeZone provides currentTimeZone, - ) { - MifosTheme { - RootNavGraph( - appState = appState, - navHostController = navController, - startDestination = navDestination, - onClickLogout = { - viewModel.logOut() - navController.navigate(LOGIN_GRAPH) { - popUpTo(navController.graph.id) { - inclusive = true - } - } - }, - ) - } - } - } - } - - override fun onResume() { - super.onResume() - lazyStats.isTrackingEnabled = true - } - - override fun onPause() { - super.onPause() - lazyStats.isTrackingEnabled = false - } -} diff --git a/mifospay/src/main/java/org/mifospay/MifosPayApp.kt b/mifospay/src/main/java/org/mifospay/MifosPayApp.kt deleted file mode 100644 index e7403cf44..000000000 --- a/mifospay/src/main/java/org/mifospay/MifosPayApp.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay - -import android.app.Application -import org.koin.android.ext.koin.androidContext -import org.koin.core.context.startKoin -import org.koin.core.logger.Level -import org.mifospay.di.KoinModules - -class MifosPayApp : Application() { - override fun onCreate() { - super.onCreate() - val koinModules = KoinModules() - - startKoin { - printLogger(Level.ERROR) - androidContext(this@MifosPayApp) - modules( - listOf( - koinModules.dataModules, - koinModules.mifosPayModule, - koinModules - .coreDataStoreModules, - koinModules.featureModules, - koinModules.networkModules, - koinModules - .analyticsModules, - koinModules.commonModules, - koinModules.libsModule, - ), - ) - } - } -} diff --git a/mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt b/mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt deleted file mode 100644 index aa1210bf6..000000000 --- a/mifospay/src/main/java/org/mifospay/di/JankStatsModule.kt +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.di - -import android.app.Activity -import android.util.Log -import android.view.Window -import androidx.metrics.performance.JankStats -import org.koin.core.module.dsl.viewModel -import org.koin.dsl.module -import org.mifospay.MainActivityViewModel - -val JankStatsModule = module { - - factory { (activity: Activity) -> activity.window } - factory { (window: Window) -> - JankStats.createAndTrack(window) { frameData -> - // Make sure to only log janky frames. - if (frameData.isJank) { - // We're currently logging this but would better report it to a backend. - Log.v("Mifos Jank", frameData.toString()) - } - } - } - - viewModel { - MainActivityViewModel(userDataRepository = get(), passcodeManager = get()) - } -} diff --git a/mifospay/src/main/java/org/mifospay/di/KoinModules.kt b/mifospay/src/main/java/org/mifospay/di/KoinModules.kt deleted file mode 100644 index 72e1d3422..000000000 --- a/mifospay/src/main/java/org/mifospay/di/KoinModules.kt +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.di - -import org.koin.dsl.module -import org.mifos.library.passcode.di.ApplicationModule -import org.mifospay.core.analytics.di.AnalyticsModule -import org.mifospay.core.data.di.DataModule -import org.mifospay.core.data.di.LocalDataModule -import org.mifospay.core.datastore.di.CoreDataStoreModule -import org.mifospay.core.common.di.CoroutineScopesModule -import org.mifospay.core.common.di.DispatchersModule -import org.mifospay.core.network.di.LocalModule -import org.mifospay.core.network.di.NetworkModule -import org.mifospay.feature.auth.di.AuthModule -import org.mifospay.feature.bank.accounts.di.AccountsModule -import org.mifospay.feature.di.HistoryModule -import org.mifospay.feature.editpassword.di.EditPasswordModule -import org.mifospay.feature.faq.di.FaqModule -import org.mifospay.feature.home.di.HomeModule -import org.mifospay.feature.invoices.di.InvoicesModule -import org.mifospay.feature.kyc.di.KYCModule -import org.mifospay.feature.make.transfer.di.MakeTransferModule -import org.mifospay.feature.merchants.di.MerchantsModule -import org.mifospay.feature.notification.di.NotificationModule -import org.mifospay.feature.payments.di.PaymentsModule -import org.mifospay.feature.profile.di.ProfileModule -import org.mifospay.feature.read.qr.di.QrModule -import org.mifospay.feature.receipt.di.ReceiptModule -import org.mifospay.feature.request.money.di.RequestMoneyModule -import org.mifospay.feature.savedcards.di.SavedCardsModule -import org.mifospay.feature.search.di.SearchModule -import org.mifospay.feature.send.money.di.SendMoneyModule -import org.mifospay.feature.settings.di.SettingsModule -import org.mifospay.feature.standing.instruction.di.StandingInstructionModule -import org.mifospay.feature.upiSetup.di.UpiSetupModule - -class KoinModules { - val analyticsModules = module { - includes(AnalyticsModule) - } - val commonModules = module { - includes(CoroutineScopesModule, DispatchersModule) - } - val dataModules = module { - includes(DataModule, LocalDataModule) - } - val coreDataStoreModules = module { - includes(CoreDataStoreModule) - } - val networkModules = module { - includes(LocalModule, NetworkModule) - } - val featureModules = module { - includes( - AuthModule, AccountsModule, EditPasswordModule, FaqModule, HistoryModule, HomeModule, - InvoicesModule, KYCModule, MakeTransferModule, MerchantsModule, NotificationModule, - PaymentsModule, ProfileModule, QrModule, ReceiptModule, RequestMoneyModule, - SavedCardsModule, SearchModule, SendMoneyModule, SettingsModule, - StandingInstructionModule, UpiSetupModule, - ) - } - val mifosPayModule = module { - includes(JankStatsModule) - } - val libsModule = module { - includes(ApplicationModule) - } -} diff --git a/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt b/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt deleted file mode 100644 index dc2a4acc5..000000000 --- a/mifospay/src/main/java/org/mifospay/navigation/MifosNavHost.kt +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.navigation - -import android.content.Context -import android.net.Uri -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.core.content.FileProvider -import androidx.navigation.compose.NavHost -import com.mifos.library.material3.navigation.ModalBottomSheetLayout -import org.mifospay.core.common.Constants -import org.mifospay.core.ui.utility.TabContent -import org.mifospay.feature.bank.accounts.AccountsScreen -import org.mifospay.feature.bank.accounts.navigation.bankAccountDetailScreen -import org.mifospay.feature.bank.accounts.navigation.linkBankAccountScreen -import org.mifospay.feature.bank.accounts.navigation.navigateToBankAccountDetail -import org.mifospay.feature.bank.accounts.navigation.navigateToLinkBankAccount -import org.mifospay.feature.editpassword.navigation.editPasswordScreen -import org.mifospay.feature.editpassword.navigation.navigateToEditPassword -import org.mifospay.feature.faq.navigation.faqScreen -import org.mifospay.feature.finance.FinanceScreenContents -import org.mifospay.feature.finance.navigation.financeScreen -import org.mifospay.feature.history.HistoryScreen -import org.mifospay.feature.home.navigation.HOME_ROUTE -import org.mifospay.feature.home.navigation.homeScreen -import org.mifospay.feature.invoices.InvoiceScreenRoute -import org.mifospay.feature.invoices.navigation.invoiceDetailScreen -import org.mifospay.feature.invoices.navigation.navigateToInvoiceDetail -import org.mifospay.feature.kyc.KYCScreen -import org.mifospay.feature.kyc.navigation.kycLevel1Screen -import org.mifospay.feature.kyc.navigation.kycLevel2Screen -import org.mifospay.feature.kyc.navigation.kycLevel3Screen -import org.mifospay.feature.kyc.navigation.kycScreen -import org.mifospay.feature.kyc.navigation.navigateToKYCLevel1 -import org.mifospay.feature.kyc.navigation.navigateToKYCLevel2 -import org.mifospay.feature.kyc.navigation.navigateToKYCLevel3 -import org.mifospay.feature.make.transfer.navigation.makeTransferScreen -import org.mifospay.feature.make.transfer.navigation.navigateToMakeTransferScreen -import org.mifospay.feature.merchants.navigation.merchantTransferScreen -import org.mifospay.feature.merchants.ui.MerchantScreen -import org.mifospay.feature.notification.notificationScreen -import org.mifospay.feature.payments.PaymentsScreenContents -import org.mifospay.feature.payments.RequestScreen -import org.mifospay.feature.payments.paymentsScreen -import org.mifospay.feature.profile.navigation.editProfileScreen -import org.mifospay.feature.profile.navigation.navigateToEditProfile -import org.mifospay.feature.profile.navigation.profileScreen -import org.mifospay.feature.read.qr.navigation.readQrScreen -import org.mifospay.feature.receipt.navigation.navigateToReceipt -import org.mifospay.feature.receipt.navigation.receiptScreen -import org.mifospay.feature.request.money.navigation.navigateToShowQrScreen -import org.mifospay.feature.request.money.navigation.showQrScreen -import org.mifospay.feature.savedcards.CardsScreen -import org.mifospay.feature.savedcards.navigation.addCardScreen -import org.mifospay.feature.search.searchScreen -import org.mifospay.feature.send.money.SendScreenRoute -import org.mifospay.feature.send.money.navigation.navigateToSendMoneyScreen -import org.mifospay.feature.send.money.navigation.sendMoneyScreen -import org.mifospay.feature.settings.navigation.navigateToSettings -import org.mifospay.feature.settings.navigation.settingsScreen -import org.mifospay.feature.specific.transactions.navigation.navigateToSpecificTransactions -import org.mifospay.feature.specific.transactions.navigation.specificTransactionsScreen -import org.mifospay.feature.standing.instruction.StandingInstructionsScreenRoute -import org.mifospay.feature.standing.instruction.navigateToNewSiScreen -import org.mifospay.feature.standing.instruction.newSiScreen -import org.mifospay.feature.standing.instruction.siDetailsScreen -import org.mifospay.feature.upiSetup.navigation.navigateToSetupUpiPin -import org.mifospay.feature.upiSetup.navigation.setupUpiPinScreen -import org.mifospay.ui.MifosAppState -import java.io.File -import java.util.Objects - -/** - * Top-level navigation graph. Navigation is organized as explained at - * https://d.android.com/jetpack/compose/nav-adaptive - * - * The navigation graph defined in this file defines the different top level routes. Navigation - * within each route is handled using state and Back Handlers. - */ -@Suppress("MaxLineLength", "LongMethod") -@Composable -internal fun MifosNavHost( - appState: MifosAppState, - onClickLogout: () -> Unit, - modifier: Modifier = Modifier, -) { - val navController = appState.navController - - val tabContents = listOf( - TabContent(FinanceScreenContents.ACCOUNTS.name) { - AccountsScreen( - navigateToBankAccountDetailScreen = navController::navigateToBankAccountDetail, - navigateToLinkBankAccountScreen = navController::navigateToLinkBankAccount, - ) - }, - TabContent(FinanceScreenContents.CARDS.name) { - CardsScreen(onEditCard = {}) - }, - TabContent(FinanceScreenContents.MERCHANTS.name) { - MerchantScreen() - }, - TabContent(FinanceScreenContents.KYC.name) { - KYCScreen( - onLevel1Clicked = navController::navigateToKYCLevel1, - onLevel2Clicked = navController::navigateToKYCLevel2, - onLevel3Clicked = navController::navigateToKYCLevel3, - ) - }, - ) - - val paymentsTabContents = listOf( - TabContent(PaymentsScreenContents.SEND.name) { - SendScreenRoute( - onBackClick = {}, - showToolBar = false, - proceedWithMakeTransferFlow = navController::navigateToMakeTransferScreen, - ) - }, - TabContent(PaymentsScreenContents.REQUEST.name) { - RequestScreen(showQr = navController::navigateToShowQrScreen) - }, - TabContent(PaymentsScreenContents.HISTORY.name) { - HistoryScreen( - accountClicked = navController::navigateToSpecificTransactions, - viewReceipt = { - navController - .navigateToReceipt(Uri.parse(Constants.RECEIPT_DOMAIN + it)) - }, - ) - }, - TabContent(PaymentsScreenContents.SI.name) { - StandingInstructionsScreenRoute( - onNewSI = navController::navigateToNewSiScreen, - onBackPress = navController::popBackStack, - ) - }, - TabContent(PaymentsScreenContents.INVOICES.name) { - InvoiceScreenRoute( - navigateToInvoiceDetailScreen = { - navController.navigateToInvoiceDetail(it.toString()) - }, - ) - }, - ) - - ModalBottomSheetLayout( - bottomSheetNavigator = appState.bottomSheetNavigator, - modifier = modifier, - ) { - NavHost( - route = MifosNavGraph.MAIN_GRAPH, - startDestination = HOME_ROUTE, - navController = navController, - ) { - homeScreen( - onRequest = navController::navigateToShowQrScreen, - onPay = navController::navigateToSendMoneyScreen, - ) - paymentsScreen( - tabContents = paymentsTabContents, - ) - financeScreen( - tabContents = tabContents, - ) - addCardScreen( - onDismiss = navController::popBackStack, - onAddCard = { - // Handle adding the cards - navController.popBackStack() - }, - ) - profileScreen( - onEditProfile = navController::navigateToEditProfile, - onSettings = navController::navigateToSettings, - ) - sendMoneyScreen( - onBackClick = navController::popBackStack, - proceedWithMakeTransferFlow = navController::navigateToMakeTransferScreen, - ) - makeTransferScreen( - onDismiss = navController::popBackStack, - ) - showQrScreen( - onBackClick = navController::popBackStack, - ) - merchantTransferScreen( - proceedWithMakeTransferFlow = navController::navigateToMakeTransferScreen, - onBackPressed = navController::popBackStack, - ) - settingsScreen( - onBackPress = navController::popBackStack, - navigateToEditPasswordScreen = navController::navigateToEditPassword, - onLogout = onClickLogout, - onChangePasscode = { - // TODO:: Implement change passcode screen - }, - ) - - kycScreen( - onLevel1Clicked = navController::navigateToKYCLevel1, - onLevel2Clicked = navController::navigateToKYCLevel2, - onLevel3Clicked = navController::navigateToKYCLevel3, - ) - kycLevel1Screen( - navigateToKycLevel2 = navController::navigateToKYCLevel2, - ) - kycLevel2Screen( - onSuccessKyc2 = navController::navigateToKYCLevel3, - ) - - kycLevel3Screen() - - newSiScreen(onBackClick = navController::popBackStack) - - siDetailsScreen( - onClickCreateNew = navController::navigateToNewSiScreen, - onBackPress = navController::popBackStack, - ) - - editProfileScreen( - onBackPress = navController::popBackStack, - getUri = ::getUri, - ) - - faqScreen( - navigateBack = navController::popBackStack, - ) - readQrScreen( - onBackClick = navController::popBackStack, - ) - - specificTransactionsScreen( - onBackClick = navController::popBackStack, - onTransactionItemClicked = { transactionId -> - navController.navigateToReceipt(Uri.parse(Constants.RECEIPT_DOMAIN + transactionId)) - }, - ) - invoiceDetailScreen( - onBackPress = navController::popBackStack, - navigateToReceiptScreen = { uri -> - navController.navigateToReceipt(Uri.parse(Constants.RECEIPT_DOMAIN + uri)) - }, - ) - receiptScreen( - openPassCodeActivity = { - // TODO: Implement Passcode Screen for Receipt - }, - onBackClick = navController::popBackStack, - ) - setupUpiPinScreen( - onBackPress = navController::popBackStack, - ) - - bankAccountDetailScreen( - onSetupUpiPin = { bankAccountDetails, index -> - navController.navigateToSetupUpiPin(bankAccountDetails, index, Constants.SETUP) - }, - onChangeUpiPin = { bankAccountDetails, index -> - navController.navigateToSetupUpiPin(bankAccountDetails, index, Constants.CHANGE) - }, - onForgotUpiPin = { bankAccountDetails, index -> - navController.navigateToSetupUpiPin(bankAccountDetails, index, Constants.FORGOT) - }, - onBackClick = { bankAccountDetails, index -> - navController.previousBackStackEntry?.savedStateHandle?.set( - Constants.UPDATED_BANK_ACCOUNT, - bankAccountDetails, - ) - navController.previousBackStackEntry?.savedStateHandle?.set( - Constants.INDEX, - index, - ) - navController.popBackStack() - }, - ) - linkBankAccountScreen( - onBackClick = navController::popBackStack, - ) - editPasswordScreen( - onBackPress = navController::popBackStack, - onCancelChanges = navController::popBackStack, - ) - - notificationScreen() - - searchScreen(onBackClick = navController::popBackStack) - } - } -} - -fun getUri(context: Context, file: File): Uri { - val uri = FileProvider.getUriForFile( - Objects.requireNonNull(context), - org.mifospay.BuildConfig.APPLICATION_ID + ".provider", - file, - ) - return uri -} diff --git a/mifospay/src/main/java/org/mifospay/navigation/PasscodeNavGraph.kt b/mifospay/src/main/java/org/mifospay/navigation/PasscodeNavGraph.kt deleted file mode 100644 index a672817e2..000000000 --- a/mifospay/src/main/java/org/mifospay/navigation/PasscodeNavGraph.kt +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.navigation - -import androidx.navigation.NavController -import androidx.navigation.NavGraphBuilder -import androidx.navigation.navigation -import org.mifos.library.passcode.PASSCODE_SCREEN -import org.mifos.library.passcode.passcodeRoute - -internal fun NavGraphBuilder.passcodeNavGraph(navController: NavController) { - navigation( - route = MifosNavGraph.PASSCODE_GRAPH, - startDestination = PASSCODE_SCREEN, - ) { - passcodeRoute( - onForgotButton = { - navController.popBackStack() - navController.navigate(MifosNavGraph.MAIN_GRAPH) - }, - onSkipButton = { - navController.popBackStack() - navController.navigate(MifosNavGraph.MAIN_GRAPH) - }, - onPasscodeConfirm = { - navController.popBackStack() - navController.navigate(MifosNavGraph.MAIN_GRAPH) - }, - onPasscodeRejected = { - navController.popBackStack() - navController.navigate(MifosNavGraph.MAIN_GRAPH) - }, - ) - } -} diff --git a/scripts/pre-commit.sh b/scripts/pre-commit.sh index c49bfe109..2f87f220e 100644 --- a/scripts/pre-commit.sh +++ b/scripts/pre-commit.sh @@ -74,26 +74,6 @@ run_detekt_checks() { fi } -# Function to run Version Catalog checks -run_version_catalog_checks() { - echo "\nšŸš€ Version catalog linter is now analyzing your catalog for potential issues!" - ./gradlew formatVersionCatalog > /tmp/catalog-result - DETEKT_EXIT_CODE=$? - - if [ ${DETEKT_EXIT_CODE} -ne 0 ]; then - cat /tmp/catalog-result - rm /tmp/catalog-result - echo "\n*********************************************************************************" - echo " šŸ’„ Oh no! Version Catalog found issues in the code! Time to fix those issues! šŸ’„" - echo " šŸ’” Tip: Review the Version Catalog logs to resolve these issues. šŸ› ļø" - echo "*********************************************************************************" - exit ${DETEKT_EXIT_CODE} - else - rm /tmp/catalog-result - echo "šŸŽ‰ Fantastic work! Your Version catalog has been formatted successfully šŸš€šŸŒŸ" - fi -} - # Function to print success message print_success_message() { GIT_USERNAME=$(git config user.name) @@ -109,7 +89,6 @@ check_current_branch run_spotless_checks run_detekt_checks run_dependency_guard -run_version_catalog_checks print_success_message exit 0 diff --git a/scripts/pre-push.sh b/scripts/pre-push.sh index cad5ba9a1..d628bc07b 100644 --- a/scripts/pre-push.sh +++ b/scripts/pre-push.sh @@ -80,29 +80,6 @@ run_dependency_guard() { fi } -# Function to run Version Catalog checks -run_version_catalog_checks() { - echo "\nšŸš€ Version catalog linter is now analyzing your catalog for potential issues!" - ./gradlew checkVersionCatalog > /tmp/catalog-result - DETEKT_EXIT_CODE=$? - - if [ ${DETEKT_EXIT_CODE} -ne 0 ]; then - cat /tmp/catalog-result - rm /tmp/catalog-result - echo "\n*********************************************************************************" - echo " šŸ’„ Oh no! Version Catalog found issues in the code! Time to fix those issues! šŸ’„" - echo " šŸ’” Tip: Review the Version Catalog logs to resolve these issues. šŸ› ļø" - echo "*********************************************************************************" - echo "šŸš€ Attempting to format the Version Catalog again..." - ./gradlew formatVersionCatalog > /tmp/catalog-result - rm /tmp/catalog-result - echo "šŸŽ‰ Fantastic work! Your Version catalog has been formatted successfully šŸš€šŸŒŸ" - else - rm /tmp/catalog-result - echo "šŸŽ‰ Fantastic work! Your Version catalog has been formatted properly šŸš€šŸŒŸ" - fi -} - # Function to print success message print_success_message() { GIT_USERNAME=$(git config user.name) @@ -118,7 +95,6 @@ check_current_branch run_spotless_checks run_detekt_checks run_dependency_guard -run_version_catalog_checks print_success_message exit 0 diff --git a/settings.gradle.kts b/settings.gradle.kts index f43a17c79..1ccad1d2f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -34,9 +34,14 @@ extensions.configure { rootProject.name = "mobile-wallet" enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") -include(":mifospay") + +include(":mifospay-shared") +include(":mifospay-android") +include(":mifospay-desktop") +include(":mifospay-web") include(":core:data") +include(":core:domain") include(":core:datastore") include(":core:designsystem") include(":core:ui") @@ -47,8 +52,6 @@ include(":core:model") include(":core:datastore-proto") include(":core:analytics") -include(":lint") - include(":feature:home") include(":feature:history") include(":feature:receipt") @@ -74,10 +77,9 @@ include(":feature:upi-setup") include(":feature:qr") include(":feature:search") +include(":lint") + include(":libs:country-code-picker") include(":libs:pullrefresh") include(":libs:material3-navigation") include(":libs:mifos-passcode") - -include(":shared") -include(":desktop") diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts deleted file mode 100644 index fec478782..000000000 --- a/shared/build.gradle.kts +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi -import org.jetbrains.kotlin.gradle.dsl.JvmTarget - -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -plugins { - alias(libs.plugins.kotlinMultiplatform) - alias(libs.plugins.android.library) - alias(libs.plugins.compose.compiler) - alias(libs.plugins.jetbrainsCompose) - alias(libs.plugins.wire) - id("kotlin-parcelize") -} - -kotlin { - androidTarget { - @OptIn(ExperimentalKotlinGradlePluginApi::class) - compilerOptions { - jvmTarget.set(JvmTarget.JVM_11) - } - } - - jvm("desktop") - - listOf( - iosX64(), - iosArm64(), - iosSimulatorArm64() - ).forEach { - it.binaries.framework { - baseName = "shared" - isStatic = true - } - } - - sourceSets { - androidMain.dependencies { - implementation(compose.preview) - implementation(libs.androidx.activity.compose) - - implementation(libs.koin.android) - implementation(libs.koin.androidx.compose) - } - - commonMain.dependencies { - //put your multiplatform dependencies here - implementation(compose.runtime) - implementation(compose.material3) - implementation(compose.ui) - implementation(compose.components.resources) - implementation(compose.components.uiToolingPreview) - - implementation(libs.kotlinx.datetime) - implementation(libs.kotlinx.serialization.json) - - api(libs.koin.core) - implementation(libs.koin.compose) - - implementation(libs.datastore) - } - - val desktopMain by getting { - dependencies { - // Desktop specific dependencies - implementation(compose.desktop.currentOs) - implementation(compose.desktop.common) - } - } - } - - task("testClasses") -} - -wire { - kotlin {} - sourcePath { - srcDir("src/commonMain/proto") - } -} - -android { - namespace = "org.mifospay.shared" - compileSdk = 34 - - defaultConfig { - minSdk = 24 - } - - packaging { - resources { - excludes += "/META-INF/{AL2.0,LGPL2.1}" - } - } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 - } - - dependencies { - debugImplementation(compose.uiTooling) - } -} diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/MainActivity.kt b/shared/src/androidMain/kotlin/org/mifospay/shared/MainActivity.kt deleted file mode 100644 index e65339b5a..000000000 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/MainActivity.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import android.os.Bundle -import androidx.activity.ComponentActivity -import androidx.activity.compose.setContent -import androidx.compose.runtime.Composable -import androidx.compose.ui.tooling.preview.Preview - -class MainActivity : ComponentActivity() { - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setContent { - App() - } - } -} - -@Preview -@Composable -fun AppAndroidPreview() { - App() -} diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/Platform.android.kt b/shared/src/androidMain/kotlin/org/mifospay/shared/Platform.android.kt deleted file mode 100644 index 909044b97..000000000 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/Platform.android.kt +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import android.os.Parcelable -import kotlinx.parcelize.Parcelize - -class AndroidPlatform : Platform { - override val name: String = "Android ${android.os.Build.VERSION.SDK_INT}" -} - -actual fun getPlatform(): Platform = AndroidPlatform() - -actual typealias CommonParcelize = Parcelize -actual typealias CommonParcelable = Parcelable diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/di/AndroidPlatformContextProvider.kt b/shared/src/androidMain/kotlin/org/mifospay/shared/di/AndroidPlatformContextProvider.kt deleted file mode 100644 index 9c6908224..000000000 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/di/AndroidPlatformContextProvider.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.di - -import android.content.Context - -object AndroidPlatformContextProvider { - private var appContext: Context? = null - - val context: Context? - get() = appContext - - fun setContext(context: Context) { - appContext = context - } -} diff --git a/shared/src/androidMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.android.kt b/shared/src/androidMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.android.kt deleted file mode 100644 index 7976d9c2b..000000000 --- a/shared/src/androidMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.android.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.DataStore -import okio.FileSystem -import okio.Path.Companion.toPath -import org.mifospay.shared.commonMain.proto.UserPreferences -import org.mifospay.shared.di.AndroidPlatformContextProvider - -actual fun getDataStore(): DataStore { - val content = requireNotNull(AndroidPlatformContextProvider.context) - val producePath = { content.filesDir.resolve(DATA_STORE_FILE_NAME).absolutePath.toPath() } - - return createDataStore(fileSystem = FileSystem.SYSTEM, producePath = producePath) -} diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/App.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/App.kt deleted file mode 100644 index 8e9fb5365..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/App.kt +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.text.font.FontWeight -import org.koin.compose.KoinContext - -@Composable -fun App() { - KoinContext { - Box( - modifier = Modifier - .fillMaxSize(), - contentAlignment = Alignment.Center, - ) { - Text( - text = "MifosWallet", - style = MaterialTheme.typography.titleLarge.copy(fontWeight = FontWeight.Bold), - color = MaterialTheme.colorScheme.onSurface, - ) - } - } -} diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/Platform.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/Platform.kt deleted file mode 100644 index 00ed0030d..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/Platform.kt +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -interface Platform { - val name: String -} - -expect fun getPlatform(): Platform - -// For Android @Parcelize -@OptIn(ExperimentalMultiplatform::class) -@OptionalExpectation -@Target(AnnotationTarget.CLASS) -@Retention(AnnotationRetention.BINARY) -expect annotation class CommonParcelize() - -// For Android Parcelable -expect interface CommonParcelable diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Client.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Client.kt deleted file mode 100644 index 60f1e2d05..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/Client.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.modal.domain - -data class Client( - var name: String? = null, - var image: String, - var externalId: String? = null, - var clientId: Long = 0L, - var displayName: String, - var mobileNo: String, -) diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/User.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/User.kt deleted file mode 100644 index dad50bcc7..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/User.kt +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.modal.domain - -data class User( - val username: String, - val userId: Long = 0, - val base64EncodedAuthenticationKey: String, - val authenticated: Boolean = false, - val officeId: Int, - val officeName: String, - val roles: List, - val permissions: List, - val clients: List, - val shouldRenewPassword: Boolean, - val isTwoFactorAuthenticationRequired: Boolean, -) diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/UserData.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/UserData.kt deleted file mode 100644 index 4191ecd67..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/modal/domain/UserData.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.modal.domain - -data class UserData( - val authToken: String, - val user: String, - val userEmail: String, - val client: String, -) diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.kt deleted file mode 100644 index 2c7fbe6f2..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.kt +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.DataStore -import androidx.datastore.core.DataStoreFactory -import androidx.datastore.core.okio.OkioStorage -import okio.FileSystem -import okio.Path -import org.mifospay.shared.commonMain.proto.UserPreferences -internal const val DATA_STORE_FILE_NAME = "user.preferences_pb" - -expect fun getDataStore(): DataStore - -fun createDataStore( - fileSystem: FileSystem, - producePath: () -> Path, -): DataStore = - DataStoreFactory.create( - storage = OkioStorage( - fileSystem = fileSystem, - producePath = producePath, - serializer = UserPreferenceSerializer, - ), - ) diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceRepository.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceRepository.kt deleted file mode 100644 index 294905f01..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceRepository.kt +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.DataStore -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import org.mifospay.shared.commonMain.proto.Client -import org.mifospay.shared.commonMain.proto.User -import org.mifospay.shared.commonMain.proto.UserPreferences - -interface UserPreferenceRepository { - suspend fun saveToken(token: String) - fun getToken(): Flow - suspend fun saveFullName(name: String) - fun getFullName(): Flow - suspend fun saveUsername(name: String) - fun getUsername(): Flow - suspend fun saveEmail(email: String) - fun getEmail(): Flow - suspend fun saveMobile(mobile: String) - fun getMobile(): Flow - fun getUserId(): Flow - suspend fun setUserId(id: Int) - fun getClientId(): Flow - suspend fun setClientId(clientId: Int) - fun getClientVpa(): Flow - suspend fun setClientVpa(vpa: String) - fun getAccountId(): Flow - suspend fun setAccountId(accountId: Int) - fun getFirebaseRegId(): Flow - suspend fun setFirebaseRegId(firebaseRegId: String) - fun getUser(): Flow - suspend fun setUser(user: User) - fun getClient(): Flow - suspend fun setClient(client: Client) -} - -class UserPreferenceRepositoryImpl( - private val dataStore: DataStore = getDataStore(), -) : UserPreferenceRepository { - - override suspend fun saveToken(token: String) { - dataStore.updateData { preferences -> - preferences.copy(token = token) - } - } - - override fun getToken(): Flow { - return dataStore.data.map { it.token } - } - - override suspend fun saveFullName(name: String) { - dataStore.updateData { preferences -> - preferences.copy(name = name) - } - } - - override fun getFullName(): Flow { - return dataStore.data.map { it.name } - } - - override suspend fun saveUsername(name: String) { - dataStore.updateData { preferences -> - preferences.copy(username = name) - } - } - - override fun getUsername(): Flow { - return dataStore.data.map { it.username } - } - - override suspend fun saveEmail(email: String) { - dataStore.updateData { preferences -> - preferences.copy(email = email) - } - } - - override fun getEmail(): Flow { - return dataStore.data.map { it.email } - } - - override suspend fun saveMobile(mobile: String) { - dataStore.updateData { preferences -> - preferences.copy(mobile_no = mobile) - } - } - - override fun getMobile(): Flow { - return dataStore.data.map { it.mobile_no } - } - - override fun getUserId(): Flow { - return dataStore.data.map { it.user_id } - } - - override suspend fun setUserId(id: Int) { - dataStore.updateData { preferences -> - preferences.copy(user_id = id) - } - } - - override fun getClientId(): Flow { - return dataStore.data.map { it.client_id } - } - - override suspend fun setClientId(clientId: Int) { - dataStore.updateData { preferences -> - preferences.copy(client_id = clientId) - } - } - - override fun getClientVpa(): Flow { - return dataStore.data.map { it.client_vpa } - } - - override suspend fun setClientVpa(vpa: String) { - dataStore.updateData { preferences -> - preferences.copy(client_vpa = vpa) - } - } - - override fun getAccountId(): Flow { - return dataStore.data.map { it.account_id } - } - - override suspend fun setAccountId(accountId: Int) { - dataStore.updateData { preferences -> - preferences.copy(account_id = accountId) - } - } - - override fun getFirebaseRegId(): Flow { - return dataStore.data.map { it.firebase_reg_id } - } - - override suspend fun setFirebaseRegId(firebaseRegId: String) { - dataStore.updateData { preferences -> - preferences.copy(firebase_reg_id = firebaseRegId) - } - } - - override fun getUser(): Flow { - return dataStore.data.map { it.user!! } - } - - override suspend fun setUser(user: User) { - dataStore.updateData { preferences -> - preferences.copy(user = user) - } - } - - override fun getClient(): Flow { - return dataStore.data.map { it.client!! } - } - - override suspend fun setClient(client: Client) { - dataStore.updateData { preferences -> - preferences.copy(client = client) - } - } -} diff --git a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceSerializer.kt b/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceSerializer.kt deleted file mode 100644 index 803b106af..000000000 --- a/shared/src/commonMain/kotlin/org/mifospay/shared/preferences/UserPreferenceSerializer.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.okio.OkioSerializer -import okio.BufferedSink -import okio.BufferedSource -import okio.IOException -import org.mifospay.shared.commonMain.proto.UserPreferences - -object UserPreferenceSerializer : OkioSerializer { - override val defaultValue: UserPreferences - get() = UserPreferences() - - override suspend fun readFrom(source: BufferedSource): UserPreferences { - try { - return UserPreferences.ADAPTER.decode(source) - } catch (exception: IOException) { - throw Exception(exception.message ?: "Serialization Exception") - } - } - - override suspend fun writeTo(t: UserPreferences, sink: BufferedSink) { - sink.write(t.encode()) - } -} diff --git a/shared/src/commonMain/proto/user_preferences.proto b/shared/src/commonMain/proto/user_preferences.proto deleted file mode 100644 index 1a7a43dc5..000000000 --- a/shared/src/commonMain/proto/user_preferences.proto +++ /dev/null @@ -1,49 +0,0 @@ -syntax = "proto3"; - -option java_package = "org.mifospay.shared.commonMain.proto"; -option java_multiple_files = true; - -message UserPreferences { - string token = 1; - string name = 2; - string username = 3; - string email = 4; - string mobile_no = 5; - int32 user_id = 6; - int32 client_id = 7; - string client_vpa = 8; - int32 account_id = 9; - string firebase_reg_id = 10; - Client client = 11; - User user = 12; -} - -message Client { - string name = 1; - string image = 2; - string external_id = 3; - int64 clientId = 4; - string display_name = 5; - string mobileNo = 6; -} - -message User { - string username = 1; - int64 userId = 2; - string base64EncodedAuthenticationKey = 3; - bool authenticated = 4; - int32 officeId = 5; - string officeName = 6; - repeated Role roles = 7; - repeated string permissions = 8; - repeated int64 clients = 9; - bool shouldRenewPassword = 10; - bool isTwoFactorAuthenticationRequired = 11; -} - -message Role { - string id = 1; - string name = 2; - string description = 3; - bool disabled = 4; -} \ No newline at end of file diff --git a/shared/src/desktopMain/kotlin/org/mifospay/shared/Platform.desktop.kt b/shared/src/desktopMain/kotlin/org/mifospay/shared/Platform.desktop.kt deleted file mode 100644 index fcc74d588..000000000 --- a/shared/src/desktopMain/kotlin/org/mifospay/shared/Platform.desktop.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import androidx.compose.runtime.Composable - -@Composable -fun MainView() = App() - -class JVMPlatform : Platform { - override val name: String = "Windows" -} - -actual fun getPlatform(): Platform = JVMPlatform() - -actual interface CommonParcelable diff --git a/shared/src/desktopMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.desktop.kt b/shared/src/desktopMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.desktop.kt deleted file mode 100644 index 64fe263b0..000000000 --- a/shared/src/desktopMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.desktop.kt +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.DataStore -import okio.FileSystem -import okio.Path.Companion.toPath -import org.mifospay.shared.commonMain.proto.UserPreferences -import java.io.File - -actual fun getDataStore(): DataStore { - val dbFile = File(System.getProperty("java.io.tmpdir"), DATA_STORE_FILE_NAME) - - return createDataStore( - fileSystem = FileSystem.SYSTEM, - producePath = { dbFile.absolutePath.toPath() }, - ) -} diff --git a/shared/src/iosMain/kotlin/org/mifospay/shared/MainViewController.kt b/shared/src/iosMain/kotlin/org/mifospay/shared/MainViewController.kt deleted file mode 100644 index 1f5f6765a..000000000 --- a/shared/src/iosMain/kotlin/org/mifospay/shared/MainViewController.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import androidx.compose.ui.window.ComposeUIViewController -import org.mifospay.shared.di.initKoin - -fun mainViewController() = ComposeUIViewController( - configure = { - initKoin() - }, -) { - App() -} diff --git a/shared/src/iosMain/kotlin/org/mifospay/shared/Platform.ios.kt b/shared/src/iosMain/kotlin/org/mifospay/shared/Platform.ios.kt deleted file mode 100644 index 22fb77da7..000000000 --- a/shared/src/iosMain/kotlin/org/mifospay/shared/Platform.ios.kt +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared - -import platform.UIKit.UIDevice - -class IOSPlatform : Platform { - override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion -} - -actual fun getPlatform(): Platform = IOSPlatform() - -actual interface CommonParcelable diff --git a/shared/src/iosMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.ios.kt b/shared/src/iosMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.ios.kt deleted file mode 100644 index 6e7e19d38..000000000 --- a/shared/src/iosMain/kotlin/org/mifospay/shared/preferences/DataStoreModule.ios.kt +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2024 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md - */ -package org.mifospay.shared.preferences - -import androidx.datastore.core.DataStore -import okio.FileSystem -import okio.Path.Companion.toPath -import org.mifospay.shared.commonMain.proto.UserPreferences - -actual fun getDataStore(): DataStore { - return createDataStore( - fileSystem = FileSystem.SYSTEM, - producePath = { "${documentDirectory()}/$DATA_STORE_FILE_NAME".toPath() }, - ) -} - -private fun documentDirectory(): String { - val documentDirectory = NSFileManager.defaultManager.URLForDirectory( - directory = NSDocumentDirectory, - inDomain = NSUserDomainMask, - appropriateForURL = null, - create = false, - error = null, - ) - return requireNotNull(documentDirectory?.path) -}