Add PreferencesScreen
Three layers : - DataStore implementation - Preference description - UI Preference composables
This commit is contained in:
parent
76dfbeff32
commit
da5b030ab6
@ -57,6 +57,7 @@ dependencies {
|
||||
implementation(libs.palette)
|
||||
implementation(libs.workmanager)
|
||||
implementation(libs.encrypted.preferences)
|
||||
implementation(libs.datastore)
|
||||
|
||||
implementation(libs.jsoup)
|
||||
implementation(libs.jodatime)
|
||||
|
@ -1,5 +1,11 @@
|
||||
package com.readrops.app
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.handlers.ReplaceFileCorruptionHandler
|
||||
import androidx.datastore.preferences.SharedPreferencesMigration
|
||||
import androidx.datastore.preferences.core.PreferenceDataStoreFactory
|
||||
import androidx.datastore.preferences.core.emptyPreferences
|
||||
import androidx.datastore.preferences.preferencesDataStoreFile
|
||||
import androidx.security.crypto.EncryptedSharedPreferences
|
||||
import androidx.security.crypto.MasterKey
|
||||
import com.readrops.api.services.Credentials
|
||||
@ -16,8 +22,13 @@ import com.readrops.app.repositories.GetFoldersWithFeeds
|
||||
import com.readrops.app.repositories.LocalRSSRepository
|
||||
import com.readrops.app.repositories.NextcloudNewsRepository
|
||||
import com.readrops.app.timelime.TimelineScreenModel
|
||||
import com.readrops.app.util.DataStorePreferences
|
||||
import com.readrops.app.util.Preferences
|
||||
import com.readrops.db.entities.account.Account
|
||||
import com.readrops.db.entities.account.AccountType
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import org.koin.android.ext.koin.androidContext
|
||||
import org.koin.core.parameter.parametersOf
|
||||
import org.koin.dsl.module
|
||||
@ -72,4 +83,19 @@ val composeAppModule = module {
|
||||
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
|
||||
)
|
||||
}
|
||||
|
||||
single {
|
||||
PreferenceDataStoreFactory.create(
|
||||
corruptionHandler = ReplaceFileCorruptionHandler(
|
||||
produceNewData = { emptyPreferences() }
|
||||
),
|
||||
migrations = listOf(SharedPreferencesMigration(get(),"settings")),
|
||||
scope = CoroutineScope(Dispatchers.IO + SupervisorJob()),
|
||||
produceFile = { get<Context>().preferencesDataStoreFile("settings") }
|
||||
)
|
||||
}
|
||||
|
||||
single { DataStorePreferences(get()) }
|
||||
|
||||
single { Preferences(get()) }
|
||||
}
|
@ -18,6 +18,7 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
@ -26,6 +27,7 @@ import cafe.adriel.voyager.navigator.tab.TabOptions
|
||||
import com.readrops.app.BuildConfig
|
||||
import com.readrops.app.R
|
||||
import com.readrops.app.account.selection.adaptiveIconPainterResource
|
||||
import com.readrops.app.more.preferences.PreferencesScreen
|
||||
import com.readrops.app.util.components.IconText
|
||||
import com.readrops.app.util.components.SelectableIconText
|
||||
import com.readrops.app.util.openUrl
|
||||
@ -33,8 +35,10 @@ import com.readrops.app.util.theme.LargeSpacer
|
||||
import com.readrops.app.util.theme.MediumSpacer
|
||||
import com.readrops.app.util.theme.ShortSpacer
|
||||
import com.readrops.app.util.theme.spacing
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.get
|
||||
|
||||
object MoreTab : Tab {
|
||||
object MoreTab : Tab, KoinComponent {
|
||||
|
||||
override val options: TabOptions
|
||||
@Composable
|
||||
@ -127,32 +131,35 @@ object MoreTab : Tab {
|
||||
}
|
||||
}
|
||||
|
||||
LargeSpacer()
|
||||
MediumSpacer()
|
||||
|
||||
SelectableIconText(
|
||||
icon = painterResource(id = R.drawable.ic_settings),
|
||||
text = stringResource(R.string.settings),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
spacing = MaterialTheme.spacing.mediumSpacing,
|
||||
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Normal),
|
||||
spacing = MaterialTheme.spacing.largeSpacing,
|
||||
padding = MaterialTheme.spacing.mediumSpacing,
|
||||
onClick = { }
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
onClick = { navigator.push(PreferencesScreen(get())) }
|
||||
)
|
||||
|
||||
SelectableIconText(
|
||||
icon = painterResource(id = R.drawable.ic_library),
|
||||
text = stringResource(id = R.string.open_source_libraries),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
spacing = MaterialTheme.spacing.mediumSpacing,
|
||||
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Normal),
|
||||
spacing = MaterialTheme.spacing.largeSpacing,
|
||||
padding = MaterialTheme.spacing.mediumSpacing,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
onClick = { navigator.push(AboutLibrariesScreen()) }
|
||||
)
|
||||
|
||||
SelectableIconText(
|
||||
icon = painterResource(id = R.drawable.ic_donation),
|
||||
text = stringResource(id = R.string.make_donation),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
spacing = MaterialTheme.spacing.mediumSpacing,
|
||||
style = MaterialTheme.typography.titleMedium.copy(fontWeight = FontWeight.Normal),
|
||||
spacing = MaterialTheme.spacing.largeSpacing,
|
||||
padding = MaterialTheme.spacing.mediumSpacing,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
onClick = { }
|
||||
)
|
||||
}
|
||||
|
@ -0,0 +1,114 @@
|
||||
package com.readrops.app.more.preferences
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import cafe.adriel.voyager.navigator.LocalNavigator
|
||||
import cafe.adriel.voyager.navigator.currentOrThrow
|
||||
import com.readrops.app.R
|
||||
import com.readrops.app.more.preferences.components.ListPreferenceWidget
|
||||
import com.readrops.app.more.preferences.components.PreferenceHeader
|
||||
import com.readrops.app.more.preferences.components.SwitchPreferenceWidget
|
||||
import com.readrops.app.util.Preferences
|
||||
import com.readrops.app.util.components.AndroidScreen
|
||||
import org.koin.core.component.KoinComponent
|
||||
|
||||
|
||||
class PreferencesScreen(val preferences: Preferences) : AndroidScreen(), KoinComponent {
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
override fun Content() {
|
||||
val navigator = LocalNavigator.currentOrThrow
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text(text = stringResource(id = R.string.preferences)) },
|
||||
navigationIcon = {
|
||||
IconButton(
|
||||
onClick = { navigator.pop() }
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.AutoMirrored.Default.ArrowBack,
|
||||
contentDescription = null
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
Box(
|
||||
modifier = Modifier.padding(paddingValues)
|
||||
) {
|
||||
Column {
|
||||
PreferenceHeader(text = stringResource(id = R.string.global))
|
||||
|
||||
ListPreferenceWidget(
|
||||
preference = preferences.theme,
|
||||
entries = mapOf(
|
||||
"light" to stringResource(id = R.string.light),
|
||||
"dark" to stringResource(id = R.string.dark),
|
||||
"system" to stringResource(id = R.string.system)
|
||||
),
|
||||
title = stringResource(id = R.string.theme),
|
||||
onValueChange = {}
|
||||
)
|
||||
|
||||
ListPreferenceWidget(
|
||||
preference = preferences.backgroundSynchronization,
|
||||
entries = mapOf(
|
||||
"manual" to stringResource(id = R.string.manual),
|
||||
"0.30" to stringResource(id = R.string.min_30),
|
||||
"1" to stringResource(id = R.string.hour_1),
|
||||
"2" to stringResource(id = R.string.hour_2),
|
||||
"3" to stringResource(id = R.string.hour_3),
|
||||
"6" to stringResource(id = R.string.hour_6),
|
||||
"12" to stringResource(id = R.string.hour_12),
|
||||
"24" to stringResource(id = R.string.every_day)
|
||||
),
|
||||
title = stringResource(id = R.string.auto_synchro),
|
||||
onValueChange = {}
|
||||
)
|
||||
|
||||
PreferenceHeader(text = "Timeline")
|
||||
|
||||
SwitchPreferenceWidget(
|
||||
preference = preferences.hideReadFeeds,
|
||||
title = stringResource(id = R.string.hide_feeds),
|
||||
subtitle = "Feeds with no left unread items will be hidden with their respective folder"
|
||||
)
|
||||
|
||||
SwitchPreferenceWidget(
|
||||
preference = preferences.scrollRead,
|
||||
title = stringResource(id = R.string.mark_items_read)
|
||||
)
|
||||
|
||||
PreferenceHeader(text = "Item view")
|
||||
|
||||
ListPreferenceWidget(
|
||||
preference = preferences.openLinksWith,
|
||||
entries = mapOf(
|
||||
"navigator_view" to stringResource(id = R.string.navigator_view),
|
||||
"external_navigator" to stringResource(id = R.string.external_navigator)
|
||||
),
|
||||
title = stringResource(id = R.string.open_items_in),
|
||||
onValueChange = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,63 @@
|
||||
package com.readrops.app.more.preferences.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import com.readrops.app.util.theme.MediumSpacer
|
||||
import com.readrops.app.util.theme.spacing
|
||||
|
||||
@Composable
|
||||
fun BasePreference(
|
||||
title: String,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
subtitle: String? = null,
|
||||
rightComponent: (@Composable () -> Unit)? = null
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier.clickable { onClick() }
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier.padding(MaterialTheme.spacing.mediumSpacing)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.weight(1f)
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
fontWeight = FontWeight.Normal,
|
||||
maxLines = 2
|
||||
)
|
||||
|
||||
if (subtitle != null) {
|
||||
Text(
|
||||
text = subtitle,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (rightComponent != null) {
|
||||
MediumSpacer()
|
||||
|
||||
rightComponent()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
package com.readrops.app.more.preferences.components
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.toMutableStateList
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.readrops.app.util.Preference
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun <T> ListPreferenceWidget(
|
||||
preference: Preference<T>,
|
||||
entries: Map<T, String>,
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
onValueChange: (T) -> Unit,
|
||||
) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
var showDialog by remember { mutableStateOf(false) }
|
||||
val selectedKey by preference.flow.collectAsStateWithLifecycle(initialValue = preference.default)
|
||||
|
||||
if (showDialog) {
|
||||
val values = remember {
|
||||
entries.map { entry ->
|
||||
ToggleableInfo(
|
||||
key = entry.key,
|
||||
text = entry.value,
|
||||
isSelected = selectedKey == entry.key
|
||||
)
|
||||
}.toMutableStateList()
|
||||
}
|
||||
|
||||
RadioButtonPreferenceDialog(
|
||||
title = title,
|
||||
entries = values,
|
||||
onCheckChange = { newKey ->
|
||||
onValueChange(newKey)
|
||||
|
||||
values.replaceAll {
|
||||
it.copy(isSelected = it.key == newKey)
|
||||
}
|
||||
|
||||
coroutineScope.launch {
|
||||
preference.write(newKey)
|
||||
}
|
||||
},
|
||||
onDismiss = { showDialog = false }
|
||||
)
|
||||
}
|
||||
|
||||
BasePreference(
|
||||
title = title,
|
||||
subtitle = entries[selectedKey],
|
||||
onClick = { showDialog = true },
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.readrops.app.more.preferences.components
|
||||
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.readrops.app.util.theme.spacing
|
||||
|
||||
@Composable
|
||||
fun PreferenceHeader(
|
||||
text: String
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
modifier = Modifier.padding(MaterialTheme.spacing.shortSpacing)
|
||||
)
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
package com.readrops.app.more.preferences.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.BasicAlertDialog
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.readrops.app.R
|
||||
import com.readrops.app.util.theme.LargeSpacer
|
||||
import com.readrops.app.util.theme.MediumSpacer
|
||||
import com.readrops.app.util.theme.spacing
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun PreferenceBaseDialog(
|
||||
title: String,
|
||||
onDismiss: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
BasicAlertDialog(
|
||||
onDismissRequest = onDismiss
|
||||
) {
|
||||
Surface(
|
||||
tonalElevation = AlertDialogDefaults.TonalElevation,
|
||||
shape = AlertDialogDefaults.shape,
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.Center,
|
||||
horizontalAlignment = Alignment.Start,
|
||||
modifier = modifier
|
||||
.padding(MaterialTheme.spacing.largeSpacing)
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = MaterialTheme.typography.headlineSmall,
|
||||
color = AlertDialogDefaults.titleContentColor
|
||||
)
|
||||
|
||||
MediumSpacer()
|
||||
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data class ToggleableInfo<T>(
|
||||
val key: T,
|
||||
val text: String,
|
||||
val isSelected: Boolean
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun <T> RadioButtonPreferenceDialog(
|
||||
title: String,
|
||||
entries: List<ToggleableInfo<T>>,
|
||||
onCheckChange: (T) -> Unit,
|
||||
onDismiss: () -> Unit
|
||||
) {
|
||||
PreferenceBaseDialog(
|
||||
title = title,
|
||||
onDismiss = onDismiss
|
||||
) {
|
||||
Column(
|
||||
horizontalAlignment = Alignment.Start
|
||||
) {
|
||||
entries.forEach { entry ->
|
||||
RadioButtonItem(
|
||||
text = entry.text,
|
||||
isSelected = entry.isSelected,
|
||||
onClick = { onCheckChange(entry.key) }
|
||||
)
|
||||
}
|
||||
|
||||
MediumSpacer()
|
||||
|
||||
TextButton(
|
||||
onClick = onDismiss,
|
||||
modifier = Modifier.align(Alignment.End)
|
||||
) {
|
||||
Text(text = stringResource(id = R.string.cancel))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RadioButtonItem(
|
||||
text: String,
|
||||
isSelected: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier.clickable { onClick() }
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(
|
||||
horizontal = MaterialTheme.spacing.shortSpacing,
|
||||
vertical = MaterialTheme.spacing.veryShortSpacing
|
||||
)
|
||||
) {
|
||||
RadioButton(
|
||||
selected = isSelected,
|
||||
onClick = onClick
|
||||
)
|
||||
|
||||
LargeSpacer()
|
||||
|
||||
Text(
|
||||
text = text,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package com.readrops.app.more.preferences.components
|
||||
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.readrops.app.util.Preference
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun SwitchPreferenceWidget(
|
||||
preference: Preference<Boolean>,
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
subtitle: String? = null,
|
||||
) {
|
||||
val isChecked by preference.flow.collectAsState(initial = preference.default)
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
BasePreference(
|
||||
title = title,
|
||||
subtitle = subtitle,
|
||||
onClick = {
|
||||
coroutineScope.launch {
|
||||
preference.write(!isChecked)
|
||||
}
|
||||
},
|
||||
rightComponent = {
|
||||
Switch(
|
||||
checked = isChecked,
|
||||
onCheckedChange = {
|
||||
coroutineScope.launch {
|
||||
preference.write(!isChecked)
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
modifier = modifier
|
||||
)
|
||||
}
|
73
app/src/main/java/com/readrops/app/util/Preferences.kt
Normal file
73
app/src/main/java/com/readrops/app/util/Preferences.kt
Normal file
@ -0,0 +1,73 @@
|
||||
package com.readrops.app.util
|
||||
|
||||
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.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
data class Preference<T>(
|
||||
val dataStore: DataStorePreferences,
|
||||
val key: Preferences.Key<T>,
|
||||
val default: T,
|
||||
val flow: Flow<T> = dataStore.read(key, default)
|
||||
) {
|
||||
|
||||
suspend fun write(value: T) {
|
||||
dataStore.write(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
class Preferences(
|
||||
dataStore: DataStorePreferences,
|
||||
) {
|
||||
|
||||
val theme = Preference(
|
||||
dataStore = dataStore,
|
||||
key = stringPreferencesKey("theme"),
|
||||
default = "system"
|
||||
)
|
||||
|
||||
val backgroundSynchronization = Preference(
|
||||
dataStore = dataStore,
|
||||
key = stringPreferencesKey("synchro"),
|
||||
default = "manual"
|
||||
)
|
||||
|
||||
val scrollRead = Preference(
|
||||
dataStore = dataStore,
|
||||
key = booleanPreferencesKey("scroll_read"),
|
||||
default = false
|
||||
)
|
||||
|
||||
val hideReadFeeds = Preference(
|
||||
dataStore = dataStore,
|
||||
key = booleanPreferencesKey("hide_read_feeds"),
|
||||
default = false
|
||||
)
|
||||
|
||||
val openLinksWith = Preference(
|
||||
dataStore = dataStore,
|
||||
key = stringPreferencesKey("open_links_with"),
|
||||
default = "navigator_view"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class DataStorePreferences(private val dataStore: DataStore<Preferences>) {
|
||||
|
||||
fun <T> read(key: Preferences.Key<T>, default: T): Flow<T> {
|
||||
return dataStore.data
|
||||
.map { it[key] ?: default }
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
|
||||
suspend fun <T> write(key: Preferences.Key<T>, value: T) {
|
||||
dataStore.edit { settings ->
|
||||
settings[key] = value
|
||||
}
|
||||
}
|
||||
}
|
@ -176,4 +176,5 @@
|
||||
<string name="name">Nom</string>
|
||||
<string name="url">URL</string>
|
||||
<string name="unread">%1$d non-lu(s)</string>
|
||||
<string name="preferences">Paramètres</string>
|
||||
</resources>
|
@ -185,4 +185,5 @@
|
||||
<string name="name">Name</string>
|
||||
<string name="url">URL</string>
|
||||
<string name="unread">%1$d unread</string>
|
||||
<string name="preferences">Preferences</string>
|
||||
</resources>
|
@ -94,6 +94,7 @@ material = "com.google.android.material:material:1.12.0"
|
||||
palette = "androidx.palette:palette-ktx:1.0.0"
|
||||
workmanager = "androidx.work:work-runtime-ktx:2.9.0"
|
||||
encrypted-preferences = "androidx.security:security-crypto:1.1.0-alpha06"
|
||||
datastore = "androidx.datastore:datastore-preferences:1.1.1"
|
||||
|
||||
# test
|
||||
junit4 = "junit:junit:4.13.2"
|
||||
|
Loading…
x
Reference in New Issue
Block a user