From 54f5686d048f21fce939ed52af0abaff34a9bfc2 Mon Sep 17 00:00:00 2001 From: AbdallahMehiz Date: Sat, 20 Jul 2024 20:51:14 +0100 Subject: [PATCH] feat: datastore preferences --- .editorconfig | 0 .github/workflows/build.yml | 0 .gitignore | 0 api/.gitignore | 0 api/build.gradle.kts | 0 .../mehiz/abdallah/progres/api/ProgresApi.kt | 0 build.gradle.kts | 0 composeApp/build.gradle.kts | 3 + .../src/androidMain/AndroidManifest.xml | 0 .../androidMain/kotlin/Platform.android.kt | 0 .../mehiz/abdallah/progres/MainActivity.kt | 7 +- .../drawable-v24/ic_launcher_foreground.xml | 0 .../res/drawable/ic_launcher_background.xml | 0 .../res/mipmap-anydpi-v26/ic_launcher.xml | 0 .../mipmap-anydpi-v26/ic_launcher_round.xml | 0 .../res/mipmap-hdpi/ic_launcher.png | Bin .../res/mipmap-hdpi/ic_launcher_round.png | Bin .../res/mipmap-mdpi/ic_launcher.png | Bin .../res/mipmap-mdpi/ic_launcher_round.png | Bin .../res/mipmap-xhdpi/ic_launcher.png | Bin .../res/mipmap-xhdpi/ic_launcher_round.png | Bin .../res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin .../res/mipmap-xxxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin .../src/androidMain/res/values/strings.xml | 0 .../drawable/compose-multiplatform.xml | 0 composeApp/src/commonMain/kotlin/App.kt | 0 composeApp/src/commonMain/kotlin/Greeting.kt | 0 composeApp/src/commonMain/kotlin/Platform.kt | 0 .../commonMain/kotlin/di/PreferencesModule.kt | 18 ++ .../src/commonMain/kotlin/di/initKodein.kt | 14 ++ .../kotlin/preferences/BasePreferences.kt | 7 + .../kotlin/preferences/Datastore.kt | 12 ++ .../preference/DataStorePreference.kt | 201 ++++++++++++++++++ .../preference/DataStorePreferenceStore.kt | 44 ++++ .../preferences/preference/Preference.kt | 34 +++ .../preferences/preference/PreferenceStore.kt | 17 ++ .../src/iosMain/kotlin/MainViewController.kt | 30 ++- composeApp/src/iosMain/kotlin/Platform.ios.kt | 0 data/.gitignore | 0 data/build.gradle.kts | 0 .../abdallah/progres/data/ProgresDatabase.kt | 0 domain/.gitignore | 0 domain/build.gradle.kts | 0 gradle.properties | 0 gradle/libs.versions.toml | 10 + gradle/wrapper/gradle-wrapper.jar | Bin gradle/wrapper/gradle-wrapper.properties | 0 gradlew | 0 gradlew.bat | 0 iosApp/Configuration/Config.xcconfig | 0 iosApp/iosApp.xcodeproj/project.pbxproj | 0 .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/app-icon-1024.png | Bin iosApp/iosApp/Assets.xcassets/Contents.json | 0 iosApp/iosApp/ContentView.swift | 0 iosApp/iosApp/Info.plist | 0 .../Preview Assets.xcassets/Contents.json | 0 iosApp/iosApp/iOSApp.swift | 0 settings.gradle.kts | 0 62 files changed, 395 insertions(+), 2 deletions(-) mode change 100644 => 100755 .editorconfig mode change 100644 => 100755 .github/workflows/build.yml mode change 100644 => 100755 .gitignore mode change 100644 => 100755 api/.gitignore mode change 100644 => 100755 api/build.gradle.kts mode change 100644 => 100755 api/src/commonMain/kotlin/mehiz/abdallah/progres/api/ProgresApi.kt mode change 100644 => 100755 build.gradle.kts mode change 100644 => 100755 composeApp/build.gradle.kts mode change 100644 => 100755 composeApp/src/androidMain/AndroidManifest.xml mode change 100644 => 100755 composeApp/src/androidMain/kotlin/Platform.android.kt mode change 100644 => 100755 composeApp/src/androidMain/kotlin/mehiz/abdallah/progres/MainActivity.kt mode change 100644 => 100755 composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml mode change 100644 => 100755 composeApp/src/androidMain/res/drawable/ic_launcher_background.xml mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png mode change 100644 => 100755 composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png mode change 100644 => 100755 composeApp/src/androidMain/res/values/strings.xml mode change 100644 => 100755 composeApp/src/commonMain/composeResources/drawable/compose-multiplatform.xml mode change 100644 => 100755 composeApp/src/commonMain/kotlin/App.kt mode change 100644 => 100755 composeApp/src/commonMain/kotlin/Greeting.kt mode change 100644 => 100755 composeApp/src/commonMain/kotlin/Platform.kt create mode 100755 composeApp/src/commonMain/kotlin/di/PreferencesModule.kt create mode 100755 composeApp/src/commonMain/kotlin/di/initKodein.kt create mode 100755 composeApp/src/commonMain/kotlin/preferences/BasePreferences.kt create mode 100755 composeApp/src/commonMain/kotlin/preferences/Datastore.kt create mode 100755 composeApp/src/commonMain/kotlin/preferences/preference/DataStorePreference.kt create mode 100755 composeApp/src/commonMain/kotlin/preferences/preference/DataStorePreferenceStore.kt create mode 100755 composeApp/src/commonMain/kotlin/preferences/preference/Preference.kt create mode 100755 composeApp/src/commonMain/kotlin/preferences/preference/PreferenceStore.kt mode change 100644 => 100755 composeApp/src/iosMain/kotlin/MainViewController.kt mode change 100644 => 100755 composeApp/src/iosMain/kotlin/Platform.ios.kt mode change 100644 => 100755 data/.gitignore mode change 100644 => 100755 data/build.gradle.kts mode change 100644 => 100755 data/src/commonMain/kotlin/mehiz/abdallah/progres/data/ProgresDatabase.kt mode change 100644 => 100755 domain/.gitignore mode change 100644 => 100755 domain/build.gradle.kts mode change 100644 => 100755 gradle.properties mode change 100644 => 100755 gradle/libs.versions.toml mode change 100644 => 100755 gradle/wrapper/gradle-wrapper.jar mode change 100644 => 100755 gradle/wrapper/gradle-wrapper.properties mode change 100644 => 100755 gradlew mode change 100644 => 100755 gradlew.bat mode change 100644 => 100755 iosApp/Configuration/Config.xcconfig mode change 100644 => 100755 iosApp/iosApp.xcodeproj/project.pbxproj mode change 100644 => 100755 iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json mode change 100644 => 100755 iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json mode change 100644 => 100755 iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png mode change 100644 => 100755 iosApp/iosApp/Assets.xcassets/Contents.json mode change 100644 => 100755 iosApp/iosApp/ContentView.swift mode change 100644 => 100755 iosApp/iosApp/Info.plist mode change 100644 => 100755 iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json mode change 100644 => 100755 iosApp/iosApp/iOSApp.swift mode change 100644 => 100755 settings.gradle.kts diff --git a/.editorconfig b/.editorconfig old mode 100644 new mode 100755 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/api/.gitignore b/api/.gitignore old mode 100644 new mode 100755 diff --git a/api/build.gradle.kts b/api/build.gradle.kts old mode 100644 new mode 100755 diff --git a/api/src/commonMain/kotlin/mehiz/abdallah/progres/api/ProgresApi.kt b/api/src/commonMain/kotlin/mehiz/abdallah/progres/api/ProgresApi.kt old mode 100644 new mode 100755 diff --git a/build.gradle.kts b/build.gradle.kts old mode 100644 new mode 100755 diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts old mode 100644 new mode 100755 index b54597e..f84b70c --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -40,6 +40,9 @@ kotlin { implementation(compose.ui) implementation(compose.components.resources) implementation(compose.components.uiToolingPreview) + + api(libs.bundles.kodein) + api(libs.bundles.datastore) } } } diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/kotlin/Platform.android.kt b/composeApp/src/androidMain/kotlin/Platform.android.kt old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/kotlin/mehiz/abdallah/progres/MainActivity.kt b/composeApp/src/androidMain/kotlin/mehiz/abdallah/progres/MainActivity.kt old mode 100644 new mode 100755 index 85c9e9a..0bbba35 --- a/composeApp/src/androidMain/kotlin/mehiz/abdallah/progres/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/mehiz/abdallah/progres/MainActivity.kt @@ -6,13 +6,18 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview +import di.initKodein +import org.kodein.di.compose.withDI class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + val di = initKodein(applicationContext.filesDir.path) setContent { - App() + withDI(di = di) { + App() + } } } } diff --git a/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml b/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml b/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png old mode 100644 new mode 100755 diff --git a/composeApp/src/androidMain/res/values/strings.xml b/composeApp/src/androidMain/res/values/strings.xml old mode 100644 new mode 100755 diff --git a/composeApp/src/commonMain/composeResources/drawable/compose-multiplatform.xml b/composeApp/src/commonMain/composeResources/drawable/compose-multiplatform.xml old mode 100644 new mode 100755 diff --git a/composeApp/src/commonMain/kotlin/App.kt b/composeApp/src/commonMain/kotlin/App.kt old mode 100644 new mode 100755 diff --git a/composeApp/src/commonMain/kotlin/Greeting.kt b/composeApp/src/commonMain/kotlin/Greeting.kt old mode 100644 new mode 100755 diff --git a/composeApp/src/commonMain/kotlin/Platform.kt b/composeApp/src/commonMain/kotlin/Platform.kt old mode 100644 new mode 100755 diff --git a/composeApp/src/commonMain/kotlin/di/PreferencesModule.kt b/composeApp/src/commonMain/kotlin/di/PreferencesModule.kt new file mode 100755 index 0000000..39132f8 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/di/PreferencesModule.kt @@ -0,0 +1,18 @@ +package di + +import org.kodein.di.DI.Module +import org.kodein.di.bindSingleton +import org.kodein.di.instance +import org.kodein.di.singleton +import preferences.BasePreferences +import preferences.createDataStore +import preferences.preference.DataStorePreferenceStore +import preferences.preference.PreferenceStore + +val PreferencesModule: (String) -> Module = { + Module("PreferencesModule") { + bindSingleton { createDataStore { it } } + bindSingleton { DataStorePreferenceStore(instance()) } + bindSingleton { BasePreferences(instance()) } + } +} diff --git a/composeApp/src/commonMain/kotlin/di/initKodein.kt b/composeApp/src/commonMain/kotlin/di/initKodein.kt new file mode 100755 index 0000000..e07327c --- /dev/null +++ b/composeApp/src/commonMain/kotlin/di/initKodein.kt @@ -0,0 +1,14 @@ +package di + +import org.kodein.di.DI + +fun initKodein( + datastorePath: String, +): DI { + return DI.from( + listOf( + PreferencesModule(datastorePath) + ) + ) +} + diff --git a/composeApp/src/commonMain/kotlin/preferences/BasePreferences.kt b/composeApp/src/commonMain/kotlin/preferences/BasePreferences.kt new file mode 100755 index 0000000..306e4a1 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/preferences/BasePreferences.kt @@ -0,0 +1,7 @@ +package preferences + +import preferences.preference.PreferenceStore + +class BasePreferences( + preferences: PreferenceStore +) diff --git a/composeApp/src/commonMain/kotlin/preferences/Datastore.kt b/composeApp/src/commonMain/kotlin/preferences/Datastore.kt new file mode 100755 index 0000000..8efff4f --- /dev/null +++ b/composeApp/src/commonMain/kotlin/preferences/Datastore.kt @@ -0,0 +1,12 @@ +package preferences + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.PreferenceDataStoreFactory +import androidx.datastore.preferences.core.Preferences +import okio.Path.Companion.toPath + +fun createDataStore(producePath: () -> String): DataStore { + return PreferenceDataStoreFactory.createWithPath { (producePath() + "/" + DataStoreFileName).toPath() } +} + +internal const val DataStoreFileName = "prefs.preferences_pb" diff --git a/composeApp/src/commonMain/kotlin/preferences/preference/DataStorePreference.kt b/composeApp/src/commonMain/kotlin/preferences/preference/DataStorePreference.kt new file mode 100755 index 0000000..45145ff --- /dev/null +++ b/composeApp/src/commonMain/kotlin/preferences/preference/DataStorePreference.kt @@ -0,0 +1,201 @@ +package preferences.preference + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.byteArrayPreferencesKey +import androidx.datastore.preferences.core.doublePreferencesKey +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.floatPreferencesKey +import androidx.datastore.preferences.core.intPreferencesKey +import androidx.datastore.preferences.core.longPreferencesKey +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.core.stringSetPreferencesKey +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.IO +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking + +sealed class DataStorePreference( + private val dataStore: DataStore, + key: String, + private val defaultValue: T, +): Preference { + abstract fun read(key: Preferences.Key): T + + abstract fun write(key: Preferences.Key, value: T) + + abstract val key: Preferences.Key + + val coroutineScope = CoroutineScope(Dispatchers.IO) + + override fun key(): String { + return key.name + } + + override fun get(): T { + return read(key) + } + + override fun set(value: T) { + write(key, value) + } + + override fun isSet(): Boolean { + return runBlocking { dataStore.data.map { it.contains(key) }.first() } + } + + override fun delete() { + coroutineScope.launch { dataStore.edit { it.remove(key) } } + } + + override fun defaultValue(): T { + return defaultValue + } + + override fun changes(): Flow { + return dataStore.data.map { it[key]?: defaultValue } + } + + override fun stateIn(scope: CoroutineScope): StateFlow { + return changes().stateIn(scope, SharingStarted.Eagerly, get()) + } +} + +class StringPrimitive( + private val dataStore: DataStore, + key: String, + private val defaultValue: String, +): DataStorePreference(dataStore, key, defaultValue) { + override val key = stringPreferencesKey(key) + + override fun read(key: Preferences.Key): String { + return runBlocking { + dataStore.data.map { it[key] }.firstOrNull() ?: defaultValue + } + } + + override fun write(key: Preferences.Key, value: String) { + coroutineScope.launch { dataStore.edit { it[key] = value } } + } +} + +class IntPrimitive( + private val dataStore: DataStore, + key: String, + private val defaultValue: Int +): DataStorePreference(dataStore, key, defaultValue) { + override val key: Preferences.Key = intPreferencesKey(key) + + override fun read(key: Preferences.Key): Int { + return runBlocking { dataStore.data.map { it[key] }.firstOrNull()?: defaultValue } + } + + override fun write(key: Preferences.Key, value: Int) { + coroutineScope.launch { dataStore.edit { it[key] = value } } + } +} + +class FloatPrimitive( + private val dataStore: DataStore, + key: String, + private val defaultValue: Float, +): DataStorePreference(dataStore, key, defaultValue) { + override val key = floatPreferencesKey(key) + + override fun read(key: Preferences.Key): Float { + return runBlocking { dataStore.data.map { it[key] }.firstOrNull()?: defaultValue } + } + + override fun write(key: Preferences.Key, value: Float) { + coroutineScope.launch { dataStore.edit { it[key] = value } } + } +} + +class DoublePrimitive( + private val dataStore: DataStore, + key: String, + private val defaultValue: Double, +): DataStorePreference(dataStore, key, defaultValue) { + override val key = doublePreferencesKey(key) + + override fun read(key: Preferences.Key): Double { + return runBlocking { dataStore.data.map { it[key] }.firstOrNull()?: defaultValue } + } + + override fun write(key: Preferences.Key, value: Double) { + coroutineScope.launch { dataStore.edit { it[key] = value } } + } +} + +class LongPrimitive( + private val dataStore: DataStore, + key: String, + private val defaultValue: Long, +): DataStorePreference(dataStore, key, defaultValue) { + override val key = longPreferencesKey(key) + + override fun read(key: Preferences.Key): Long { + return runBlocking { dataStore.data.map { it[key] }.firstOrNull()?: defaultValue } + } + + override fun write(key: Preferences.Key, value: Long) { + coroutineScope.launch { dataStore.edit { it[key] = value } } + } +} + +class BooleanPrimitive( + private val dataStore: DataStore, + key: String, + private val defaultValue: Boolean, +): DataStorePreference(dataStore, key, defaultValue) { + override val key = booleanPreferencesKey(key) + + override fun read(key: Preferences.Key): Boolean { + return runBlocking { dataStore.data.map { it[key] }.firstOrNull()?: defaultValue } + } + + override fun write(key: Preferences.Key, value: Boolean) { + coroutineScope.launch { dataStore.edit { it[key] = value } } + } +} + +class StringSetPrimitive( + private val dataStore: DataStore, + key: String, + private val defaultValue: Set, +): DataStorePreference>(dataStore, key, defaultValue) { + override val key = stringSetPreferencesKey(key) + + override fun read(key: Preferences.Key>): Set { + return runBlocking { dataStore.data.map { it[key] }.firstOrNull()?: defaultValue } + } + + override fun write(key: Preferences.Key>, value: Set) { + coroutineScope.launch { dataStore.edit { it[key] = value } } + } +} + +class ByteArrayPrimitive( + private val dataStore: DataStore, + key: String, + private val defaultValue: ByteArray, +): DataStorePreference(dataStore, key, defaultValue) { + override val key = byteArrayPreferencesKey(key) + + override fun read(key: Preferences.Key): ByteArray { + return runBlocking { dataStore.data.map { it[key] }.firstOrNull()?: defaultValue } + } + + override fun write(key: Preferences.Key, value: ByteArray) { + coroutineScope.launch { dataStore.edit { it[key] = value } } + } +} diff --git a/composeApp/src/commonMain/kotlin/preferences/preference/DataStorePreferenceStore.kt b/composeApp/src/commonMain/kotlin/preferences/preference/DataStorePreferenceStore.kt new file mode 100755 index 0000000..b4b5b81 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/preferences/preference/DataStorePreferenceStore.kt @@ -0,0 +1,44 @@ +package preferences.preference + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import preferences.preference.BooleanPrimitive +import preferences.preference.ByteArrayPrimitive +import preferences.preference.IntPrimitive +import preferences.preference.LongPrimitive +import preferences.preference.Preference +import preferences.preference.PreferenceStore +import preferences.preference.StringPrimitive +import preferences.preference.StringSetPrimitive + +class DataStorePreferenceStore( + private val dataStore: DataStore +):PreferenceStore { + override fun getString(key: String, defaultValue: String): Preference { + return StringPrimitive(dataStore, key, defaultValue) + } + + override fun getLong(key: String, defaultValue: Long): Preference { + return LongPrimitive(dataStore, key, defaultValue) + } + + override fun getInt(key: String, defaultValue: Int): Preference { + return IntPrimitive(dataStore, key, defaultValue) + } + + override fun getFloat(key: String, defaultValue: Float): Preference { + return getFloat(key, defaultValue) + } + + override fun getBoolean(key: String, defaultValue: Boolean): Preference { + return BooleanPrimitive(dataStore, key, defaultValue) + } + + override fun getStringSet(key: String, defaultValue: Set): Preference> { + return StringSetPrimitive(dataStore, key, defaultValue) + } + + override fun getByteArray(key: String, defaultValue: ByteArray): Preference { + return ByteArrayPrimitive(dataStore, key, defaultValue) + } +} diff --git a/composeApp/src/commonMain/kotlin/preferences/preference/Preference.kt b/composeApp/src/commonMain/kotlin/preferences/preference/Preference.kt new file mode 100755 index 0000000..3a34c8c --- /dev/null +++ b/composeApp/src/commonMain/kotlin/preferences/preference/Preference.kt @@ -0,0 +1,34 @@ +package preferences.preference + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.remember +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow + +interface Preference { + + fun key(): String + + fun get(): T + + fun set(value: T) + + fun isSet(): Boolean + + fun delete() + + fun defaultValue(): T + + fun changes(): Flow + + fun stateIn(scope: CoroutineScope): StateFlow +} + +@Composable +fun Preference.collectAsState(): State { + val stateFlow = remember(this) { changes() } + return stateFlow.collectAsState(initial = get()) +} diff --git a/composeApp/src/commonMain/kotlin/preferences/preference/PreferenceStore.kt b/composeApp/src/commonMain/kotlin/preferences/preference/PreferenceStore.kt new file mode 100755 index 0000000..3301109 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/preferences/preference/PreferenceStore.kt @@ -0,0 +1,17 @@ +package preferences.preference + +interface PreferenceStore { + fun getString(key: String, defaultValue: String = ""): Preference + + fun getLong(key: String, defaultValue: Long = 0): Preference + + fun getInt(key: String, defaultValue: Int = 0): Preference + + fun getFloat(key: String, defaultValue: Float = 0f): Preference + + fun getBoolean(key: String, defaultValue: Boolean = false): Preference + + fun getStringSet(key: String, defaultValue: Set = emptySet()): Preference> + + fun getByteArray(key: String, defaultValue: ByteArray = byteArrayOf()): Preference +} diff --git a/composeApp/src/iosMain/kotlin/MainViewController.kt b/composeApp/src/iosMain/kotlin/MainViewController.kt old mode 100644 new mode 100755 index fa143d4..b79211d --- a/composeApp/src/iosMain/kotlin/MainViewController.kt +++ b/composeApp/src/iosMain/kotlin/MainViewController.kt @@ -1,3 +1,31 @@ import androidx.compose.ui.window.ComposeUIViewController +import di.initKodein +import kotlinx.cinterop.ExperimentalForeignApi +import org.kodein.di.compose.withDI +import platform.Foundation.NSDocumentDirectory +import platform.Foundation.NSFileManager +import platform.Foundation.NSUserDomainMask +import platform.UIKit.UIViewController +import preferences.DataStoreFileName -fun MainViewController() = ComposeUIViewController { App() } \ No newline at end of file +fun MainViewController(): UIViewController { + val di = initKodein(preferencesStorePath()) + return ComposeUIViewController { + withDI(di = di) { + App() + } + } +} + +@OptIn(ExperimentalForeignApi::class) +val preferencesStorePath: () -> String = { + requireNotNull( + NSFileManager.defaultManager.URLForDirectory( + directory = NSDocumentDirectory, + inDomain = NSUserDomainMask, + appropriateForURL = null, + create = false, + error = null, + ), + ).path!! +} diff --git a/composeApp/src/iosMain/kotlin/Platform.ios.kt b/composeApp/src/iosMain/kotlin/Platform.ios.kt old mode 100644 new mode 100755 diff --git a/data/.gitignore b/data/.gitignore old mode 100644 new mode 100755 diff --git a/data/build.gradle.kts b/data/build.gradle.kts old mode 100644 new mode 100755 diff --git a/data/src/commonMain/kotlin/mehiz/abdallah/progres/data/ProgresDatabase.kt b/data/src/commonMain/kotlin/mehiz/abdallah/progres/data/ProgresDatabase.kt old mode 100644 new mode 100755 diff --git a/domain/.gitignore b/domain/.gitignore old mode 100644 new mode 100755 diff --git a/domain/build.gradle.kts b/domain/build.gradle.kts old mode 100644 new mode 100755 diff --git a/gradle.properties b/gradle.properties old mode 100644 new mode 100755 diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml old mode 100644 new mode 100755 index 108a993..a8319ab --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,8 @@ kotlin = "2.0.0" jetbrainsKotlinJvm = "1.9.0" ktor = "2.3.12" +datastore = "1.1.1" +kodein = "7.22.0" [libraries] kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } @@ -36,8 +38,16 @@ ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" } +datastore-core = { module = "androidx.datastore:datastore", version.ref = "datastore" } +datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastore" } + +kodein-core = { module = "org.kodein.di:kodein-di", version.ref = "kodein" } +kodein-compose = { module = "org.kodein.di:kodein-di-framework-compose", version.ref = "kodein" } + [bundles] ktor = ["ktor-core", "ktor-logging", "ktor-content-negotiation", "ktor-serialization-kotlinx-json"] +kodein = ["kodein-core", "kodein-compose"] +datastore = ["datastore-core", "datastore-preferences"] [plugins] androidApplication = { id = "com.android.application", version.ref = "agp" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar old mode 100644 new mode 100755 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties old mode 100644 new mode 100755 diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/gradlew.bat b/gradlew.bat old mode 100644 new mode 100755 diff --git a/iosApp/Configuration/Config.xcconfig b/iosApp/Configuration/Config.xcconfig old mode 100644 new mode 100755 diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj old mode 100644 new mode 100755 diff --git a/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json b/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json old mode 100644 new mode 100755 diff --git a/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json old mode 100644 new mode 100755 diff --git a/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png b/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png old mode 100644 new mode 100755 diff --git a/iosApp/iosApp/Assets.xcassets/Contents.json b/iosApp/iosApp/Assets.xcassets/Contents.json old mode 100644 new mode 100755 diff --git a/iosApp/iosApp/ContentView.swift b/iosApp/iosApp/ContentView.swift old mode 100644 new mode 100755 diff --git a/iosApp/iosApp/Info.plist b/iosApp/iosApp/Info.plist old mode 100644 new mode 100755 diff --git a/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json b/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json old mode 100644 new mode 100755 diff --git a/iosApp/iosApp/iOSApp.swift b/iosApp/iosApp/iOSApp.swift old mode 100644 new mode 100755 diff --git a/settings.gradle.kts b/settings.gradle.kts old mode 100644 new mode 100755