diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 786923c..f91637f 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -5,6 +5,7 @@ plugins { alias(libs.plugins.self.application) alias(libs.plugins.self.compose) alias(libs.plugins.androidx.room) + alias(libs.plugins.koin) alias(libs.plugins.kotlin.serialization) alias(libs.plugins.ksp) } @@ -13,14 +14,13 @@ val baseVersionName = "1.0.1" val gitCommitTag = gitCommitTag() val gitCommitSha = gitCommitSha() val gitCommitNum = gitCommitNum() -val devSuffix = if (gitCommitTag.isEmpty()) ".dev" else "" android { namespace = "dev.sanmer.authenticator" defaultConfig { applicationId = namespace - versionName = "${baseVersionName}.${gitCommitSha}${devSuffix}" + versionName = baseVersionName + if (gitCommitTag.isEmpty()) ".$gitCommitSha" else "" versionCode = gitCommitNum ndk.abiFilters += listOf("arm64-v8a", "x86_64") } @@ -103,7 +103,6 @@ dependencies { implementation(libs.androidx.camera.compose) implementation(libs.androidx.camera.lifecycle) implementation(platform(libs.androidx.compose.bom)) - implementation(libs.androidx.compose.material.icons.extended) implementation(libs.androidx.compose.material3) implementation(libs.androidx.compose.ui) debugImplementation(libs.androidx.compose.ui.tooling) @@ -119,8 +118,11 @@ dependencies { implementation(libs.androidx.navigation3.ui) implementation(libs.androidx.room.runtime) ksp(libs.androidx.room.compiler) + implementation(platform(libs.koin.bom)) implementation(libs.koin.android) + implementation(libs.koin.annotations) implementation(libs.koin.compose) + implementation(libs.koin.compose.viewmodel) implementation(libs.koin.compose.navigation3) implementation(libs.kotlinx.coroutines.android) implementation(libs.kotlinx.datetime) diff --git a/app/src/main/kotlin/dev/sanmer/authenticator/App.kt b/app/src/main/kotlin/dev/sanmer/authenticator/App.kt index 875ae49..b4e4e68 100644 --- a/app/src/main/kotlin/dev/sanmer/authenticator/App.kt +++ b/app/src/main/kotlin/dev/sanmer/authenticator/App.kt @@ -4,31 +4,25 @@ import android.app.Application import android.util.Log import androidx.camera.camera2.Camera2Config import androidx.camera.core.CameraXConfig -import dev.sanmer.authenticator.di.DataStore -import dev.sanmer.authenticator.di.Database -import dev.sanmer.authenticator.di.Navigation -import dev.sanmer.authenticator.di.Repositories +import dev.sanmer.authenticator.di.AppModule import org.koin.android.ext.koin.androidContext import org.koin.android.ext.koin.androidLogger import org.koin.core.context.startKoin +import org.koin.core.logger.Level class App : Application(), CameraXConfig.Provider { override fun onCreate() { super.onCreate() startKoin { - androidLogger() + androidLogger(if (BuildConfig.DEBUG) Level.DEBUG else Level.INFO) androidContext(this@App) - modules(DataStore, Database, Repositories, Navigation) + modules(AppModule) } } override fun getCameraXConfig() = CameraXConfig.Builder.fromConfig(Camera2Config.defaultConfig()) .apply { - if (BuildConfig.DEBUG) { - setMinimumLoggingLevel(Log.DEBUG) - } else { - setMinimumLoggingLevel(Log.INFO) - } + setMinimumLoggingLevel(if (BuildConfig.DEBUG) Log.DEBUG else Log.INFO) }.build() } \ No newline at end of file diff --git a/app/src/main/kotlin/dev/sanmer/authenticator/di/NavigationModule.kt b/app/src/main/kotlin/dev/sanmer/authenticator/di/AppModule.kt similarity index 85% rename from app/src/main/kotlin/dev/sanmer/authenticator/di/NavigationModule.kt rename to app/src/main/kotlin/dev/sanmer/authenticator/di/AppModule.kt index 67b10f1..21b11f5 100644 --- a/app/src/main/kotlin/dev/sanmer/authenticator/di/NavigationModule.kt +++ b/app/src/main/kotlin/dev/sanmer/authenticator/di/AppModule.kt @@ -15,36 +15,22 @@ import dev.sanmer.authenticator.ui.screen.brand.BrandScreen import dev.sanmer.authenticator.ui.screen.edit.EditScreen import dev.sanmer.authenticator.ui.screen.edit.EditViewModel import dev.sanmer.authenticator.ui.screen.export.ExportScreen -import dev.sanmer.authenticator.ui.screen.export.ExportViewModel import dev.sanmer.authenticator.ui.screen.home.HomeScreen -import dev.sanmer.authenticator.ui.screen.home.HomeViewModel -import dev.sanmer.authenticator.ui.screen.main.MainViewModel import dev.sanmer.authenticator.ui.screen.ntp.NtpScreen -import dev.sanmer.authenticator.ui.screen.ntp.NtpViewModel import dev.sanmer.authenticator.ui.screen.scan.ScanScreen import dev.sanmer.authenticator.ui.screen.scan.ScanViewModel import dev.sanmer.authenticator.ui.screen.setting.SettingScreen -import dev.sanmer.authenticator.ui.screen.setting.SettingViewModel import dev.sanmer.authenticator.ui.screen.trash.TrashScreen -import dev.sanmer.authenticator.ui.screen.trash.TrashViewModel -import org.koin.androidx.compose.koinViewModel import org.koin.androidx.scope.dsl.activityRetainedScope +import org.koin.compose.viewmodel.koinViewModel import org.koin.core.annotation.KoinExperimentalAPI -import org.koin.core.module.dsl.viewModelOf import org.koin.core.parameter.parametersOf import org.koin.dsl.module import org.koin.dsl.navigation3.navigation @OptIn(KoinExperimentalAPI::class) -val Navigation = module { - viewModelOf(::MainViewModel) - viewModelOf(::HomeViewModel) - viewModelOf(::EditViewModel) - viewModelOf(::ScanViewModel) - viewModelOf(::SettingViewModel) - viewModelOf(::TrashViewModel) - viewModelOf(::NtpViewModel) - viewModelOf(::ExportViewModel) +val AppModule = module { + includes(ViewModelsModule) activityRetainedScope { scoped { NavBackStack(Screen.Home) } diff --git a/app/src/main/kotlin/dev/sanmer/authenticator/di/DataStoreModule.kt b/app/src/main/kotlin/dev/sanmer/authenticator/di/DataStoreModule.kt index f4f47d4..9c3dd17 100644 --- a/app/src/main/kotlin/dev/sanmer/authenticator/di/DataStoreModule.kt +++ b/app/src/main/kotlin/dev/sanmer/authenticator/di/DataStoreModule.kt @@ -1,24 +1,23 @@ package dev.sanmer.authenticator.di -import android.content.Context -import androidx.datastore.core.DataStore import androidx.datastore.core.DataStoreFactory import androidx.datastore.core.Serializer import androidx.datastore.dataStoreFile import dev.sanmer.authenticator.datastore.PreferenceSerializer import dev.sanmer.authenticator.datastore.model.Preference -import org.koin.core.module.dsl.bind -import org.koin.core.module.dsl.factoryOf +import org.koin.android.ext.koin.androidContext +import org.koin.dsl.bind import org.koin.dsl.module +import org.koin.plugin.module.dsl.factory -val DataStore = module { - factoryOf(::PreferenceSerializer) { bind>() } +val DataStoreModule = module { + factory() bind Serializer::class - factory> { + factory { DataStoreFactory.create( - serializer = get() + serializer = get>() ) { - get().createDeviceProtectedStorageContext().dataStoreFile("preference.pb") + androidContext().createDeviceProtectedStorageContext().dataStoreFile("preference.pb") } } } \ No newline at end of file diff --git a/app/src/main/kotlin/dev/sanmer/authenticator/di/DatabaseModule.kt b/app/src/main/kotlin/dev/sanmer/authenticator/di/DatabaseModule.kt index e3469b6..81d4c9e 100644 --- a/app/src/main/kotlin/dev/sanmer/authenticator/di/DatabaseModule.kt +++ b/app/src/main/kotlin/dev/sanmer/authenticator/di/DatabaseModule.kt @@ -1,12 +1,12 @@ package dev.sanmer.authenticator.di -import android.content.Context import dev.sanmer.authenticator.database.AppDatabase +import org.koin.android.ext.koin.androidContext import org.koin.dsl.module -val Database = module { +val DatabaseModule = module { single { - AppDatabase.build(get().createDeviceProtectedStorageContext()) + AppDatabase.build(androidContext().createDeviceProtectedStorageContext()) } single { diff --git a/app/src/main/kotlin/dev/sanmer/authenticator/di/RepositoriesModule.kt b/app/src/main/kotlin/dev/sanmer/authenticator/di/RepositoriesModule.kt index 9baf5f2..950c0c3 100644 --- a/app/src/main/kotlin/dev/sanmer/authenticator/di/RepositoriesModule.kt +++ b/app/src/main/kotlin/dev/sanmer/authenticator/di/RepositoriesModule.kt @@ -8,13 +8,14 @@ import dev.sanmer.authenticator.repository.PreferenceRepository import dev.sanmer.authenticator.repository.PreferenceRepositoryImpl import dev.sanmer.authenticator.repository.TimeRepository import dev.sanmer.authenticator.repository.TimeRepositoryImpl -import org.koin.core.module.dsl.bind -import org.koin.core.module.dsl.singleOf +import org.koin.dsl.bind import org.koin.dsl.module +import org.koin.plugin.module.dsl.single -val Repositories = module { - singleOf(::PreferenceRepositoryImpl) { bind() } - singleOf(::DbRepositoryImpl) { bind() } - singleOf(::TimeRepositoryImpl) { bind() } - singleOf(::OtpRepositoryImpl) { bind() } +val RepositoriesModule = module { + includes(DataStoreModule, DatabaseModule) + single() bind PreferenceRepository::class + single() bind DbRepository::class + single() bind TimeRepository::class + single() bind OtpRepository::class } \ No newline at end of file diff --git a/app/src/main/kotlin/dev/sanmer/authenticator/di/ViewModelsModule.kt b/app/src/main/kotlin/dev/sanmer/authenticator/di/ViewModelsModule.kt new file mode 100644 index 0000000..1e04172 --- /dev/null +++ b/app/src/main/kotlin/dev/sanmer/authenticator/di/ViewModelsModule.kt @@ -0,0 +1,24 @@ +package dev.sanmer.authenticator.di + +import dev.sanmer.authenticator.ui.screen.edit.EditViewModel +import dev.sanmer.authenticator.ui.screen.export.ExportViewModel +import dev.sanmer.authenticator.ui.screen.home.HomeViewModel +import dev.sanmer.authenticator.ui.screen.main.MainViewModel +import dev.sanmer.authenticator.ui.screen.ntp.NtpViewModel +import dev.sanmer.authenticator.ui.screen.scan.ScanViewModel +import dev.sanmer.authenticator.ui.screen.setting.SettingViewModel +import dev.sanmer.authenticator.ui.screen.trash.TrashViewModel +import org.koin.dsl.module +import org.koin.plugin.module.dsl.viewModel + +val ViewModelsModule = module { + includes(RepositoriesModule) + viewModel() + viewModel() + viewModel() + viewModel() + viewModel() + viewModel() + viewModel() + viewModel() +} \ No newline at end of file diff --git a/app/src/main/kotlin/dev/sanmer/authenticator/ui/screen/edit/EditViewModel.kt b/app/src/main/kotlin/dev/sanmer/authenticator/ui/screen/edit/EditViewModel.kt index c9a6022..6ff5343 100644 --- a/app/src/main/kotlin/dev/sanmer/authenticator/ui/screen/edit/EditViewModel.kt +++ b/app/src/main/kotlin/dev/sanmer/authenticator/ui/screen/edit/EditViewModel.kt @@ -36,10 +36,11 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch +import org.koin.core.annotation.InjectedParam class EditViewModel( - private val authId: Long, - private val otpUri: Uri, + @InjectedParam private val authId: Long, + @InjectedParam private val otpUri: Uri, private val dbRepository: DbRepository, private val otpRepository: OtpRepository, private val timeRepository: TimeRepository @@ -256,11 +257,14 @@ class EditViewModel( sealed interface BottomSheet { data object None : BottomSheet - data class Preview( + + @JvmInline + value class Preview( val preview: Result>> ) : BottomSheet - data class Qrcode( + @JvmInline + value class Qrcode( val qrcode: Result> ) : BottomSheet } diff --git a/app/src/main/kotlin/dev/sanmer/authenticator/ui/screen/scan/ScanViewModel.kt b/app/src/main/kotlin/dev/sanmer/authenticator/ui/screen/scan/ScanViewModel.kt index b09d4f1..1112203 100644 --- a/app/src/main/kotlin/dev/sanmer/authenticator/ui/screen/scan/ScanViewModel.kt +++ b/app/src/main/kotlin/dev/sanmer/authenticator/ui/screen/scan/ScanViewModel.kt @@ -31,12 +31,13 @@ import dev.sanmer.authenticator.compat.PermissionCompat import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.awaitCancellation import kotlinx.coroutines.launch +import org.koin.core.annotation.InjectedParam import java.nio.ByteBuffer import java.util.concurrent.Executors import java.util.concurrent.TimeUnit class ScanViewModel( - private val callback: Callback + @InjectedParam private val callback: Callback ) : ViewModel() { var isAllowed by mutableStateOf(false) private set diff --git a/build.gradle.kts b/build.gradle.kts index 43879c3..8b328a9 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,11 +2,7 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.androidx.room) apply false - alias(libs.plugins.compose.compiler) apply false + alias(libs.plugins.kotlin.compose) apply false alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.ksp) apply false } - -tasks.register("clean") { - delete(layout.buildDirectory) -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ec7b513..53e77a3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -15,6 +15,7 @@ androidxRoom = "3.0.3" encoding = "2.6.0" googleZxing = "3.5.4" koin = "4.2.2" +koinPlugin = "1.2.1" kotlin = "2.4.20" kotlinxCoroutines = "1.11.0" kotlinxDatetime = "0.8.0" @@ -35,7 +36,6 @@ androidx-camera-camera2 = { module = "androidx.camera:camera-camera2", version.r androidx-camera-compose = { module = "androidx.camera:camera-compose", version.ref = "androidxCamera" } androidx-camera-lifecycle = { module = "androidx.camera:camera-lifecycle", version.ref = "androidxCamera" } androidx-compose-bom = { module = "androidx.compose:compose-bom", version.ref = "androidxComposeBom" } -androidx-compose-material-icons-extended = { module = "androidx.compose.material:material-icons-extended" } androidx-compose-material3 = { module = "androidx.compose.material3:material3" } androidx-compose-ui = { module = "androidx.compose.ui:ui" } androidx-compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling" } @@ -54,9 +54,12 @@ androidx-room-runtime = { module = "androidx.room3:room3-runtime", version.ref = encoding-base32 = { module = "io.matthewnelson.encoding:base32", version.ref = "encoding" } encoding-base64 = { module = "io.matthewnelson.encoding:base64", version.ref = "encoding" } google-zxing = { module = "com.google.zxing:core", version.ref = "googleZxing" } -koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } -koin-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koin" } -koin-compose-navigation3 = { module = "io.insert-koin:koin-compose-navigation3", version.ref = "koin" } +koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koin" } +koin-android = { module = "io.insert-koin:koin-android" } +koin-annotations = { module = "io.insert-koin:koin-annotations" } +koin-compose = { module = "io.insert-koin:koin-compose" } +koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel" } +koin-compose-navigation3 = { module = "io.insert-koin:koin-compose-navigation3" } kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutines" } kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" } kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerialization" } @@ -70,6 +73,7 @@ self-compose = { id = "self.compose", version = "unspecified" } android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" } androidx-room = { id = "androidx.room3", version.ref = "androidxRoom" } -compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } +koin = { id = "io.insert-koin.compiler.plugin", version.ref = "koinPlugin" } +kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }