diff --git a/appiOS/Notflix/Koin.swift b/appiOS/Notflix/Koin.swift index 7e82af16..c28ccb75 100644 --- a/appiOS/Notflix/Koin.swift +++ b/appiOS/Notflix/Koin.swift @@ -24,9 +24,7 @@ extension KoinApplication { } extension KoinApplication { - private static let keyPaths: [PartialKeyPath] = [ - \.homeViewModel - + private static let keyPaths: [PartialKeyPath] = [ ] static func inject() -> T { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 44aa5990..72eee98b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -13,21 +13,22 @@ nativeCocoapod = "1.9.0" # Kotlin Multiplatform Version kotlinxCoroutines = "1.7.3" koinCore = "3.5.3" -koinCompose = "1.1.2" +koinCompose = "1.1.5" +koinComposeViewModel = "1.2.0-Beta4" koinAndroid = "3.5.3" koinAndroidxCompose = "3.5.3" +composeMultiplatform = "1.5.11" kotlinxSerializationJson = "1.6.2" kotlinxDateTime = "0.5.0" napier = "2.6.1" ktor = "2.3.7" sqlDelight = "2.0.1" -multiplatformSettings = "1.1.1" -kmpNativeCoroutines = "0.12.1-new-mm" buildKonfig = "0.13.3" kover = "0.6.1" -preCompose = "1.5.10" -imageLoader = "1.7.1" materialWindowSizeClass = "0.3.0" +navigation = "2.7.0-alpha07" +coil = "3.0.0-alpha06" +datastore = "1.1.1" #Android Versions androidxActivity = "1.8.2" @@ -50,7 +51,6 @@ espresso = "3.5.1" test = "1.5.0" archTestCore = "2.2.0" turbine = "0.12.3" -composeMultiplatform = "1.5.11" [plugins] ktLint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktLint" } @@ -64,7 +64,6 @@ android-library = { id = "com.android.library", version.ref = "gradle" } android-application = { id = "com.android.application", version.ref = "gradle" } jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlinX-serialization-plugin = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } -kmp-NativeCoroutines-plugin = { id = "com.rickclephas.kmp.nativecoroutines", version.ref = "kmpNativeCoroutines" } buildKonfig = { id = "com.codingfeline.buildkonfig", version.ref = "buildKonfig" } compose = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" } sqlDelight = { id = "app.cash.sqldelight", version.ref = "sqlDelight" } @@ -77,11 +76,12 @@ firebase-performance-plugin = { id = "com.google.firebase.firebase-perf", versio [libraries] #Kotlin Multiplatform Lib Dependencies -kotlinX-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } +coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" } +coroutines-swing={module="org.jetbrains.kotlinx:kotlinx-coroutines-swing", version.ref="coroutines"} +datastore-preferences = { module = "androidx.datastore:datastore-preferences-core", version.ref = "datastore" } koin-core = { module = "io.insert-koin:koin-core", version.ref = "koinCore" } kotlinX-serializationJson = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } ktor-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } -ktor-serialization = { module = "io.ktor:ktor-client-serialization", version.ref = "ktor" } ktor-contentNegotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" } ktor-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" } ktor-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" } @@ -97,21 +97,21 @@ sqlDelight-native = { module = "app.cash.sqldelight:native-driver", version.ref sqlDelight-JVM = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqlDelight" } napier = { module = "io.github.aakira:napier", version.ref = "napier" } kotlinX-dateTime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDateTime" } -multiplatformSettings-noArg = { module = "com.russhwolf:multiplatform-settings-no-arg", version.ref = "multiplatformSettings" } -multiplatformSettings-coroutines = { module = "com.russhwolf:multiplatform-settings-coroutines", version.ref = "multiplatformSettings" } -multiplatformSettings-test = { module = "com.russhwolf:multiplatform-settings-test", version.ref = "multiplatformSettings" } -imageLoader = { module = "io.github.qdsfdhvh:image-loader", version.ref = "imageLoader" } -preCompose = { module = "moe.tlaster:precompose", version.ref = "preCompose" } -preCompose-viewmodel = { module = "moe.tlaster:precompose-viewmodel", version.ref = "preCompose" } material-windowSizeClass = { module = "dev.chrisbanes.material3:material3-window-size-class-multiplatform", version.ref = "materialWindowSizeClass" } +navigation = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigation" } +coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" } +coil-compose-core = { module = "io.coil-kt.coil3:coil-compose-core", version.ref = "coil" } +coil-ktor = { module = "io.coil-kt.coil3:coil-network-ktor", version.ref = "coil" } +coil-multiplatform = { module = "io.coil-kt.coil3:coil", version.ref = "coil" } #Android Lib Dependencies androidX-core = { module = "androidx.core:core-ktx", version.ref = "androidxCore" } -androidX-activity={module="androidx.activity:activity-compose", version.ref="androidxActivity"} +androidX-activity = { module = "androidx.activity:activity-compose", version.ref = "androidxActivity" } material = { module = "com.google.android.material:material", version.ref = "material" } koin-android = { module = "io.insert-koin:koin-android", version.ref = "koinAndroid" } koin-androidx-compose = { module = "io.insert-koin:koin-androidx-compose", version.ref = "koinAndroidxCompose" } koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koinCompose" } +koin-composeViewModel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koinComposeViewModel" } leakCanary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakCanary" } firebase-BOM = { module = "com.google.firebase:firebase-bom", version.ref = "firebaseBOM" } firebase-analytics = { module = "com.google.firebase:firebase-analytics-ktx" } @@ -133,4 +133,8 @@ test-core = { module = "androidx.test:core-ktx", version.ref = "test" } archTestCore = { module = "androidx.arch.core:core-testing", version.ref = "archTestCore" } test-rules = { module = "androidx.test:rules", version.ref = "test" } test-runner = { module = "androidx.test:runner", version.ref = "test" } -turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } \ No newline at end of file +turbine = { module = "app.cash.turbine:turbine", version.ref = "turbine" } + +[bundles] +ktor = ["ktor-core", "ktor-contentNegotiation", "ktor-json", "ktor-logging"] +coil = ["coil-compose-core", "coil-compose", "coil-ktor", "coil-multiplatform"] \ No newline at end of file diff --git a/notflix.preferences_pb b/notflix.preferences_pb new file mode 100644 index 00000000..a438c60d Binary files /dev/null and b/notflix.preferences_pb differ diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index e56e71c6..b1cf759c 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -27,7 +27,7 @@ kotlin { } iosTarget("ios") {} - jvm() + jvm("desktop") cocoapods { summary = "Some description for the Shared Module" @@ -50,32 +50,28 @@ kotlin { api(compose.components.resources) api(compose.materialIconsExtended) - implementation(libs.kotlinX.coroutines) + implementation(libs.coroutines) - api(libs.ktor.core) - implementation(libs.ktor.contentNegotiation) - implementation(libs.ktor.json) - implementation(libs.ktor.logging) + implementation(libs.bundles.ktor) api(libs.koin.core) implementation(libs.koin.compose) + implementation(libs.koin.composeViewModel) implementation(libs.kotlinX.serializationJson) implementation(libs.kotlinX.dateTime) - implementation(libs.multiplatformSettings.noArg) - implementation(libs.multiplatformSettings.coroutines) - api(libs.napier) - implementation(libs.imageLoader) + implementation(libs.bundles.coil) - api(libs.preCompose) - api(libs.preCompose.viewmodel) + implementation(libs.navigation) implementation(libs.sqlDelight.coroutine) + implementation(libs.datastore.preferences) + // implementation(libs.material.windowSizeClass) } @@ -101,11 +97,13 @@ kotlin { sourceSets["iosTest"].dependencies {} - sourceSets["jvmMain"].dependencies { + sourceSets["desktopMain"].dependencies { + implementation(libs.ktor.java) implementation(libs.sqlDelight.jvm) + implementation(libs.coroutines.swing) } - sourceSets["jvmTest"].dependencies {} + sourceSets["desktopTest"].dependencies {} } } diff --git a/shared/src/androidMain/kotlin/com/vickbt/shared/di/Module.kt b/shared/src/androidMain/kotlin/com/vickbt/shared/di/Module.kt index fceffa8d..ff1fbba6 100644 --- a/shared/src/androidMain/kotlin/com/vickbt/shared/di/Module.kt +++ b/shared/src/androidMain/kotlin/com/vickbt/shared/di/Module.kt @@ -1,11 +1,11 @@ package com.vickbt.shared.di import com.vickbt.shared.utils.DatabaseDriverFactory -import com.vickbt.shared.utils.MultiplatformSettingsWrapper +import com.vickbt.shared.utils.DatastoreFactory import org.koin.core.module.Module import org.koin.dsl.module actual fun platformModule(): Module = module { single { DatabaseDriverFactory(context = get()) } - single { MultiplatformSettingsWrapper().createSettings() } + single { DatastoreFactory(context = get()).createDatastore() } } diff --git a/shared/src/androidMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt b/shared/src/androidMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt deleted file mode 100644 index 9ca77e28..00000000 --- a/shared/src/androidMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt +++ /dev/null @@ -1,33 +0,0 @@ -package com.vickbt.shared.utils - -import com.seiko.imageloader.ImageLoader -import com.seiko.imageloader.cache.memory.maxSizePercent -import com.seiko.imageloader.component.setupDefaultComponents -import com.seiko.imageloader.option.androidContext -import okio.Path.Companion.toOkioPath - -actual object CustomImageLoader { - - actual fun generateImageLoader(): ImageLoader { - val context = ContextUtils.context - - return ImageLoader { - options { - androidContext(context) - } - components { - setupDefaultComponents() - } - interceptor { - memoryCacheConfig { - // Set the max size to 25% of the app's available memory. - maxSizePercent(context, 0.25) - } - diskCacheConfig { - directory(context.cacheDir.toOkioPath()) - maxSizeBytes(512L * 1024 * 1024) // 512MB - } - } - } - } -} diff --git a/shared/src/androidMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.android.kt b/shared/src/androidMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.android.kt new file mode 100644 index 00000000..303e49fb --- /dev/null +++ b/shared/src/androidMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.android.kt @@ -0,0 +1,14 @@ +package com.vickbt.shared.utils + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import com.vickbt.shared.domain.utils.Constants + +actual class DatastoreFactory(private val context: Context) { + actual fun createDatastore(): DataStore { + return initDataStore { + context.filesDir.resolve(Constants.dataStoreFileName).absolutePath + } + } +} diff --git a/shared/src/androidMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt b/shared/src/androidMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt deleted file mode 100644 index 27710d95..00000000 --- a/shared/src/androidMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.vickbt.shared.utils - -import android.content.Context -import com.russhwolf.settings.ObservableSettings -import com.russhwolf.settings.SharedPreferencesSettings - -actual class MultiplatformSettingsWrapper { - private val context = ContextUtils.context - - actual fun createSettings(): ObservableSettings { - val sharedPreferences = - context.getSharedPreferences("notflix_preferences", Context.MODE_PRIVATE) - return SharedPreferencesSettings(delegate = sharedPreferences) - } -} diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/data/datasources/SettingsRepositoryImpl.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/data/datasources/SettingsRepositoryImpl.kt index cda142bb..ee9afc0b 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/data/datasources/SettingsRepositoryImpl.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/data/datasources/SettingsRepositoryImpl.kt @@ -1,25 +1,34 @@ package com.vickbt.shared.data.datasources -import com.russhwolf.settings.ExperimentalSettingsApi -import com.russhwolf.settings.ObservableSettings -import com.russhwolf.settings.coroutines.getIntFlow +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.intPreferencesKey import com.vickbt.shared.domain.repositories.SettingsRepository import com.vickbt.shared.domain.utils.Constants.KEY_IMAGE_QUALITY import com.vickbt.shared.domain.utils.Constants.KEY_THEME import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map -@ExperimentalSettingsApi -class SettingsRepositoryImpl(private val observableSettings: ObservableSettings) : - SettingsRepository { +class SettingsRepositoryImpl( + private val dataStore: DataStore +) : SettingsRepository { - override suspend fun savePreferenceSelection(key: String, selection: Int) = - observableSettings.putInt(key = key, value = selection) + override suspend fun savePreferenceSelection(key: String, selection: Int) { + dataStore.edit { preferences -> + preferences[intPreferencesKey(key)] = selection + } + } override suspend fun getThemePreference(): Flow { - return observableSettings.getIntFlow(key = KEY_THEME, defaultValue = 2) + return dataStore.data.map { preferences -> + preferences[intPreferencesKey(KEY_THEME)] ?: 2 + } } override suspend fun getImageQualityPreference(): Flow { - return observableSettings.getIntFlow(key = KEY_IMAGE_QUALITY, defaultValue = 1) + return dataStore.data.map { preferences -> + preferences[intPreferencesKey(KEY_IMAGE_QUALITY)] ?: 1 + } } } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/di/CommonModule.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/di/CommonModule.kt index dfe1fcf3..bf07b291 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/di/CommonModule.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/di/CommonModule.kt @@ -12,11 +12,11 @@ import com.vickbt.shared.domain.repositories.MoviesRepository import com.vickbt.shared.domain.repositories.SettingsRepository import com.vickbt.shared.domain.utils.Constants.BASE_URL import com.vickbt.shared.domain.utils.Constants.URL_PATH -import com.vickbt.shared.presentation.ui.screens.home.HomeViewModel -import com.vickbt.shared.presentation.ui.screens.main.MainViewModel -import com.vickbt.shared.ui.screens.settings.SettingsViewModel import com.vickbt.shared.ui.screens.details.DetailsViewModel import com.vickbt.shared.ui.screens.favorites.FavoritesViewModel +import com.vickbt.shared.ui.screens.home.HomeViewModel +import com.vickbt.shared.ui.screens.main.MainViewModel +import com.vickbt.shared.ui.screens.settings.SettingsViewModel import io.github.aakira.napier.DebugAntilog import io.github.aakira.napier.Napier import io.ktor.client.HttpClient @@ -30,9 +30,8 @@ import io.ktor.http.URLProtocol import io.ktor.http.path import io.ktor.serialization.kotlinx.json.json import kotlinx.serialization.json.Json +import org.koin.compose.viewmodel.dsl.viewModelOf import org.koin.core.module.Module -import org.koin.core.module.dsl.factoryOf -import org.koin.core.module.dsl.singleOf import org.koin.dsl.module fun commonModule(enableNetworkLogs: Boolean) = module { @@ -85,13 +84,13 @@ fun commonModule(enableNetworkLogs: Boolean) = module { MovieDetailsRepositoryImpl(httpClient = get(), favoriteMovieDao = get()) } single { FavoritesRepositoryImpl(favoriteMovieDao = get()) } - single { SettingsRepositoryImpl(observableSettings = get()) } + single { SettingsRepositoryImpl(dataStore = get()) } - singleOf(::MainViewModel) - singleOf(::HomeViewModel) - factoryOf(::DetailsViewModel) - singleOf(::SettingsViewModel) - singleOf(::FavoritesViewModel) + viewModelOf(::MainViewModel) + viewModelOf(::HomeViewModel) + viewModelOf(::DetailsViewModel) + viewModelOf(::SettingsViewModel) + viewModelOf(::FavoritesViewModel) } expect fun platformModule(): Module diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/di/Koin.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/di/Koin.kt index 44899aa8..b1224854 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/di/Koin.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/di/Koin.kt @@ -1,9 +1,5 @@ package com.vickbt.shared.di -import com.vickbt.shared.presentation.ui.screens.home.HomeViewModel -import com.vickbt.shared.presentation.ui.screens.main.MainViewModel -import com.vickbt.shared.ui.screens.settings.SettingsViewModel -import org.koin.core.Koin import org.koin.core.KoinApplication import org.koin.core.context.startKoin import org.koin.dsl.KoinAppDeclaration @@ -18,12 +14,3 @@ fun initKoin(enableNetworkLogs: Boolean = true, appDeclaration: KoinAppDeclarati // fun initKoin() = initKoin(enableNetworkLogs = false) {} fun KoinApplication.Companion.start(): KoinApplication = initKoin { } - -val Koin.mainViewModel: MainViewModel - get() = get() - -val Koin.homeViewModel: HomeViewModel - get() = get() - -val Koin.settingsViewModel: SettingsViewModel - get() = get() diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/domain/utils/Constants.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/domain/utils/Constants.kt index b8cc8cef..70848c56 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/domain/utils/Constants.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/domain/utils/Constants.kt @@ -16,4 +16,6 @@ object Constants { const val KEY_THEME = "theme" const val KEY_LANGUAGE = "language" const val KEY_IMAGE_QUALITY = "image_quality" + + internal const val dataStoreFileName = "notflix.preferences_pb" } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/BottomNavBar.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/BottomNavBar.kt index f5e45590..b878cb36 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/BottomNavBar.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/BottomNavBar.kt @@ -8,16 +8,16 @@ import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItemDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier -import com.vickbt.shared.presentation.ui.navigation.NavigationItem +import androidx.navigation.NavHostController +import androidx.navigation.compose.currentBackStackEntryAsState +import com.vickbt.shared.ui.navigation.NavigationItem import com.vickbt.shared.ui.theme.Gray -import moe.tlaster.precompose.navigation.Navigator @Composable fun BottomNavBar( modifier: Modifier = Modifier, - navigator: Navigator, + navHostController: NavHostController, bottomNavItems: List ) { NavigationBar( @@ -27,7 +27,7 @@ fun BottomNavBar( bottomNavItems.iterator().forEach { item -> val currentDestination = - navigator.currentEntry.collectAsState(null).value?.route?.route + navHostController.currentBackStackEntryAsState().value?.destination?.route val isSelected = item.route == currentDestination NavigationBarItem( @@ -45,7 +45,7 @@ fun BottomNavBar( ), selected = isSelected, onClick = { - if (item.route != currentDestination) navigator.navigate(route = item.route) + if (item.route != currentDestination) navHostController.navigate(route = item.route) } ) } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/ItemMovieCast.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/ItemMovieCast.kt index a6cd76fa..4f0f4495 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/ItemMovieCast.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/ItemMovieCast.kt @@ -1,6 +1,5 @@ package com.vickbt.shared.ui.components -import androidx.compose.foundation.Image import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.size @@ -17,10 +16,9 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.seiko.imageloader.rememberImagePainter +import coil3.compose.AsyncImage import com.vickbt.shared.domain.models.Actor import com.vickbt.shared.ui.theme.TextSecondary -import com.vickbt.shared.utils.commonImageLoader import com.vickbt.shared.utils.loadImage @Composable @@ -30,16 +28,12 @@ fun ItemMovieCast(modifier: Modifier = Modifier, actor: Actor) { horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(space = 1.dp) ) { - commonImageLoader { - val painter = rememberImagePainter(actor.profilePath?.loadImage() ?: "") - - Image( - modifier = Modifier.size(80.dp).clip(CircleShape), - painter = painter, - contentDescription = "Cast", - contentScale = ContentScale.Crop - ) - } + AsyncImage( + modifier = Modifier.size(80.dp).clip(CircleShape), + model = actor.profilePath?.loadImage(), + contentDescription = "Cast", + contentScale = ContentScale.Crop, + ) Text( modifier = Modifier.width(78.dp), diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardDescription.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardDescription.kt index 376b747b..180e9c1f 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardDescription.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardDescription.kt @@ -1,6 +1,5 @@ package com.vickbt.shared.ui.components -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box @@ -26,9 +25,8 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.seiko.imageloader.rememberImagePainter +import coil3.compose.AsyncImage import com.vickbt.shared.domain.models.MovieDetails -import com.vickbt.shared.utils.commonImageLoader import com.vickbt.shared.utils.loadImage @Composable @@ -45,19 +43,15 @@ fun MovieCardDescription( Card(modifier = modifier.clickable { onItemClick(movie) }) { Box { //region Movie Cover Image - commonImageLoader { - val painter = rememberImagePainter(movie.backdropPath?.loadImage() ?: "") - - Image( - modifier = Modifier - .fillMaxSize() - .align(Alignment.Center), - alignment = Alignment.Center, - contentScale = ContentScale.Crop, - painter = painter, - contentDescription = null - ) - } + AsyncImage( + modifier = Modifier + .fillMaxSize() + .align(Alignment.Center), + model = movie.backdropPath?.loadImage(), + contentDescription = null, + contentScale = ContentScale.Crop, + alignment = Alignment.Center, + ) //endregion //region Fading Edge Box diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardLandscape.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardLandscape.kt index 83ea8aa0..74ef4ad4 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardLandscape.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardLandscape.kt @@ -1,6 +1,5 @@ package com.vickbt.shared.ui.components -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -33,13 +32,12 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.seiko.imageloader.rememberImagePainter +import coil3.compose.AsyncImage import com.vickbt.shared.domain.models.Movie import com.vickbt.shared.ui.components.ratingbar.RatingBar import com.vickbt.shared.ui.components.ratingbar.RatingBarStyle import com.vickbt.shared.ui.components.ratingbar.StepSize import com.vickbt.shared.utils.capitalizeEachWord -import com.vickbt.shared.utils.commonImageLoader import com.vickbt.shared.utils.getRating import com.vickbt.shared.utils.getReleaseDate import com.vickbt.shared.utils.loadImage @@ -59,20 +57,15 @@ fun MovieCardLandscape( shape = RoundedCornerShape(4.dp) ) { Box(modifier = modifier) { - commonImageLoader { - val painter = rememberImagePainter(movie.backdropPath?.loadImage() ?: "") - - //region Movie Cover - Image( - modifier = Modifier - .fillMaxSize() - .align(Alignment.Center), - alignment = Alignment.Center, - contentScale = ContentScale.Crop, - painter = painter, - contentDescription = null - ) - } + AsyncImage( + modifier = Modifier + .fillMaxSize() + .align(Alignment.Center), + model = movie.backdropPath?.loadImage(), + contentDescription = null, + contentScale = ContentScale.Crop, + alignment = Alignment.Center, + ) //endregion //region Fading Edge @@ -140,7 +133,7 @@ fun MovieCardLandscape( Text( modifier = Modifier, - text = movie.releaseDate.getReleaseDate()?.capitalizeEachWord() ?: "", + text = movie.releaseDate.getReleaseDate().capitalizeEachWord(), fontSize = 14.sp, maxLines = 1, style = MaterialTheme.typography.labelSmall, diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardPager.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardPager.kt index 3ab20b4f..dc189fd1 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardPager.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardPager.kt @@ -2,7 +2,6 @@ package com.vickbt.shared.ui.components import androidx.compose.foundation.Canvas import androidx.compose.foundation.ExperimentalFoundationApi -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -33,12 +32,11 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.seiko.imageloader.rememberImagePainter +import coil3.compose.AsyncImage import com.vickbt.shared.domain.models.Movie import com.vickbt.shared.ui.components.ratingbar.RatingBar import com.vickbt.shared.ui.components.ratingbar.RatingBarStyle import com.vickbt.shared.ui.components.ratingbar.StepSize -import com.vickbt.shared.utils.commonImageLoader import com.vickbt.shared.utils.getRating import com.vickbt.shared.utils.loadImage @@ -54,19 +52,15 @@ fun MovieCardPager( Card(modifier = modifier.clickable { onItemClick(movie) }) { Box { //region Movie Cover Image - commonImageLoader { - val painter = rememberImagePainter(movie.backdropPath?.loadImage() ?: "") - - Image( - modifier = Modifier - .fillMaxSize() - .align(Alignment.Center), - alignment = Alignment.Center, - contentScale = ContentScale.Crop, - painter = painter, - contentDescription = null - ) - } + AsyncImage( + modifier = Modifier + .fillMaxSize() + .align(Alignment.Center), + model = movie.backdropPath?.loadImage(), + contentDescription = null, + contentScale = ContentScale.Crop, + alignment = Alignment.Center, + ) //endregion //region Fading Edge Box diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardPortraitCompact.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardPortraitCompact.kt index 9075aab9..59b53ba0 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardPortraitCompact.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/MovieCardPortraitCompact.kt @@ -1,6 +1,5 @@ package com.vickbt.shared.ui.components -import androidx.compose.foundation.Image import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -22,9 +21,8 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.seiko.imageloader.rememberImagePainter +import coil3.compose.AsyncImage import com.vickbt.shared.domain.models.Movie -import com.vickbt.shared.utils.commonImageLoader import com.vickbt.shared.utils.loadImage @Composable @@ -45,20 +43,16 @@ fun MovieCardPortraitCompact( elevation = CardDefaults.cardElevation(8.dp), shape = RoundedCornerShape(4.dp) ) { - commonImageLoader { - val painter = rememberImagePainter(movie.posterPath?.loadImage() ?: "") - - Image( - modifier = Modifier - .fillMaxWidth() - .height(220.dp) - .sizeIn(minHeight = 30.dp), - painter = painter, - alignment = Alignment.Center, - contentScale = ContentScale.Crop, - contentDescription = "Trending movie poster" - ) - } + AsyncImage( + modifier = Modifier + .fillMaxWidth() + .height(220.dp) + .sizeIn(minHeight = 30.dp), + model = movie.posterPath?.loadImage(), + contentDescription = "Trending movie poster", + contentScale = ContentScale.Crop, + alignment = Alignment.Center, + ) } Text( diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/NavRailBar.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/NavRailBar.kt index 03ca7b63..88569096 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/NavRailBar.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/NavRailBar.kt @@ -8,18 +8,18 @@ import androidx.compose.material3.NavigationRailItem import androidx.compose.material3.NavigationRailItemDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.draw.alpha -import com.vickbt.shared.presentation.ui.navigation.NavigationItem +import androidx.navigation.NavHostController +import androidx.navigation.compose.currentBackStackEntryAsState +import com.vickbt.shared.ui.navigation.NavigationItem import com.vickbt.shared.ui.theme.Gray import com.vickbt.shared.ui.theme.PrimaryColor -import moe.tlaster.precompose.navigation.Navigator @Composable fun NavRailBar( modifier: Modifier = Modifier, - navigator: Navigator, + navHostController: NavHostController, navigationItems: List ) { NavigationRail( @@ -37,7 +37,7 @@ fun NavRailBar( navigationItems.forEach { item -> val currentDestination = - navigator.currentEntry.collectAsState(null).value?.route?.route + navHostController.currentBackStackEntryAsState().value?.destination?.route val isSelected = item.route == currentDestination NavigationRailItem( @@ -57,7 +57,7 @@ fun NavRailBar( alwaysShowLabel = false, selected = isSelected, onClick = { - if (item.route != currentDestination) navigator.navigate(route = item.route) + if (item.route != currentDestination) navHostController.navigate(route = item.route) } ) } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/appbars/DetailsAppBar.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/appbars/DetailsAppBar.kt index 53bfe0b1..623e7ef0 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/appbars/DetailsAppBar.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/components/appbars/DetailsAppBar.kt @@ -1,7 +1,6 @@ package com.vickbt.shared.ui.components.appbars import androidx.compose.animation.animateColorAsState -import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box @@ -39,11 +38,10 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.seiko.imageloader.rememberImagePainter +import coil3.compose.AsyncImage import com.vickbt.shared.domain.models.MovieDetails import com.vickbt.shared.ui.components.collapsingToolbar.CollapsingToolbarScaffoldState import com.vickbt.shared.utils.DetailsUiState -import com.vickbt.shared.utils.commonImageLoader import com.vickbt.shared.utils.getMovieDuration import com.vickbt.shared.utils.loadImage @@ -78,19 +76,16 @@ fun DetailsAppBar( .height(350.dp) .graphicsLayer { alpha = scrollProgress } ) { - commonImageLoader { - val painter = rememberImagePainter(movieDetails?.backdropPath?.loadImage() ?: "") - - Image( - modifier = Modifier - .fillMaxSize() - .align(Alignment.Center) - .aspectRatio(scrollProgress.coerceAtLeast(.1f)), - painter = painter, - contentDescription = "Movie poster", - contentScale = ContentScale.Crop - ) - } + AsyncImage( + modifier = Modifier + .fillMaxSize() + .align(Alignment.Center) + .aspectRatio(scrollProgress.coerceAtLeast(.1f)), + model = movieDetails?.backdropPath?.loadImage(), + contentDescription = "Movie poster", + contentScale = ContentScale.Crop, + alignment = Alignment.Center, + ) Box( modifier = Modifier diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/navigation/Navigation.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/navigation/Navigation.kt index 93e6942e..20ea4ae1 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/navigation/Navigation.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/navigation/Navigation.kt @@ -2,42 +2,52 @@ package com.vickbt.shared.ui.navigation import androidx.compose.foundation.layout.PaddingValues import androidx.compose.runtime.Composable -import com.vickbt.shared.presentation.ui.navigation.NavigationItem +import androidx.navigation.NavHostController +import androidx.navigation.NavType +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.navArgument import com.vickbt.shared.ui.screens.details.DetailsScreen import com.vickbt.shared.ui.screens.favorites.FavoritesScreen import com.vickbt.shared.ui.screens.home.HomeScreen import com.vickbt.shared.ui.screens.settings.SettingsScreen import com.vickbt.shared.utils.WindowSize -import moe.tlaster.precompose.navigation.NavHost -import moe.tlaster.precompose.navigation.Navigator -import moe.tlaster.precompose.navigation.path +import io.github.aakira.napier.Napier @Composable fun Navigation( - navigator: Navigator, + navHostController: NavHostController, windowSize: WindowSize, paddingValues: PaddingValues = PaddingValues() ) { - NavHost(navigator = navigator, initialRoute = NavigationItem.Home.route) { - scene(NavigationItem.Home.route) { + NavHost(navController = navHostController, startDestination = NavigationItem.Home.route) { + composable(route = NavigationItem.Home.route) { HomeScreen( - navigator = navigator, + navigator = navHostController, windowSize = windowSize, paddingValues = paddingValues ) } - scene(NavigationItem.Favorites.route) { - FavoritesScreen(navigator = navigator) + composable(route = NavigationItem.Favorites.route) { + FavoritesScreen(navigator = navHostController) } - scene(NavigationItem.Settings.route) { + composable(route = NavigationItem.Settings.route) { SettingsScreen() } - scene(NavigationItem.Details.route) { backStackEntry -> - backStackEntry.path("id")?.let { movieId -> - DetailsScreen(navigator = navigator, windowSize = windowSize, movieId = movieId) + composable( + route = NavigationItem.Details.route, + arguments = listOf(navArgument("movieId") { type = NavType.IntType }) + ) { backStackEntry -> + backStackEntry.arguments?.getInt("movieId")?.let { movieId -> + Napier.e("Movie ID: $movieId") + DetailsScreen( + navigator = navHostController, + windowSize = windowSize, + movieId = movieId + ) } } } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/navigation/NavigationItem.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/navigation/NavigationItem.kt index e46d85f3..9f136136 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/navigation/NavigationItem.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/navigation/NavigationItem.kt @@ -1,4 +1,4 @@ -package com.vickbt.shared.presentation.ui.navigation +package com.vickbt.shared.ui.navigation import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.Favorite @@ -15,5 +15,5 @@ sealed class NavigationItem( object Home : NavigationItem("/home", "Home", Icons.Rounded.Home) object Favorites : NavigationItem("/favorites", "Favorites", Icons.Rounded.Favorite) object Settings : NavigationItem("/settings", "Settings", Icons.Rounded.Settings) - object Details : NavigationItem("/details/{id:[0-9]+}", "Details", null) + object Details : NavigationItem("/details/{movieId}", "Details", null) } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/details/DetailsScreen.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/details/DetailsScreen.kt index b38c2a34..9fcdcd98 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/details/DetailsScreen.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/details/DetailsScreen.kt @@ -23,6 +23,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.navigation.NavHostController import com.vickbt.shared.ui.components.ItemMovieCast import com.vickbt.shared.ui.components.MovieCardPortrait import com.vickbt.shared.ui.components.MovieRatingSection @@ -34,14 +35,13 @@ import com.vickbt.shared.utils.WindowSize import com.vickbt.shared.utils.getPopularity import com.vickbt.shared.utils.getRating import io.github.aakira.napier.Napier -import moe.tlaster.precompose.navigation.Navigator -import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel @Composable fun DetailsScreen( - navigator: Navigator, + navigator: NavHostController, windowSize: WindowSize = WindowSize.COMPACT, - viewModel: DetailsViewModel = koinInject(), + viewModel: DetailsViewModel = koinViewModel(), movieId: Int ) { LaunchedEffect(key1 = Unit) { @@ -77,7 +77,7 @@ fun DetailsScreen( modifier = Modifier.fillMaxWidth(), collapsingScrollState = collapsingScrollState, movieDetailsState = movieDetailsState, - onNavigationIconClick = { navigator.goBack() }, + onNavigationIconClick = { navigator.navigateUp() }, onShareIconClick = {}, onFavoriteIconClick = { movieDetails, isFavorite -> if (isFavorite == true) { diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/details/DetailsViewModel.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/details/DetailsViewModel.kt index 34fbbfe4..0bba50df 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/details/DetailsViewModel.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/details/DetailsViewModel.kt @@ -1,5 +1,7 @@ package com.vickbt.shared.ui.screens.details +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.vickbt.shared.domain.models.MovieDetails import com.vickbt.shared.domain.repositories.MovieDetailsRepository import com.vickbt.shared.utils.DetailsUiState @@ -8,23 +10,18 @@ import com.vickbt.shared.utils.onFailure import com.vickbt.shared.utils.onSuccess import io.github.aakira.napier.Napier import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.koin.core.component.KoinComponent class DetailsViewModel( private val movieDetailsRepository: MovieDetailsRepository -) : KoinComponent { +) : ViewModel() { private val _movieDetailsState = MutableStateFlow(DetailsUiState()) val movieDetailsState = _movieDetailsState.asStateFlow() - private val viewModelScope = CoroutineScope(Dispatchers.Default) - private val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception -> _movieDetailsState.update { it.copy(isLoading = false, error = exception.message) } } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/favorites/FavoritesScreen.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/favorites/FavoritesScreen.kt index 75bca67a..b67a72e6 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/favorites/FavoritesScreen.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/favorites/FavoritesScreen.kt @@ -12,13 +12,16 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.vickbt.shared.ui.components.MovieCardDescription import com.vickbt.shared.ui.components.appbars.AppBar -import moe.tlaster.precompose.navigation.Navigator -import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel @Composable -fun FavoritesScreen(navigator: Navigator, viewModel: FavoritesViewModel = koinInject()) { +fun FavoritesScreen( + navigator: NavHostController, + viewModel: FavoritesViewModel = koinViewModel() +) { val favoriteMovies = viewModel.favoriteMoviesState.collectAsState().value Scaffold( diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/favorites/FavoritesViewModel.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/favorites/FavoritesViewModel.kt index 7708647c..d4d749a5 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/favorites/FavoritesViewModel.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/favorites/FavoritesViewModel.kt @@ -1,25 +1,22 @@ package com.vickbt.shared.ui.screens.favorites +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.vickbt.shared.domain.repositories.FavoritesRepository import com.vickbt.shared.utils.FavouritesUiState import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.koin.core.component.KoinComponent class FavoritesViewModel( private val favoritesRepository: FavoritesRepository -) : KoinComponent { +) : ViewModel() { private val _favoriteMoviesState = MutableStateFlow(FavouritesUiState()) val favoriteMoviesState = _favoriteMoviesState.asStateFlow() - private val viewModelScope = CoroutineScope(Dispatchers.Default) - private val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception -> _favoriteMoviesState.update { it.copy(isLoading = false, error = exception.message) } } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/home/HomeScreen.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/home/HomeScreen.kt index a6cb8de3..6d2a7446 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/home/HomeScreen.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/home/HomeScreen.kt @@ -32,7 +32,6 @@ import androidx.compose.material3.SearchBar import androidx.compose.material3.SearchBarDefaults import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -45,7 +44,7 @@ import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import com.vickbt.shared.presentation.ui.screens.home.HomeViewModel +import androidx.navigation.NavHostController import com.vickbt.shared.ui.components.MovieCardLandscape import com.vickbt.shared.ui.components.MovieCardPager import com.vickbt.shared.ui.components.MovieCardPagerIndicator @@ -54,26 +53,18 @@ import com.vickbt.shared.ui.components.SectionSeparator import com.vickbt.shared.ui.screens.search.SearchScreen import com.vickbt.shared.ui.theme.DarkPrimaryColor import com.vickbt.shared.utils.WindowSize -import moe.tlaster.precompose.navigation.Navigator -import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel @OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class) @Composable fun HomeScreen( - navigator: Navigator, + navigator: NavHostController, windowSize: WindowSize = WindowSize.COMPACT, - viewModel: HomeViewModel = koinInject(), + viewModel: HomeViewModel = koinViewModel(), paddingValues: PaddingValues ) { val scrollState = rememberScrollState() - LaunchedEffect(key1 = viewModel) { - viewModel.fetchNowPlayingMovies() - viewModel.fetchTrendingMovies() - viewModel.fetchUpcomingMovies() - viewModel.fetchPopularMovies() - } - val homeUiState = viewModel.homeUiState.collectAsState().value val searchUiState = viewModel.searchUiState.collectAsState().value diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/home/HomeViewModel.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/home/HomeViewModel.kt index d7793efe..fc8a19ee 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/home/HomeViewModel.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/home/HomeViewModel.kt @@ -1,5 +1,7 @@ -package com.vickbt.shared.presentation.ui.screens.home +package com.vickbt.shared.ui.screens.home +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.vickbt.shared.domain.repositories.MoviesRepository import com.vickbt.shared.utils.HomeUiState import com.vickbt.shared.utils.SearchUiState @@ -7,17 +9,13 @@ import com.vickbt.shared.utils.isLoading import com.vickbt.shared.utils.onFailure import com.vickbt.shared.utils.onSuccess import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.koin.core.component.KoinComponent -class HomeViewModel constructor(private val moviesRepository: MoviesRepository) : KoinComponent { +class HomeViewModel(private val moviesRepository: MoviesRepository) : ViewModel() { private val _homeUiState = MutableStateFlow(HomeUiState(isLoading = true)) val homeUiState = _homeUiState.asStateFlow() @@ -28,12 +26,17 @@ class HomeViewModel constructor(private val moviesRepository: MoviesRepository) private val _searchQuery = MutableStateFlow("") val searchQuery = _searchQuery.asStateFlow() - private val viewModelScope = CoroutineScope(Dispatchers.IO) - private val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception -> _homeUiState.update { it.copy(isLoading = false, error = exception.message) } } + init { + fetchNowPlayingMovies() + fetchTrendingMovies() + fetchUpcomingMovies() + fetchPopularMovies() + } + fun fetchNowPlayingMovies() = viewModelScope.launch(coroutineExceptionHandler) { moviesRepository.fetchNowPlayingMovies().collectLatest { moviesResult -> moviesResult.isLoading { isLoading -> diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/main/MainScreen.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/main/MainScreen.kt index a1ed91f2..31ddfdde 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/main/MainScreen.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/main/MainScreen.kt @@ -11,64 +11,64 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier -import com.vickbt.shared.presentation.ui.navigation.NavigationItem -import com.vickbt.shared.presentation.ui.screens.main.MainViewModel +import androidx.navigation.compose.currentBackStackEntryAsState +import androidx.navigation.compose.rememberNavController import com.vickbt.shared.ui.components.BottomNavBar import com.vickbt.shared.ui.components.NavRailBar import com.vickbt.shared.ui.navigation.Navigation +import com.vickbt.shared.ui.navigation.NavigationItem import com.vickbt.shared.ui.theme.NotflixTheme import com.vickbt.shared.utils.WindowSize -import moe.tlaster.precompose.PreComposeApp -import moe.tlaster.precompose.navigation.rememberNavigator -import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel @Composable -fun MainScreen(viewModel: MainViewModel = koinInject()) { - PreComposeApp { - val appUiState = viewModel.mainUiState.collectAsState().value - var windowSize by remember { mutableStateOf(WindowSize.COMPACT) } +fun MainScreen(viewModel: MainViewModel = koinViewModel()) { + val appUiState = viewModel.mainUiState.collectAsState().value + var windowSize by remember { mutableStateOf(WindowSize.COMPACT) } - val isDarkTheme = appUiState.selectedTheme != 0 + val isDarkTheme = appUiState.selectedTheme != 0 - NotflixTheme(darkTheme = isDarkTheme) { - val navigator = rememberNavigator() + NotflixTheme(darkTheme = isDarkTheme) { + val navHostController = rememberNavController() - val topLevelDestinations = listOf( - NavigationItem.Home, - NavigationItem.Favorites, - NavigationItem.Settings - ) + val topLevelDestinations = listOf( + NavigationItem.Home, + NavigationItem.Favorites, + NavigationItem.Settings + ) - val isTopLevelDestination = - navigator.currentEntry.collectAsState(null).value?.route?.route in topLevelDestinations.map { it.route } + val isTopLevelDestination = + navHostController.currentBackStackEntryAsState().value?.destination?.route in topLevelDestinations.map { it.route } - val showNavigationRail = windowSize != WindowSize.COMPACT + val showNavigationRail = windowSize != WindowSize.COMPACT - Scaffold( - bottomBar = { - if (isTopLevelDestination && !showNavigationRail) { - BottomNavBar(bottomNavItems = topLevelDestinations, navigator = navigator) - } + Scaffold( + bottomBar = { + if (isTopLevelDestination && !showNavigationRail) { + BottomNavBar( + bottomNavItems = topLevelDestinations, + navHostController = navHostController + ) } - ) { paddingValues -> - - BoxWithConstraints(modifier = Modifier.fillMaxSize()) { - windowSize = WindowSize.basedOnWidth(this.minWidth) + } + ) { paddingValues -> - Row(modifier = Modifier.fillMaxSize()) { - if (isTopLevelDestination && showNavigationRail) { - NavRailBar( - navigationItems = topLevelDestinations, - navigator = navigator - ) - } + BoxWithConstraints(modifier = Modifier.fillMaxSize()) { + windowSize = WindowSize.basedOnWidth(this.minWidth) - Navigation( - navigator = navigator, - windowSize = windowSize, - paddingValues = paddingValues + Row(modifier = Modifier.fillMaxSize()) { + if (isTopLevelDestination && showNavigationRail) { + NavRailBar( + navigationItems = topLevelDestinations, + navHostController = navHostController ) } + + Navigation( + navHostController = navHostController, + windowSize = windowSize, + paddingValues = paddingValues + ) } } } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/main/MainViewModel.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/main/MainViewModel.kt index 3ef9e1ac..d956b212 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/main/MainViewModel.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/main/MainViewModel.kt @@ -1,26 +1,22 @@ -package com.vickbt.shared.presentation.ui.screens.main +package com.vickbt.shared.ui.screens.main +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.vickbt.shared.domain.repositories.SettingsRepository import com.vickbt.shared.utils.MainUiState import io.github.aakira.napier.Napier import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.koin.core.component.KoinComponent -class MainViewModel(private val settingsRepository: SettingsRepository) : KoinComponent { +class MainViewModel(private val settingsRepository: SettingsRepository) : ViewModel() { private val _mainUiState = MutableStateFlow(MainUiState()) val mainUiState = _mainUiState.asStateFlow() - private val viewModelScope = CoroutineScope(Dispatchers.IO) - private val coroutineExceptionHandler = CoroutineExceptionHandler { _, _ -> } init { diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/search/SearchScreen.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/search/SearchScreen.kt index 1a85d8c2..dfeb5e7d 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/search/SearchScreen.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/search/SearchScreen.kt @@ -17,14 +17,14 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController import com.vickbt.shared.ui.components.MovieCardPortrait import com.vickbt.shared.utils.SearchUiState import com.vickbt.shared.utils.WindowSize -import moe.tlaster.precompose.navigation.Navigator @Composable fun SearchScreen( - navigator: Navigator, + navigator: NavHostController, searchUiState: SearchUiState, windowSize: WindowSize = WindowSize.COMPACT ) { diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/settings/SettingsScreen.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/settings/SettingsScreen.kt index c6378d38..9e272f78 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/settings/SettingsScreen.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/settings/SettingsScreen.kt @@ -18,13 +18,13 @@ import com.vickbt.shared.ui.components.appbars.AppBar import com.vickbt.shared.ui.components.preferences.DialogPreferenceSelection import com.vickbt.shared.ui.components.preferences.PreferencesGroup import com.vickbt.shared.ui.components.preferences.TextPreference -import org.koin.compose.koinInject +import org.koin.compose.viewmodel.koinViewModel private val themeLabels = listOf("Light", "Dark", "System Default") private val imageQualityLabels = listOf("High Quality", "Low Quality") @Composable -fun SettingsScreen(viewModel: SettingsViewModel = koinInject()) { +fun SettingsScreen(viewModel: SettingsViewModel = koinViewModel()) { val settingsUiState = viewModel.settingsUiState.collectAsState().value val showThemeDialog = remember { mutableStateOf(false) } @@ -47,10 +47,10 @@ fun SettingsScreen(viewModel: SettingsViewModel = koinInject()) { if (showThemeDialog.value) { ChangeTheme( - viewModel = viewModel, - showDialog = showThemeDialog, - currentValue = themeLabel - ) + viewModel = viewModel, + showDialog = showThemeDialog, + currentValue = themeLabel + ) } TextPreference( @@ -62,10 +62,10 @@ fun SettingsScreen(viewModel: SettingsViewModel = koinInject()) { if (showImageQualityDialog.value) { ChangeImageQuality( - viewModel = viewModel, - showDialog = showImageQualityDialog, - currentValue = imageQualityLabel - ) + viewModel = viewModel, + showDialog = showImageQualityDialog, + currentValue = imageQualityLabel + ) } } } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/settings/SettingsViewModel.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/settings/SettingsViewModel.kt index 765daa0e..7b2218d7 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/settings/SettingsViewModel.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/screens/settings/SettingsViewModel.kt @@ -1,25 +1,21 @@ package com.vickbt.shared.ui.screens.settings +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.vickbt.shared.domain.repositories.SettingsRepository import com.vickbt.shared.utils.SettingsUiState import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.IO import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch -import org.koin.core.component.KoinComponent class SettingsViewModel(private val settingsRepository: SettingsRepository) : - KoinComponent { + ViewModel() { private val _settingsUiState = MutableStateFlow(SettingsUiState(isLoading = true)) val settingsUiState = _settingsUiState.asStateFlow() - private val viewModelScope = CoroutineScope(Dispatchers.IO) - private val coroutineExceptionHandler = CoroutineExceptionHandler { _, exception -> _settingsUiState.update { it.copy(isLoading = false, error = exception.message) } } diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/theme/Theme.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/theme/Theme.kt index df9a733d..ac1a0728 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/ui/theme/Theme.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/ui/theme/Theme.kt @@ -5,6 +5,8 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme import androidx.compose.runtime.Composable +import coil3.compose.setSingletonImageLoaderFactory +import com.vickbt.shared.utils.getAsyncImageLoader private val DarkColorPalette = darkColorScheme( primary = DarkPrimaryColor, @@ -29,6 +31,10 @@ fun NotflixTheme( ) { val colorScheme = if (darkTheme) DarkColorPalette else LightColorPalette + setSingletonImageLoaderFactory { context -> + context.getAsyncImageLoader() + } + MaterialTheme( colorScheme = colorScheme, // typography = Typography, diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt deleted file mode 100644 index a7c111be..00000000 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.vickbt.shared.utils - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.remember -import com.seiko.imageloader.ImageLoader -import com.seiko.imageloader.LocalImageLoader - -expect object CustomImageLoader { - fun generateImageLoader(): ImageLoader -} - -@Composable -fun commonImageLoader(content: @Composable () -> Unit) { - CompositionLocalProvider( - LocalImageLoader provides remember { CustomImageLoader.generateImageLoader() } - ) { - content() - } -} diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.kt new file mode 100644 index 00000000..dfa2ffb9 --- /dev/null +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.kt @@ -0,0 +1,15 @@ +package com.vickbt.shared.utils + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.PreferenceDataStoreFactory +import androidx.datastore.preferences.core.Preferences +import okio.Path.Companion.toPath + +expect class DatastoreFactory { + fun createDatastore(): DataStore +} + +fun initDataStore(producePath: () -> String): DataStore = + PreferenceDataStoreFactory.createWithPath( + produceFile = { producePath().toPath() } + ) diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/utils/Extensions.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/utils/Extensions.kt index b94be38f..a474bcdd 100644 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/utils/Extensions.kt +++ b/shared/src/commonMain/kotlin/com/vickbt/shared/utils/Extensions.kt @@ -2,6 +2,12 @@ package com.vickbt.shared.utils import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState +import coil3.ImageLoader +import coil3.PlatformContext +import coil3.memory.MemoryCache +import coil3.request.CachePolicy +import coil3.request.crossfade +import coil3.util.DebugLogger import com.vickbt.shared.ui.screens.settings.SettingsViewModel import org.koin.compose.koinInject @@ -20,3 +26,12 @@ fun String.loadImage(): String { return "https://image.tmdb.org/t/p/$quality/$this" } + +fun PlatformContext.getAsyncImageLoader() = ImageLoader.Builder(this) + .crossfade(true) + .memoryCachePolicy(CachePolicy.ENABLED) + .memoryCache { + MemoryCache.Builder().maxSizePercent(this, 0.3).strongReferencesEnabled(true).build() + } + .logger(DebugLogger()) + .build() diff --git a/shared/src/commonMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt b/shared/src/commonMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt deleted file mode 100644 index 976e13a3..00000000 --- a/shared/src/commonMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.vickbt.shared.utils - -import com.russhwolf.settings.ObservableSettings - -expect class MultiplatformSettingsWrapper { - fun createSettings(): ObservableSettings -} diff --git a/shared/src/jvmMain/kotlin/com/vickbt/shared/di/Module.kt b/shared/src/desktopMain/kotlin/com/vickbt/shared/di/Module.kt similarity index 65% rename from shared/src/jvmMain/kotlin/com/vickbt/shared/di/Module.kt rename to shared/src/desktopMain/kotlin/com/vickbt/shared/di/Module.kt index b8c4b58f..9a6c3113 100644 --- a/shared/src/jvmMain/kotlin/com/vickbt/shared/di/Module.kt +++ b/shared/src/desktopMain/kotlin/com/vickbt/shared/di/Module.kt @@ -1,11 +1,11 @@ package com.vickbt.shared.di import com.vickbt.shared.utils.DatabaseDriverFactory -import com.vickbt.shared.utils.MultiplatformSettingsWrapper +import com.vickbt.shared.utils.DatastoreFactory import org.koin.core.module.Module import org.koin.dsl.module actual fun platformModule(): Module = module { single { DatabaseDriverFactory() } - single { MultiplatformSettingsWrapper().createSettings() } + single { DatastoreFactory().createDatastore() } } diff --git a/shared/src/jvmMain/kotlin/com/vickbt/shared/utils/DatabaseDriverFactory.kt b/shared/src/desktopMain/kotlin/com/vickbt/shared/utils/DatabaseDriverFactory.kt similarity index 100% rename from shared/src/jvmMain/kotlin/com/vickbt/shared/utils/DatabaseDriverFactory.kt rename to shared/src/desktopMain/kotlin/com/vickbt/shared/utils/DatabaseDriverFactory.kt diff --git a/shared/src/desktopMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.desktop.kt b/shared/src/desktopMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.desktop.kt new file mode 100644 index 00000000..d3420a93 --- /dev/null +++ b/shared/src/desktopMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.desktop.kt @@ -0,0 +1,13 @@ +package com.vickbt.shared.utils + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import com.vickbt.shared.domain.utils.Constants + +actual class DatastoreFactory { + actual fun createDatastore(): DataStore { + return initDataStore { + Constants.dataStoreFileName + } + } +} diff --git a/shared/src/iosMain/kotlin/com/vickbt/shared/di/Module.kt b/shared/src/iosMain/kotlin/com/vickbt/shared/di/Module.kt index b8c4b58f..9a6c3113 100644 --- a/shared/src/iosMain/kotlin/com/vickbt/shared/di/Module.kt +++ b/shared/src/iosMain/kotlin/com/vickbt/shared/di/Module.kt @@ -1,11 +1,11 @@ package com.vickbt.shared.di import com.vickbt.shared.utils.DatabaseDriverFactory -import com.vickbt.shared.utils.MultiplatformSettingsWrapper +import com.vickbt.shared.utils.DatastoreFactory import org.koin.core.module.Module import org.koin.dsl.module actual fun platformModule(): Module = module { single { DatabaseDriverFactory() } - single { MultiplatformSettingsWrapper().createSettings() } + single { DatastoreFactory().createDatastore() } } diff --git a/shared/src/iosMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt b/shared/src/iosMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt deleted file mode 100644 index 7614e581..00000000 --- a/shared/src/iosMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt +++ /dev/null @@ -1,35 +0,0 @@ -package com.vickbt.shared.utils - -import com.seiko.imageloader.ImageLoader -import com.seiko.imageloader.component.setupDefaultComponents -import okio.Path.Companion.toPath -import platform.Foundation.NSCachesDirectory -import platform.Foundation.NSSearchPathForDirectoriesInDomains -import platform.Foundation.NSUserDomainMask - -actual object CustomImageLoader { - actual fun generateImageLoader(): ImageLoader { - return ImageLoader { - components { - setupDefaultComponents() - } - interceptor { - memoryCacheConfig { - maxSizeBytes(32 * 1024 * 1024) // 32MB - } - diskCacheConfig { - directory(getCacheDir().toPath().resolve("image_cache")) - maxSizeBytes(512L * 1024 * 1024) // 512MB - } - } - } - } - - private fun getCacheDir(): String { - return NSSearchPathForDirectoriesInDomains( - NSCachesDirectory, - NSUserDomainMask, - true, - ).first() as String - } -} diff --git a/shared/src/iosMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.ios.kt b/shared/src/iosMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.ios.kt new file mode 100644 index 00000000..c5d8535f --- /dev/null +++ b/shared/src/iosMain/kotlin/com/vickbt/shared/utils/DatastoreFactory.ios.kt @@ -0,0 +1,26 @@ +@file:OptIn(ExperimentalForeignApi::class) + +package com.vickbt.shared.utils + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import com.vickbt.shared.domain.utils.Constants +import kotlinx.cinterop.ExperimentalForeignApi +import platform.Foundation.NSDocumentDirectory +import platform.Foundation.NSFileManager +import platform.Foundation.NSUserDomainMask + +actual class DatastoreFactory { + actual fun createDatastore(): DataStore { + return initDataStore { + val directory = NSFileManager.defaultManager.URLForDirectory( + directory = NSDocumentDirectory, + inDomain = NSUserDomainMask, + appropriateForURL = null, + create = false, + error = null + ) + requireNotNull(directory).path() + "/${Constants.dataStoreFileName}" + } + } +} diff --git a/shared/src/iosMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt b/shared/src/iosMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt deleted file mode 100644 index e1055451..00000000 --- a/shared/src/iosMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.vickbt.shared.utils - -import com.russhwolf.settings.NSUserDefaultsSettings -import com.russhwolf.settings.ObservableSettings -import platform.Foundation.NSUserDefaults - -actual class MultiplatformSettingsWrapper { - actual fun createSettings(): ObservableSettings { - val nsUserDefault = NSUserDefaults.standardUserDefaults - return NSUserDefaultsSettings(delegate = nsUserDefault) - } -} diff --git a/shared/src/jvmMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt b/shared/src/jvmMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt deleted file mode 100644 index 42e8189d..00000000 --- a/shared/src/jvmMain/kotlin/com/vickbt/shared/utils/CustomImageLoader.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.vickbt.shared.utils - -import com.seiko.imageloader.ImageLoader -import com.seiko.imageloader.component.setupDefaultComponents -import okio.Path.Companion.toOkioPath -import java.io.File - -actual object CustomImageLoader { - - actual fun generateImageLoader(): ImageLoader { - return ImageLoader { - components { - setupDefaultComponents() - } - interceptor { - memoryCacheConfig { - maxSizeBytes(32 * 1024 * 1024) // 32MB - } - diskCacheConfig { - directory(getCacheDir().toOkioPath().resolve("image_cache")) - maxSizeBytes(512L * 1024 * 1024) // 512MB - } - } - } - } - - private fun getCacheDir() = when (currentOperatingSystem) { - OperatingSystem.Windows -> File(System.getenv("AppData"), "$applicationName/cache") - OperatingSystem.Linux -> File(System.getProperty("user.home"), ".cache/$applicationName") - OperatingSystem.MacOS -> File( - System.getProperty("user.home"), - "Library/Caches/$applicationName" - ) - - else -> throw IllegalStateException("Unsupported operating system") - } - - private enum class OperatingSystem { - Windows, Linux, MacOS, Unknown - } - - private val currentOperatingSystem: OperatingSystem - get() { - val operSys = System.getProperty("os.name").lowercase() - return if (operSys.contains("win")) { - OperatingSystem.Windows - } else if (operSys.contains("nix") || operSys.contains("nux") || - operSys.contains("aix") - ) { - OperatingSystem.Linux - } else if (operSys.contains("mac")) { - OperatingSystem.MacOS - } else { - OperatingSystem.Unknown - } - } - - private val applicationName = "Notflix" -} diff --git a/shared/src/jvmMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt b/shared/src/jvmMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt deleted file mode 100644 index 3343f98d..00000000 --- a/shared/src/jvmMain/kotlin/com/vickbt/shared/utils/MultiplatformSettingsWrapper.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.vickbt.shared.utils - -import com.russhwolf.settings.ObservableSettings -import com.russhwolf.settings.PreferencesSettings -import java.util.prefs.Preferences - -actual class MultiplatformSettingsWrapper { - actual fun createSettings(): ObservableSettings { - val preferences: Preferences = Preferences.userRoot() - return PreferencesSettings(delegate = preferences) - } -}