Extract SharedPreferences extensions to a file

This commit is contained in:
Kirill Kamakin
2021-11-27 00:19:49 +03:00
parent dc6084ee25
commit b3d03c5281
3 changed files with 44 additions and 35 deletions

View File

@@ -2,13 +2,11 @@ package gq.kirmanak.mealient.data.auth.impl
import android.content.SharedPreferences import android.content.SharedPreferences
import gq.kirmanak.mealient.data.auth.AuthStorage import gq.kirmanak.mealient.data.auth.AuthStorage
import kotlinx.coroutines.Dispatchers import gq.kirmanak.mealient.data.impl.util.changesFlow
import gq.kirmanak.mealient.data.impl.util.getStringOrNull
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.onFailure
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@@ -29,43 +27,21 @@ class AuthStorageImpl @Inject constructor(
} }
override suspend fun getBaseUrl(): String? { override suspend fun getBaseUrl(): String? {
val baseUrl = getString(BASE_URL_KEY) val baseUrl = sharedPreferences.getStringOrNull(BASE_URL_KEY)
Timber.d("getBaseUrl: base url is $baseUrl") Timber.d("getBaseUrl: base url is $baseUrl")
return baseUrl return baseUrl
} }
override suspend fun getToken(): String? { override suspend fun getToken(): String? {
Timber.v("getToken() called") Timber.v("getToken() called")
val token = getString(TOKEN_KEY) val token = sharedPreferences.getStringOrNull(TOKEN_KEY)
Timber.d("getToken: token is $token") Timber.d("getToken: token is $token")
return token return token
} }
private suspend fun getString(key: String): String? = withContext(Dispatchers.Default) {
sharedPreferences.getString(key, null)
}
override fun tokenObservable(): Flow<String?> { override fun tokenObservable(): Flow<String?> {
Timber.v("tokenObservable() called") Timber.v("tokenObservable() called")
return callbackFlow { return sharedPreferences.changesFlow().map { it.first.getStringOrNull(TOKEN_KEY) }
val listener = SharedPreferences.OnSharedPreferenceChangeListener { prefs, key ->
Timber.v("tokenObservable: listener called with key $key")
val token = when (key) {
null -> null
TOKEN_KEY -> prefs.getString(key, null)
else -> return@OnSharedPreferenceChangeListener
}
Timber.d("tokenObservable: New token: $token")
trySend(token).onFailure { Timber.e(it, "Can't send new token") }
}
Timber.v("tokenObservable: registering listener")
send(getToken())
sharedPreferences.registerOnSharedPreferenceChangeListener(listener)
awaitClose {
Timber.v("tokenObservable: flow has been closed")
sharedPreferences.unregisterOnSharedPreferenceChangeListener(listener)
}
}
} }
override fun clearAuthData() { override fun clearAuthData() {

View File

@@ -1,8 +1,7 @@
package gq.kirmanak.mealient.data.disclaimer package gq.kirmanak.mealient.data.disclaimer
import android.content.SharedPreferences import android.content.SharedPreferences
import kotlinx.coroutines.Dispatchers import gq.kirmanak.mealient.data.impl.util.getBooleanOrFalse
import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@@ -14,9 +13,7 @@ class DisclaimerStorageImpl @Inject constructor(
override suspend fun isDisclaimerAccepted(): Boolean { override suspend fun isDisclaimerAccepted(): Boolean {
Timber.v("isDisclaimerAccepted() called") Timber.v("isDisclaimerAccepted() called")
val isAccepted = withContext(Dispatchers.IO) { val isAccepted = sharedPreferences.getBooleanOrFalse(IS_DISCLAIMER_ACCEPTED_KEY)
sharedPreferences.getBoolean(IS_DISCLAIMER_ACCEPTED_KEY, false)
}
Timber.v("isDisclaimerAccepted() returned: $isAccepted") Timber.v("isDisclaimerAccepted() returned: $isAccepted")
return isAccepted return isAccepted
} }

View File

@@ -0,0 +1,36 @@
package gq.kirmanak.mealient.data.impl.util
import android.content.SharedPreferences
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.onClosed
import kotlinx.coroutines.channels.onFailure
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.withContext
import timber.log.Timber
suspend fun SharedPreferences.getStringOrNull(key: String) =
withContext(Dispatchers.IO) { getString(key, null) }
suspend fun SharedPreferences.getBooleanOrFalse(key: String) =
withContext(Dispatchers.IO) { getBoolean(key, false) }
@ExperimentalCoroutinesApi
fun SharedPreferences.changesFlow(): Flow<Pair<SharedPreferences, String?>> = callbackFlow {
val listener = SharedPreferences.OnSharedPreferenceChangeListener { prefs, key ->
Timber.v("watchChanges: listener called with key $key")
trySend(prefs to key)
.onFailure { Timber.e(it, "watchChanges: can't send preference change, key $key") }
.onClosed { Timber.e(it, "watchChanges: flow has been closed") }
}
Timber.v("watchChanges: registering listener")
registerOnSharedPreferenceChangeListener(listener)
send(this@changesFlow to null)
awaitClose {
Timber.v("watchChanges: flow has been closed")
unregisterOnSharedPreferenceChangeListener(listener)
}
}