Replace Shared Preferences with Data Store
This commit is contained in:
@@ -15,5 +15,5 @@ interface AuthRepo {
|
||||
|
||||
fun authenticationStatuses(): Flow<Boolean>
|
||||
|
||||
fun logout()
|
||||
suspend fun logout()
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package gq.kirmanak.mealient.data.auth
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface AuthStorage {
|
||||
fun storeAuthData(authHeader: String, baseUrl: String)
|
||||
suspend fun storeAuthData(authHeader: String, baseUrl: String)
|
||||
|
||||
suspend fun getBaseUrl(): String?
|
||||
|
||||
@@ -11,5 +11,5 @@ interface AuthStorage {
|
||||
|
||||
fun authHeaderObservable(): Flow<String?>
|
||||
|
||||
fun clearAuthData()
|
||||
suspend fun clearAuthData()
|
||||
}
|
||||
@@ -46,7 +46,7 @@ class AuthRepoImpl @Inject constructor(
|
||||
return storage.authHeaderObservable().map { it != null }
|
||||
}
|
||||
|
||||
override fun logout() {
|
||||
override suspend fun logout() {
|
||||
Timber.v("logout() called")
|
||||
storage.clearAuthData()
|
||||
}
|
||||
|
||||
@@ -1,55 +1,48 @@
|
||||
package gq.kirmanak.mealient.data.auth.impl
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import gq.kirmanak.mealient.data.auth.AuthStorage
|
||||
import gq.kirmanak.mealient.extensions.changesFlow
|
||||
import gq.kirmanak.mealient.extensions.getStringOrNull
|
||||
import gq.kirmanak.mealient.data.storage.PreferencesStorage
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
private const val AUTH_HEADER_KEY = "AUTH_TOKEN"
|
||||
private const val BASE_URL_KEY = "BASE_URL"
|
||||
|
||||
@Singleton
|
||||
class AuthStorageImpl @Inject constructor(
|
||||
private val sharedPreferences: SharedPreferences
|
||||
private val preferencesStorage: PreferencesStorage,
|
||||
) : AuthStorage {
|
||||
|
||||
override fun storeAuthData(authHeader: String, baseUrl: String) {
|
||||
private val authHeaderKey by preferencesStorage::authHeaderKey
|
||||
private val baseUrlKey by preferencesStorage::baseUrlKey
|
||||
|
||||
override suspend fun storeAuthData(authHeader: String, baseUrl: String) {
|
||||
Timber.v("storeAuthData() called with: authHeader = $authHeader, baseUrl = $baseUrl")
|
||||
sharedPreferences.edit {
|
||||
putString(AUTH_HEADER_KEY, authHeader)
|
||||
putString(BASE_URL_KEY, baseUrl)
|
||||
}
|
||||
preferencesStorage.storeValues(
|
||||
Pair(authHeaderKey, authHeader),
|
||||
Pair(baseUrlKey, baseUrl),
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getBaseUrl(): String? {
|
||||
val baseUrl = sharedPreferences.getStringOrNull(BASE_URL_KEY)
|
||||
val baseUrl = preferencesStorage.getValue(baseUrlKey)
|
||||
Timber.d("getBaseUrl: base url is $baseUrl")
|
||||
return baseUrl
|
||||
}
|
||||
|
||||
override suspend fun getAuthHeader(): String? {
|
||||
Timber.v("getAuthHeader() called")
|
||||
val token = sharedPreferences.getStringOrNull(AUTH_HEADER_KEY)
|
||||
val token = preferencesStorage.getValue(authHeaderKey)
|
||||
Timber.d("getAuthHeader: header is \"$token\"")
|
||||
return token
|
||||
}
|
||||
|
||||
override fun authHeaderObservable(): Flow<String?> {
|
||||
Timber.v("authHeaderObservable() called")
|
||||
return sharedPreferences.changesFlow().map { it.first.getStringOrNull(AUTH_HEADER_KEY) }
|
||||
return preferencesStorage.valueUpdates(authHeaderKey)
|
||||
}
|
||||
|
||||
override fun clearAuthData() {
|
||||
override suspend fun clearAuthData() {
|
||||
Timber.v("clearAuthData() called")
|
||||
sharedPreferences.edit {
|
||||
remove(AUTH_HEADER_KEY)
|
||||
remove(BASE_URL_KEY)
|
||||
}
|
||||
preferencesStorage.removeValues(authHeaderKey, baseUrlKey)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ package gq.kirmanak.mealient.data.disclaimer
|
||||
interface DisclaimerStorage {
|
||||
suspend fun isDisclaimerAccepted(): Boolean
|
||||
|
||||
fun acceptDisclaimer()
|
||||
suspend fun acceptDisclaimer()
|
||||
}
|
||||
@@ -1,29 +1,26 @@
|
||||
package gq.kirmanak.mealient.data.disclaimer
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import gq.kirmanak.mealient.extensions.getBooleanOrFalse
|
||||
import gq.kirmanak.mealient.data.storage.PreferencesStorage
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
private const val IS_DISCLAIMER_ACCEPTED_KEY = "IS_DISCLAIMER_ACCEPTED"
|
||||
|
||||
@Singleton
|
||||
class DisclaimerStorageImpl @Inject constructor(
|
||||
private val sharedPreferences: SharedPreferences
|
||||
private val preferencesStorage: PreferencesStorage,
|
||||
) : DisclaimerStorage {
|
||||
|
||||
private val isDisclaimerAcceptedKey by preferencesStorage::isDisclaimerAcceptedKey
|
||||
|
||||
override suspend fun isDisclaimerAccepted(): Boolean {
|
||||
Timber.v("isDisclaimerAccepted() called")
|
||||
val isAccepted = sharedPreferences.getBooleanOrFalse(IS_DISCLAIMER_ACCEPTED_KEY)
|
||||
val isAccepted = preferencesStorage.getValue(isDisclaimerAcceptedKey) ?: false
|
||||
Timber.v("isDisclaimerAccepted() returned: $isAccepted")
|
||||
return isAccepted
|
||||
}
|
||||
|
||||
override fun acceptDisclaimer() {
|
||||
override suspend fun acceptDisclaimer() {
|
||||
Timber.v("acceptDisclaimer() called")
|
||||
sharedPreferences.edit()
|
||||
.putBoolean(IS_DISCLAIMER_ACCEPTED_KEY, true)
|
||||
.apply()
|
||||
preferencesStorage.storeValues(Pair(isDisclaimerAcceptedKey, true))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package gq.kirmanak.mealient.data.storage
|
||||
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface PreferencesStorage {
|
||||
|
||||
val baseUrlKey: Preferences.Key<String>
|
||||
|
||||
val authHeaderKey: Preferences.Key<String>
|
||||
|
||||
val isDisclaimerAcceptedKey: Preferences.Key<Boolean>
|
||||
|
||||
suspend fun <T> getValue(key: Preferences.Key<T>): T?
|
||||
|
||||
suspend fun <T> requireValue(key: Preferences.Key<T>): T
|
||||
|
||||
suspend fun <T> storeValues(vararg pairs: Pair<Preferences.Key<T>, T>)
|
||||
|
||||
fun <T> valueUpdates(key: Preferences.Key<T>): Flow<T?>
|
||||
|
||||
suspend fun <T> removeValues(vararg keys: Preferences.Key<T>)
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package gq.kirmanak.mealient.data.storage
|
||||
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import kotlinx.coroutines.flow.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class PreferencesStorageImpl @Inject constructor(
|
||||
private val dataStore: DataStore<Preferences>
|
||||
) : PreferencesStorage {
|
||||
|
||||
override val baseUrlKey = stringPreferencesKey("baseUrl")
|
||||
|
||||
override val authHeaderKey = stringPreferencesKey("authHeader")
|
||||
|
||||
override val isDisclaimerAcceptedKey = booleanPreferencesKey("isDisclaimedAccepted")
|
||||
|
||||
override suspend fun <T> getValue(key: Preferences.Key<T>): T? {
|
||||
val value = dataStore.data.first()[key]
|
||||
Timber.v("getValue() returned: $value for $key")
|
||||
return value
|
||||
}
|
||||
|
||||
override suspend fun <T> requireValue(key: Preferences.Key<T>): T =
|
||||
checkNotNull(getValue(key)) { "Value at $key is null when it was required" }
|
||||
|
||||
override suspend fun <T> storeValues(vararg pairs: Pair<Preferences.Key<T>, T>) {
|
||||
Timber.v("storeValues() called with: pairs = ${pairs.contentToString()}")
|
||||
dataStore.edit { preferences ->
|
||||
pairs.forEach { preferences += it.toPreferencesPair() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T> valueUpdates(key: Preferences.Key<T>): Flow<T?> {
|
||||
Timber.v("valueUpdates() called with: key = $key")
|
||||
return dataStore.data
|
||||
.map { it[key] }
|
||||
.distinctUntilChanged()
|
||||
.onEach { Timber.d("valueUpdates: new value at $key is $it") }
|
||||
.onCompletion { Timber.i(it, "valueUpdates: finished") }
|
||||
}
|
||||
|
||||
override suspend fun <T> removeValues(vararg keys: Preferences.Key<T>) {
|
||||
Timber.v("removeValues() called with: key = ${keys.contentToString()}")
|
||||
dataStore.edit { preferences ->
|
||||
keys.forEach { preferences -= it }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun <T> Pair<Preferences.Key<T>, T>.toPreferencesPair(): Preferences.Pair<T> {
|
||||
val (key, value) = this
|
||||
return key to value
|
||||
}
|
||||
Reference in New Issue
Block a user