diff --git a/app/src/main/java/me/ash/reader/infrastructure/preference/FlowArticleReadIndicatorPreference.kt b/app/src/main/java/me/ash/reader/infrastructure/preference/FlowArticleReadIndicatorPreference.kt new file mode 100644 index 000000000..5c010bb47 --- /dev/null +++ b/app/src/main/java/me/ash/reader/infrastructure/preference/FlowArticleReadIndicatorPreference.kt @@ -0,0 +1,54 @@ +package me.ash.reader.infrastructure.preference + +import android.content.Context +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import androidx.datastore.preferences.core.Preferences +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import me.ash.reader.R +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FlowArticleReadIndicatorPreference(val value: Boolean) : Preference() { + object ExcludingStarred : FlowArticleReadIndicatorPreference(true) + object AllRead : FlowArticleReadIndicatorPreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch { + context.dataStore.put( + DataStoreKeys.FlowArticleListReadIndicator, + value + ) + } + } + + val description: String + @Composable get() { + return when (this) { + AllRead -> stringResource(id = R.string.all_read) + ExcludingStarred -> stringResource(id = R.string.read_excluding_starred) + } + } + + companion object { + + val default = ExcludingStarred + val values = listOf(ExcludingStarred, AllRead) + + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowArticleListReadIndicator.key]) { + true -> ExcludingStarred + false -> AllRead + else -> default + } + + } +} + +operator fun FlowArticleReadIndicatorPreference.not(): FlowArticleReadIndicatorPreference = + when (value) { + true -> FlowArticleReadIndicatorPreference.AllRead + false -> FlowArticleReadIndicatorPreference.ExcludingStarred + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/infrastructure/preference/Preference.kt b/app/src/main/java/me/ash/reader/infrastructure/preference/Preference.kt index 9ca55f2fe..371062920 100644 --- a/app/src/main/java/me/ash/reader/infrastructure/preference/Preference.kt +++ b/app/src/main/java/me/ash/reader/infrastructure/preference/Preference.kt @@ -49,6 +49,7 @@ fun Preferences.toSettings(): Settings { flowArticleListDateStickyHeader = FlowArticleListDateStickyHeaderPreference.fromPreferences( this ), + flowArticleListReadIndicator = FlowArticleReadIndicatorPreference.fromPreferences(this), flowArticleListTonalElevation = FlowArticleListTonalElevationPreference.fromPreferences(this), // Reading page diff --git a/app/src/main/java/me/ash/reader/infrastructure/preference/Settings.kt b/app/src/main/java/me/ash/reader/infrastructure/preference/Settings.kt index 0f27883a3..6dfeb5058 100644 --- a/app/src/main/java/me/ash/reader/infrastructure/preference/Settings.kt +++ b/app/src/main/java/me/ash/reader/infrastructure/preference/Settings.kt @@ -49,6 +49,7 @@ data class Settings( val flowArticleListTime: FlowArticleListTimePreference = FlowArticleListTimePreference.default, val flowArticleListDateStickyHeader: FlowArticleListDateStickyHeaderPreference = FlowArticleListDateStickyHeaderPreference.default, val flowArticleListTonalElevation: FlowArticleListTonalElevationPreference = FlowArticleListTonalElevationPreference.default, + val flowArticleListReadIndicator: FlowArticleReadIndicatorPreference = FlowArticleReadIndicatorPreference.default, // Reading page val readingTheme: ReadingThemePreference = ReadingThemePreference.default, @@ -141,6 +142,8 @@ val LocalFlowArticleListDateStickyHeader = compositionLocalOf { FlowArticleListDateStickyHeaderPreference.default } val LocalFlowArticleListTonalElevation = compositionLocalOf { FlowArticleListTonalElevationPreference.default } +val LocalFlowArticleListReadIndicator = + compositionLocalOf { FlowArticleReadIndicatorPreference.default } // Reading page val LocalReadingTheme = compositionLocalOf { ReadingThemePreference.default } @@ -234,6 +237,7 @@ fun SettingsProvider( LocalFlowFilterBarFilled provides settings.flowFilterBarFilled, LocalFlowFilterBarPadding provides settings.flowFilterBarPadding, LocalFlowFilterBarTonalElevation provides settings.flowFilterBarTonalElevation, + LocalFlowArticleListReadIndicator provides settings.flowArticleListReadIndicator, // Reading page LocalReadingTheme provides settings.readingTheme, diff --git a/app/src/main/java/me/ash/reader/ui/ext/DataStoreExt.kt b/app/src/main/java/me/ash/reader/ui/ext/DataStoreExt.kt index 377f6069e..1b69ee433 100644 --- a/app/src/main/java/me/ash/reader/ui/ext/DataStoreExt.kt +++ b/app/src/main/java/me/ash/reader/ui/ext/DataStoreExt.kt @@ -270,6 +270,12 @@ sealed class DataStoreKeys { get() = intPreferencesKey("flowArticleListTonalElevation") } + object FlowArticleListReadIndicator : DataStoreKeys() { + + override val key: Preferences.Key + get() = booleanPreferencesKey("flowArticleListReadIndicator") + } + // Reading page object ReadingDarkTheme : DataStoreKeys() { diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt index 714022dc8..a9124f121 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleItem.kt @@ -42,6 +42,7 @@ fun ArticleItem( val articleListImage = LocalFlowArticleListImage.current val articleListDesc = LocalFlowArticleListDesc.current val articleListDate = LocalFlowArticleListTime.current + val articleListReadIndicator = LocalFlowArticleListReadIndicator.current Column( modifier = Modifier @@ -49,7 +50,19 @@ fun ArticleItem( .clip(Shape20) .clickable { onClick(articleWithFeed) } .padding(horizontal = 12.dp, vertical = 12.dp) - .alpha(if (articleWithFeed.article.isStarred || articleWithFeed.article.isUnread) 1f else 0.5f), + .alpha( + articleWithFeed.article.run { + when (articleListReadIndicator) { + FlowArticleReadIndicatorPreference.AllRead -> { + if (isUnread) 1f else 0.5f + } + + FlowArticleReadIndicatorPreference.ExcludingStarred -> { + if (isUnread || isStarred) 1f else 0.5f + } + } + } + ), ) { // Top Row( @@ -157,23 +170,25 @@ fun ArticleItem( } } } + @ExperimentalMaterialApi @Composable fun SwipeableArticleItem( - articleWithFeed: ArticleWithFeed, - isFilterUnread: Boolean, - articleListTonalElevation: Int, - onClick: (ArticleWithFeed) -> Unit = {}, - onSwipeOut: (ArticleWithFeed) -> Unit = {}, + articleWithFeed: ArticleWithFeed, + isFilterUnread: Boolean, + articleListTonalElevation: Int, + onClick: (ArticleWithFeed) -> Unit = {}, + onSwipeOut: (ArticleWithFeed) -> Unit = {}, ) { var isArticleVisible by remember { mutableStateOf(true) } - val dismissState = rememberDismissState(initialValue = DismissValue.Default, confirmStateChange = { - if (it == DismissValue.DismissedToEnd) { - isArticleVisible = !isFilterUnread - onSwipeOut(articleWithFeed) - } - isFilterUnread - }) + val dismissState = + rememberDismissState(initialValue = DismissValue.Default, confirmStateChange = { + if (it == DismissValue.DismissedToEnd) { + isArticleVisible = !isFilterUnread + onSwipeOut(articleWithFeed) + } + isFilterUnread + }) if (isArticleVisible) { SwipeToDismiss( state = dismissState, @@ -209,8 +224,11 @@ fun SwipeableArticleItem( Box( modifier = Modifier .fillMaxSize() - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.dp - ) onDark MaterialTheme.colorScheme.surface) + .background( + MaterialTheme.colorScheme.surfaceColorAtElevation( + articleListTonalElevation.dp + ) onDark MaterialTheme.colorScheme.surface + ) ) { ArticleItem(articleWithFeed, onClick) } diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStylePage.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStylePage.kt index a6e8b0280..781c4b1bc 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStylePage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStylePage.kt @@ -39,6 +39,7 @@ fun FlowPageStylePage( val articleListTime = LocalFlowArticleListTime.current val articleListStickyDate = LocalFlowArticleListDateStickyHeader.current val articleListTonalElevation = LocalFlowArticleListTonalElevation.current + val articleListReadIndicator = LocalFlowArticleListReadIndicator.current val scope = rememberCoroutineScope() @@ -47,6 +48,7 @@ fun FlowPageStylePage( var filterBarTonalElevationDialogVisible by remember { mutableStateOf(false) } var topBarTonalElevationDialogVisible by remember { mutableStateOf(false) } var articleListTonalElevationDialogVisible by remember { mutableStateOf(false) } + var articleListReadIndicatorDialogVisible by remember { mutableStateOf(false) } var filterBarPaddingValue: Int? by remember { mutableStateOf(filterBarPadding) } @@ -183,6 +185,13 @@ fun FlowPageStylePage( (!articleListStickyDate).put(context, scope) } } + SettingItem( + title = stringResource(R.string.grey_out_articles), + desc = articleListReadIndicator.description, + onClick = { + articleListReadIndicatorDialogVisible = true + } + ) SettingItem( title = stringResource(R.string.tonal_elevation), desc = "${articleListTonalElevation.value}dp", @@ -317,4 +326,19 @@ fun FlowPageStylePage( ) { articleListTonalElevationDialogVisible = false } + + RadioDialog( + visible = articleListReadIndicatorDialogVisible, + title = stringResource(id = R.string.grey_out_articles), + options = FlowArticleReadIndicatorPreference.values.map { + RadioDialogOption( + text = it.description, + selected = it == articleListReadIndicator + ) { + it.put(context, scope) + } + } + ) { + articleListReadIndicatorDialogVisible = false + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 231f2baf3..a188c937e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -406,4 +406,7 @@ Include additional info Exclude Additional information includes configuration options for each feed, such as whether to allow notification, parse full content, etc. When you intend to use the exported OPML file with other readers, please select \"Exclude\". + Grey out articles + All read + Read, excluding starred