From 11298766449b795cbb85cb9abb36b3106cd49ae5 Mon Sep 17 00:00:00 2001 From: IntFxZen Date: Sat, 11 Apr 2026 14:30:55 +0300 Subject: [PATCH] chore: setup Koin DI and application bootstrap --- app/build.gradle.kts | 24 +--- app/src/main/AndroidManifest.xml | 1 + .../java/com/itlab/notes/NotesApplication.kt | 16 +++ .../main/java/com/itlab/notes/di/AppModule.kt | 120 ++++++++++++++++++ gradle/libs.versions.toml | 10 +- settings-gradle.lockfile | 4 + 6 files changed, 154 insertions(+), 21 deletions(-) create mode 100644 app/src/main/java/com/itlab/notes/NotesApplication.kt create mode 100644 app/src/main/java/com/itlab/notes/di/AppModule.kt create mode 100644 settings-gradle.lockfile diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 1bbae64..e1ccdb8 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -37,26 +37,6 @@ android { buildFeatures { compose = true } - testOptions { - managedDevices { - localDevices { - create("pixel7api34X86") { - device = "Pixel 7" - apiLevel = 34 - systemImageSource = "aosp-atd" - require64Bit = true - testedAbi = "x86_64" - } - create("pixel7api34Arm64") { - device = "Pixel 7" - apiLevel = 34 - systemImageSource = "aosp-atd" - require64Bit = true - testedAbi = "arm64-v8a" - } - } - } - } } kotlin { @@ -77,6 +57,10 @@ dependencies { implementation(libs.androidx.compose.ui.graphics) implementation(libs.androidx.compose.ui.tooling.preview) implementation(libs.androidx.compose.material3) + implementation(libs.androidx.compose.materialicons.extended) + implementation(libs.koin.android) + implementation(libs.koin.androidx.compose) + testImplementation(libs.junit) androidTestImplementation(libs.androidx.junit) androidTestImplementation(libs.androidx.espresso.core) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3f41043..fd51c78 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools"> { InMemoryNotesRepository() } + single { InMemoryFolderRepository() } + + factory { CreateNoteUseCase(get()) } + factory { CreateFolderUseCase(get()) } + factory { DeleteFolderUseCase(get()) } + factory { DeleteNoteUseCase(get()) } + factory { UpdateNoteUseCase(get()) } + factory { ObserveNotesByFolderUseCase(get()) } + factory { ObserveFoldersUseCase(get()) } +// factory { +// NotesUseCases( +// createFolderUseCase = get(), +// deleteFolderUseCase = get(), +// createNoteUseCase = get(), +// deleteNoteUseCase = get(), +// updateNoteUseCase = get(), +// observeNotesByFolderUseCase = get(), +// observeFoldersUseCase = get(), +// ) +// } +// +// viewModel { +// NotesViewModel( +// useCases = get(), +// ) +// } + } + +private class InMemoryNotesRepository : NotesRepository { + private val notesFlow = MutableStateFlow>(emptyList()) + + override fun observeNotes(): Flow> = notesFlow + + override fun observeNotesByFolder(folderId: String): Flow> = + notesFlow.map { notes -> notes.filter { it.folderId == folderId } } + + override suspend fun getNoteById(id: String): Note? = notesFlow.value.firstOrNull { it.id == id } + + override suspend fun createNote(note: Note): String { + notesFlow.value = notesFlow.value + note + return note.id + } + + override suspend fun updateNote(note: Note) { + notesFlow.value = + notesFlow.value.map { existing -> + if (existing.id == note.id) note else existing + } + } + + override suspend fun deleteNote(id: String) { + notesFlow.value = notesFlow.value.filterNot { it.id == id } + } +} + +private class InMemoryFolderRepository : NoteFolderRepository { + private val foldersFlow = + MutableStateFlow( + listOf( + NoteFolder(id = "all", name = "All Notes"), + NoteFolder(id = "study", name = "My Study"), + NoteFolder(id = "cook", name = "How to Cook"), + NoteFolder(id = "poems", name = "My poems"), + ), + ) + + override fun observeFolders(): Flow> = foldersFlow + + override suspend fun createFolder(folder: NoteFolder): String { + foldersFlow.value = foldersFlow.value + folder + return folder.id + } + + override suspend fun renameFolder( + id: String, + name: String, + ) { + foldersFlow.value = + foldersFlow.value.map { folder -> + if (folder.id == id) folder.copy(name = name) else folder + } + } + + override suspend fun deleteFolder(id: String) { + foldersFlow.value = foldersFlow.value.filterNot { it.id == id } + } + + override suspend fun getFolderById(id: String): NoteFolder? = foldersFlow.value.firstOrNull { it.id == id } + + override suspend fun updateFolder(folder: NoteFolder) { + foldersFlow.value = + foldersFlow.value.map { existing -> + if (existing.id == folder.id) folder else existing + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index edd42bd..7af37ce 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -21,6 +21,8 @@ kotlinxSerializationJson = "1.6.3" robolectric = "4.16.1" coroutinesTest = "1.7.3" coreTesting = "2.2.0" +lifecycleViewmodelKtx = "2.10.0" +koin = "3.5.6" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -37,6 +39,7 @@ androidx-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "u androidx-compose-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-compose-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-compose-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-compose-materialicons-extended = { group = "androidx.compose.material", name = "material-icons-extended" } androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" } material = { group = "com.google.android.material", name = "material", version.ref = "material" } kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinxDatetime" } @@ -48,6 +51,11 @@ timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "tim androidx-compose-material-icons-core = { group = "androidx.compose.material", name = "material-icons-core" } androidx-compose-material-icons-extended = { group = "androidx.compose.material", name = "material-icons-extended" } kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutinesTest" } +androidx-core-testing = { group = "androidx.arch.core", name = "core-testing", version.ref = "coreTesting" } +androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" } +androidx-lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" } +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" } mockk = { group = "io.mockk", name = "mockk", version = "1.13.10" } robolectric = { group = "org.robolectric", name = "robolectric", version = "4.12.1" } androidx-test-core = { group = "androidx.test", name = "core", version = "1.5.0" } @@ -61,4 +69,4 @@ detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlintGradle" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } -ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } \ No newline at end of file +ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } diff --git a/settings-gradle.lockfile b/settings-gradle.lockfile new file mode 100644 index 0000000..709a43f --- /dev/null +++ b/settings-gradle.lockfile @@ -0,0 +1,4 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +empty=incomingCatalogForLibs0