diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt index 3f92501..f3a4b2e 100644 --- a/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/MainActivity.kt @@ -14,6 +14,8 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import su.reya.coop.nostr.NostrManager import su.reya.coop.storage.SecretStore +import su.reya.coop.storage.SettingStorage +import su.reya.coop.storage.settingsDataStore import su.reya.coop.viewmodel.AuthViewModel import su.reya.coop.viewmodel.ChatViewModel import su.reya.coop.viewmodel.NostrViewModel @@ -29,12 +31,13 @@ class MainActivity : ComponentActivity() { private val androidSigner = AndroidExternalSigner(this@MainActivity, externalSignerLauncher) private val secretStore = SecretStore(this@MainActivity) + private val settingStorage = SettingStorage(this@MainActivity.settingsDataStore) private val nostrViewModel = NostrViewModel(NostrManager.instance) private val chatViewModel = ChatViewModel(NostrManager.instance) private val authViewModel = - AuthViewModel(NostrManager.instance, secretStore, androidSigner) + AuthViewModel(NostrManager.instance, secretStore, settingStorage, androidSigner) override fun create(modelClass: Class): T { return when { diff --git a/composeApp/src/androidMain/kotlin/su/reya/coop/storage/DataStore.kt b/composeApp/src/androidMain/kotlin/su/reya/coop/storage/DataStore.kt new file mode 100644 index 0000000..812b65b --- /dev/null +++ b/composeApp/src/androidMain/kotlin/su/reya/coop/storage/DataStore.kt @@ -0,0 +1,8 @@ +package su.reya.coop.storage + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.preferencesDataStore + +val Context.settingsDataStore: DataStore by preferencesDataStore(name = "settings") diff --git a/shared/build.gradle.kts b/shared/build.gradle.kts index 276ec31..9f1965a 100644 --- a/shared/build.gradle.kts +++ b/shared/build.gradle.kts @@ -33,6 +33,8 @@ kotlin { implementation(libs.ktor.serialization.kotlinx.json) implementation(libs.androidx.lifecycle.viewmodelCompose) implementation(libs.androidx.lifecycle.runtimeCompose) + implementation(libs.androidx.datastore.preferences) + implementation(libs.androidx.datastore) implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.11.0") implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.8.0") implementation("su.reya:nostr-sdk-kmp:0.3.2") diff --git a/shared/src/commonMain/kotlin/su/reya/coop/storage/KeyValueStorage.kt b/shared/src/commonMain/kotlin/su/reya/coop/storage/KeyValueStorage.kt new file mode 100644 index 0000000..95c22a6 --- /dev/null +++ b/shared/src/commonMain/kotlin/su/reya/coop/storage/KeyValueStorage.kt @@ -0,0 +1,11 @@ +package su.reya.coop.storage + +import kotlinx.coroutines.flow.Flow + +interface KeyValueStorage { + suspend fun get(key: String): String? + fun getFlow(key: String): Flow + suspend fun set(key: String, value: String) + suspend fun clear(key: String) + suspend fun has(key: String): Boolean +} diff --git a/shared/src/commonMain/kotlin/su/reya/coop/storage/SettingStorage.kt b/shared/src/commonMain/kotlin/su/reya/coop/storage/SettingStorage.kt new file mode 100644 index 0000000..f6eea45 --- /dev/null +++ b/shared/src/commonMain/kotlin/su/reya/coop/storage/SettingStorage.kt @@ -0,0 +1,33 @@ +package su.reya.coop.storage + +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map + +class SettingStorage( + private val dataStore: DataStore +) : KeyValueStorage { + override suspend fun get(key: String): String? { + return dataStore.data.map { it[stringPreferencesKey(key)] }.first() + } + + override fun getFlow(key: String): Flow { + return dataStore.data.map { it[stringPreferencesKey(key)] } + } + + override suspend fun set(key: String, value: String) { + dataStore.edit { it[stringPreferencesKey(key)] = value } + } + + override suspend fun clear(key: String) { + dataStore.edit { it.remove(stringPreferencesKey(key)) } + } + + override suspend fun has(key: String): Boolean { + return dataStore.data.map { it.contains(stringPreferencesKey(key)) }.first() + } +} diff --git a/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/AuthViewModel.kt b/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/AuthViewModel.kt index e77db2e..630633f 100644 --- a/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/AuthViewModel.kt +++ b/shared/src/commonMain/kotlin/su/reya/coop/viewmodel/AuthViewModel.kt @@ -17,6 +17,7 @@ import su.reya.coop.nostr.ExternalSignerProxy import su.reya.coop.nostr.Nostr import su.reya.coop.nostr.SignerPermissions import su.reya.coop.repository.MediaRepository +import su.reya.coop.storage.KeyValueStorage import su.reya.coop.storage.SecretStorage import kotlin.time.Duration.Companion.seconds @@ -28,6 +29,7 @@ data class AuthState( class AuthViewModel( private val nostr: Nostr, private val secretStore: SecretStorage, + private val settingStorage: KeyValueStorage, private val externalSignerHandler: ExternalSignerHandler? = null, ) : BaseViewModel() { private val mediaRepository = MediaRepository() @@ -51,7 +53,7 @@ class AuthViewModel( private fun checkNotificationBannerDismissedStatus() { viewModelScope.launch { - val dismissed = secretStore.get(KEY_BANNER_DISMISSED) == "true" + val dismissed = settingStorage.get(KEY_BANNER_DISMISSED) == "true" _state.update { it.copy(isNotificationBannerDismissed = dismissed) } } } @@ -95,7 +97,7 @@ class AuthViewModel( } finally { // Clear credentials from persistent storage secretStore.clear(KEY_USER_SIGNER) - secretStore.clear(KEY_BANNER_DISMISSED) + settingStorage.clear(KEY_BANNER_DISMISSED) // Call cleanup callback (e.g. to reset other ViewModels) onLogout() // Reset local states @@ -106,7 +108,7 @@ class AuthViewModel( fun dismissNotificationBanner() { viewModelScope.launch { - secretStore.set(KEY_BANNER_DISMISSED, "true") + settingStorage.set(KEY_BANNER_DISMISSED, "true") _state.update { it.copy(isNotificationBannerDismissed = true) } } }