From 203620173a47bc43109758df409b24bd777ade5a Mon Sep 17 00:00:00 2001 From: Ash Date: Sat, 30 Apr 2022 17:37:06 +0800 Subject: [PATCH 1/6] Add more styles for navigation bar and tonal elevation available --- .../java/me/ash/reader/ui/page/home/FilterBar.kt | 14 +++++++------- .../me/ash/reader/ui/page/home/flow/FlowPage.kt | 12 +++++++----- .../ash/reader/ui/page/home/flow/StickyHeader.kt | 3 ++- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt b/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt index a2f217d..ab3cbb0 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt @@ -11,7 +11,6 @@ import androidx.compose.ui.zIndex import com.google.accompanist.pager.ExperimentalPagerApi import me.ash.reader.data.entity.Filter import me.ash.reader.ui.ext.getName -import me.ash.reader.ui.theme.palette.alwaysLight @OptIn(ExperimentalPagerApi::class) @Composable @@ -23,7 +22,7 @@ fun FilterBar( val view = LocalView.current Box( - modifier = Modifier.height(60.dp) +// modifier = Modifier.height(60.dp) ) { Divider( modifier = Modifier @@ -33,8 +32,8 @@ fun FilterBar( color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.24f) ) NavigationBar( - modifier = Modifier.fillMaxSize(), - tonalElevation = 0.dp, +// modifier = Modifier.fillMaxSize(), +// tonalElevation = 0.dp, ) { Spacer(modifier = Modifier.width(60.dp)) listOf( @@ -49,6 +48,7 @@ fun FilterBar( contentDescription = item.getName() ) }, + label = { Text(text = item.getName(), style = MaterialTheme.typography.labelMedium) }, selected = filter == item, onClick = { // view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) @@ -56,11 +56,11 @@ fun FilterBar( filterOnClick(item) }, colors = NavigationBarItemDefaults.colors( - selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer alwaysLight true, +// selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer alwaysLight true, // unselectedIconColor = MaterialTheme.colorScheme.outline, - selectedTextColor = MaterialTheme.colorScheme.onSurface alwaysLight true, +// selectedTextColor = MaterialTheme.colorScheme.onSurface alwaysLight true, // unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant, - indicatorColor = MaterialTheme.colorScheme.primaryContainer alwaysLight true, +// indicatorColor = MaterialTheme.colorScheme.primaryContainer alwaysLight true, ) ) } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt index c036717..80dcf20 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt @@ -11,10 +11,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.ArrowBack import androidx.compose.material.icons.rounded.DoneAll import androidx.compose.material.icons.rounded.Search -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SmallTopAppBar +import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester @@ -35,6 +32,7 @@ import me.ash.reader.ui.component.FeedbackIconButton import me.ash.reader.ui.component.SwipeRefresh import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.getName +import me.ash.reader.ui.ext.surfaceColorAtElevation import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.FilterState @@ -100,12 +98,16 @@ fun FlowPage( Scaffold( modifier = Modifier - .background(MaterialTheme.colorScheme.surface) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)) .statusBarsPadding() .navigationBarsPadding(), + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp), topBar = { SmallTopAppBar( title = {}, + colors = TopAppBarDefaults.smallTopAppBarColors( + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp), + ), navigationIcon = { FeedbackIconButton( imageVector = Icons.Rounded.ArrowBack, diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt index 0ef4020..b2ef0e3 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt @@ -10,13 +10,14 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import me.ash.reader.ui.ext.surfaceColorAtElevation @Composable fun StickyHeader(currentItemDay: String) { Row( modifier = Modifier .fillMaxWidth() - .background(MaterialTheme.colorScheme.surface), + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)), verticalAlignment = Alignment.CenterVertically ) { Text( From 15b6db52a77d8c2b9790898848a4b99dee518b50 Mon Sep 17 00:00:00 2001 From: Ash Date: Sat, 30 Apr 2022 17:37:06 +0800 Subject: [PATCH 2/6] Add more styles for navigation bar and tonal elevation available --- .../java/me/ash/reader/ui/page/home/FilterBar.kt | 14 +++++++------- .../me/ash/reader/ui/page/home/flow/FlowPage.kt | 12 +++++++----- .../ash/reader/ui/page/home/flow/StickyHeader.kt | 3 ++- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt b/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt index a2f217d..ab3cbb0 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt @@ -11,7 +11,6 @@ import androidx.compose.ui.zIndex import com.google.accompanist.pager.ExperimentalPagerApi import me.ash.reader.data.entity.Filter import me.ash.reader.ui.ext.getName -import me.ash.reader.ui.theme.palette.alwaysLight @OptIn(ExperimentalPagerApi::class) @Composable @@ -23,7 +22,7 @@ fun FilterBar( val view = LocalView.current Box( - modifier = Modifier.height(60.dp) +// modifier = Modifier.height(60.dp) ) { Divider( modifier = Modifier @@ -33,8 +32,8 @@ fun FilterBar( color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.24f) ) NavigationBar( - modifier = Modifier.fillMaxSize(), - tonalElevation = 0.dp, +// modifier = Modifier.fillMaxSize(), +// tonalElevation = 0.dp, ) { Spacer(modifier = Modifier.width(60.dp)) listOf( @@ -49,6 +48,7 @@ fun FilterBar( contentDescription = item.getName() ) }, + label = { Text(text = item.getName(), style = MaterialTheme.typography.labelMedium) }, selected = filter == item, onClick = { // view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) @@ -56,11 +56,11 @@ fun FilterBar( filterOnClick(item) }, colors = NavigationBarItemDefaults.colors( - selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer alwaysLight true, +// selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer alwaysLight true, // unselectedIconColor = MaterialTheme.colorScheme.outline, - selectedTextColor = MaterialTheme.colorScheme.onSurface alwaysLight true, +// selectedTextColor = MaterialTheme.colorScheme.onSurface alwaysLight true, // unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant, - indicatorColor = MaterialTheme.colorScheme.primaryContainer alwaysLight true, +// indicatorColor = MaterialTheme.colorScheme.primaryContainer alwaysLight true, ) ) } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt index c036717..80dcf20 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt @@ -11,10 +11,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.ArrowBack import androidx.compose.material.icons.rounded.DoneAll import androidx.compose.material.icons.rounded.Search -import androidx.compose.material3.ExperimentalMaterial3Api -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.SmallTopAppBar +import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester @@ -35,6 +32,7 @@ import me.ash.reader.ui.component.FeedbackIconButton import me.ash.reader.ui.component.SwipeRefresh import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.getName +import me.ash.reader.ui.ext.surfaceColorAtElevation import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.FilterState @@ -100,12 +98,16 @@ fun FlowPage( Scaffold( modifier = Modifier - .background(MaterialTheme.colorScheme.surface) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)) .statusBarsPadding() .navigationBarsPadding(), + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp), topBar = { SmallTopAppBar( title = {}, + colors = TopAppBarDefaults.smallTopAppBarColors( + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp), + ), navigationIcon = { FeedbackIconButton( imageVector = Icons.Rounded.ArrowBack, diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt index 0ef4020..b2ef0e3 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt @@ -10,13 +10,14 @@ import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import me.ash.reader.ui.ext.surfaceColorAtElevation @Composable fun StickyHeader(currentItemDay: String) { Row( modifier = Modifier .fillMaxWidth() - .background(MaterialTheme.colorScheme.surface), + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)), verticalAlignment = Alignment.CenterVertically ) { Text( From 9bea2e8e8b571da90208a028a3b5cce32ae91fb7 Mon Sep 17 00:00:00 2001 From: Ash Date: Sun, 1 May 2022 06:28:52 +0800 Subject: [PATCH 3/6] Add FlowPage style settings --- .../java/me/ash/reader/data/entity/Filter.kt | 16 +- .../preference/ArticleListDatePreference.kt | 45 +++ .../preference/ArticleListDescPreference.kt | 45 +++ .../ArticleListFeedIconPreference.kt | 45 +++ .../ArticleListFeedNamePreference.kt | 45 +++ .../preference/ArticleListImagePreference.kt | 45 +++ .../ArticleListTonalElevationPreference.kt | 57 +++ .../preference/FilterBarFilledPreference.kt | 45 +++ .../preference/FilterBarPaddingPreference.kt | 29 ++ .../preference/FilterBarStylePreference.kt | 48 +++ .../FilterBarTonalElevationPreference.kt | 57 +++ .../ash/reader/data/preference/Preference.kt | 8 + .../java/me/ash/reader/ui/ext/DataStoreExt.kt | 51 +++ .../java/me/ash/reader/ui/ext/StateFlowExt.kt | 9 +- .../me/ash/reader/ui/page/common/HomeEntry.kt | 15 + .../me/ash/reader/ui/page/common/RouteName.kt | 12 + .../me/ash/reader/ui/page/home/FilterBar.kt | 103 ++++-- .../reader/ui/page/home/feeds/FeedsPage.kt | 5 +- .../reader/ui/page/home/flow/ArticleItem.kt | 124 ++++--- .../reader/ui/page/home/flow/ArticleList.kt | 4 +- .../ash/reader/ui/page/home/flow/FlowPage.kt | 33 +- .../reader/ui/page/home/flow/StickyHeader.kt | 10 +- .../ui/page/settings/color/ColorAndStyle.kt | 8 +- .../settings/color/flow/feedsPageStyle.kt | 346 ++++++++++++++++++ app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 26 files changed, 1098 insertions(+), 111 deletions(-) create mode 100644 app/src/main/java/me/ash/reader/data/preference/ArticleListDatePreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/ArticleListDescPreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/ArticleListFeedIconPreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/ArticleListFeedNamePreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/ArticleListImagePreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/ArticleListTonalElevationPreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/FilterBarFilledPreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/FilterBarPaddingPreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/FilterBarStylePreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/FilterBarTonalElevationPreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/Preference.kt create mode 100644 app/src/main/java/me/ash/reader/ui/page/settings/color/flow/feedsPageStyle.kt diff --git a/app/src/main/java/me/ash/reader/data/entity/Filter.kt b/app/src/main/java/me/ash/reader/data/entity/Filter.kt index ec010e8..738ebca 100644 --- a/app/src/main/java/me/ash/reader/data/entity/Filter.kt +++ b/app/src/main/java/me/ash/reader/data/entity/Filter.kt @@ -2,13 +2,16 @@ package me.ash.reader.data.entity import androidx.compose.material.icons.Icons import androidx.compose.material.icons.outlined.FiberManualRecord +import androidx.compose.material.icons.rounded.FiberManualRecord +import androidx.compose.material.icons.rounded.Star import androidx.compose.material.icons.rounded.StarOutline import androidx.compose.material.icons.rounded.Subject import androidx.compose.ui.graphics.vector.ImageVector class Filter( - var index: Int, - var icon: ImageVector, + val index: Int, + val iconOutline: ImageVector, + val iconFilled: ImageVector, ) { fun isStarred(): Boolean = this == Starred fun isUnread(): Boolean = this == Unread @@ -17,15 +20,18 @@ class Filter( companion object { val Starred = Filter( index = 0, - icon = Icons.Rounded.StarOutline, + iconOutline = Icons.Rounded.StarOutline, + iconFilled = Icons.Rounded.Star, ) val Unread = Filter( index = 1, - icon = Icons.Outlined.FiberManualRecord, + iconOutline = Icons.Outlined.FiberManualRecord, + iconFilled = Icons.Rounded.FiberManualRecord, ) val All = Filter( index = 2, - icon = Icons.Rounded.Subject, + iconOutline = Icons.Rounded.Subject, + iconFilled = Icons.Rounded.Subject, ) } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListDatePreference.kt b/app/src/main/java/me/ash/reader/data/preference/ArticleListDatePreference.kt new file mode 100644 index 0000000..b89720a --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/ArticleListDatePreference.kt @@ -0,0 +1,45 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class ArticleListDatePreference(val value: Boolean) : Preference() { + object ON : ArticleListDatePreference(true) + object OFF : ArticleListDatePreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.ArticleListDate, + value + ) + } + } + + companion object { + val default = ON + val values = listOf(ON, OFF) + + val Context.articleListDate: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.ArticleListDate.key]) { + true -> ON + false -> OFF + else -> default + } + } + } +} + +operator fun ArticleListDatePreference.not(): ArticleListDatePreference = + when (value) { + true -> ArticleListDatePreference.OFF + false -> ArticleListDatePreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListDescPreference.kt b/app/src/main/java/me/ash/reader/data/preference/ArticleListDescPreference.kt new file mode 100644 index 0000000..10dc06a --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/ArticleListDescPreference.kt @@ -0,0 +1,45 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class ArticleListDescPreference(val value: Boolean) : Preference() { + object ON : ArticleListDescPreference(true) + object OFF : ArticleListDescPreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.ArticleListDesc, + value + ) + } + } + + companion object { + val default = ON + val values = listOf(ON, OFF) + + val Context.articleListDesc: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.ArticleListDesc.key]) { + true -> ON + false -> OFF + else -> default + } + } + } +} + +operator fun ArticleListDescPreference.not(): ArticleListDescPreference = + when (value) { + true -> ArticleListDescPreference.OFF + false -> ArticleListDescPreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListFeedIconPreference.kt b/app/src/main/java/me/ash/reader/data/preference/ArticleListFeedIconPreference.kt new file mode 100644 index 0000000..796aa61 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/ArticleListFeedIconPreference.kt @@ -0,0 +1,45 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class ArticleListFeedIconPreference(val value: Boolean) : Preference() { + object ON : ArticleListFeedIconPreference(true) + object OFF : ArticleListFeedIconPreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.ArticleListFeedIcon, + value + ) + } + } + + companion object { + val default = ON + val values = listOf(ON, OFF) + + val Context.articleListFeedIcon: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.ArticleListFeedIcon.key]) { + true -> ON + false -> OFF + else -> default + } + } + } +} + +operator fun ArticleListFeedIconPreference.not(): ArticleListFeedIconPreference = + when (value) { + true -> ArticleListFeedIconPreference.OFF + false -> ArticleListFeedIconPreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListFeedNamePreference.kt b/app/src/main/java/me/ash/reader/data/preference/ArticleListFeedNamePreference.kt new file mode 100644 index 0000000..9269d4b --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/ArticleListFeedNamePreference.kt @@ -0,0 +1,45 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class ArticleListFeedNamePreference(val value: Boolean) : Preference() { + object ON : ArticleListFeedNamePreference(true) + object OFF : ArticleListFeedNamePreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.ArticleListFeedName, + value + ) + } + } + + companion object { + val default = ON + val values = listOf(ON, OFF) + + val Context.articleListFeedName: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.ArticleListFeedName.key]) { + true -> ON + false -> OFF + else -> default + } + } + } +} + +operator fun ArticleListFeedNamePreference.not(): ArticleListFeedNamePreference = + when (value) { + true -> ArticleListFeedNamePreference.OFF + false -> ArticleListFeedNamePreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListImagePreference.kt b/app/src/main/java/me/ash/reader/data/preference/ArticleListImagePreference.kt new file mode 100644 index 0000000..06bdde6 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/ArticleListImagePreference.kt @@ -0,0 +1,45 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class ArticleListImagePreference(val value: Boolean) : Preference() { + object ON : ArticleListImagePreference(true) + object OFF : ArticleListImagePreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.ArticleListImage, + value + ) + } + } + + companion object { + val default = ON + val values = listOf(ON, OFF) + + val Context.articleListImage: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.ArticleListImage.key]) { + true -> ON + false -> OFF + else -> default + } + } + } +} + +operator fun ArticleListImagePreference.not(): ArticleListImagePreference = + when (value) { + true -> ArticleListImagePreference.OFF + false -> ArticleListImagePreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/ArticleListTonalElevationPreference.kt new file mode 100644 index 0000000..79a862a --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/ArticleListTonalElevationPreference.kt @@ -0,0 +1,57 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class ArticleListTonalElevationPreference(val value: Int) : Preference() { + object Level0 : ArticleListTonalElevationPreference(0) + object Level1 : ArticleListTonalElevationPreference(1) + object Level2 : ArticleListTonalElevationPreference(3) + object Level3 : ArticleListTonalElevationPreference(6) + object Level4 : ArticleListTonalElevationPreference(8) + object Level5 : ArticleListTonalElevationPreference(12) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.ArticleListTonalElevation, + value + ) + } + } + + fun getDesc(context: Context): String = + when (this) { + Level0 -> "Level 0 (0dp)" + Level1 -> "Level 1 (1dp)" + Level2 -> "Level 2 (3dp)" + Level3 -> "Level 3 (6dp)" + Level4 -> "Level 4 (8dp)" + Level5 -> "Level 5 (12dp)" + } + + companion object { + val default = Level0 + val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) + + val Context.articleListTonalElevation: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.ArticleListTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FilterBarFilledPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FilterBarFilledPreference.kt new file mode 100644 index 0000000..c6265da --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FilterBarFilledPreference.kt @@ -0,0 +1,45 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FilterBarFilledPreference(val value: Boolean) : Preference() { + object ON : FilterBarFilledPreference(true) + object OFF : FilterBarFilledPreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FilterBarFilled, + value + ) + } + } + + companion object { + val default = OFF + val values = listOf(ON, OFF) + + val Context.filterBarFilled: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FilterBarFilled.key]) { + true -> ON + false -> OFF + else -> default + } + } + } +} + +operator fun FilterBarFilledPreference.not(): FilterBarFilledPreference = + when (value) { + true -> FilterBarFilledPreference.OFF + false -> FilterBarFilledPreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FilterBarPaddingPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FilterBarPaddingPreference.kt new file mode 100644 index 0000000..516453f --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FilterBarPaddingPreference.kt @@ -0,0 +1,29 @@ +package me.ash.reader.data.preference + +import android.content.Context +import android.util.Log +import androidx.compose.runtime.Immutable +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +@Immutable +object FilterBarPaddingPreference { + const val default = 0 + + val Context.filterBarPadding: Flow + get() = this.dataStore.data.map { + it[DataStoreKeys.FilterBarPadding.key] ?: 0 + } + + fun put(context: Context, scope: CoroutineScope, value: Int) { + scope.launch(Dispatchers.IO) { + context.dataStore.put(DataStoreKeys.FilterBarPadding, value) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FilterBarStylePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FilterBarStylePreference.kt new file mode 100644 index 0000000..50e6c7b --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FilterBarStylePreference.kt @@ -0,0 +1,48 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FilterBarStylePreference(val value: Int) : Preference() { + object Icon : FilterBarStylePreference(0) + object IconLabel : FilterBarStylePreference(1) + object IconLabelOnlySelected : FilterBarStylePreference(2) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FilterBarStyle, + value + ) + } + } + + fun getDesc(context: Context): String = + when (this) { + Icon -> "图标" + IconLabel -> "图标 + 标签" + IconLabelOnlySelected -> "图标 + 标签(仅选中时)" + } + + companion object { + val default = Icon + val values = listOf(Icon, IconLabel, IconLabelOnlySelected) + + val Context.filterBarStyle: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FilterBarStyle.key]) { + 0 -> Icon + 1 -> IconLabel + 2 -> IconLabelOnlySelected + else -> default + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FilterBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FilterBarTonalElevationPreference.kt new file mode 100644 index 0000000..6c6fced --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FilterBarTonalElevationPreference.kt @@ -0,0 +1,57 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FilterBarTonalElevationPreference(val value: Int) : Preference() { + object Level0 : FilterBarTonalElevationPreference(0) + object Level1 : FilterBarTonalElevationPreference(1) + object Level2 : FilterBarTonalElevationPreference(3) + object Level3 : FilterBarTonalElevationPreference(6) + object Level4 : FilterBarTonalElevationPreference(8) + object Level5 : FilterBarTonalElevationPreference(12) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FilterBarTonalElevation, + value + ) + } + } + + fun getDesc(context: Context): String = + when (this) { + Level0 -> "Level 0 (0dp)" + Level1 -> "Level 1 (1dp)" + Level2 -> "Level 2 (3dp)" + Level3 -> "Level 3 (6dp)" + Level4 -> "Level 4 (8dp)" + Level5 -> "Level 5 (12dp)" + } + + companion object { + val default = Level0 + val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) + + val Context.filterBarTonalElevation: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FilterBarTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/Preference.kt b/app/src/main/java/me/ash/reader/data/preference/Preference.kt new file mode 100644 index 0000000..cd451da --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/Preference.kt @@ -0,0 +1,8 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope + +sealed class Preference { + abstract fun put(context: Context, scope: CoroutineScope) +} \ No newline at end of file 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 52d749c..0dd5463 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 @@ -33,6 +33,7 @@ val Context.currentAccountType: Int get() = this.dataStore.get(DataStoreKeys.CurrentAccountType)!! val Context.themeIndex: Int get() = this.dataStore.get(DataStoreKeys.ThemeIndex) ?: 5 + val Context.customPrimaryColor: String get() = this.dataStore.get(DataStoreKeys.CustomPrimaryColor) ?: "" val Context.initialPage: Int @@ -129,6 +130,56 @@ sealed class DataStoreKeys { get() = stringPreferencesKey("customPrimaryColor") } + object FilterBarStyle : DataStoreKeys() { + override val key: Preferences.Key + get() = intPreferencesKey("filterBarStyle") + } + + object FilterBarFilled : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("filterBarFilled") + } + + object FilterBarPadding : DataStoreKeys() { + override val key: Preferences.Key + get() = intPreferencesKey("filterBarPadding") + } + + object FilterBarTonalElevation : DataStoreKeys() { + override val key: Preferences.Key + get() = intPreferencesKey("filterBarTonalElevation") + } + + object ArticleListFeedIcon : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("articleListFeedIcon") + } + + object ArticleListFeedName : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("articleListFeedName") + } + + object ArticleListImage : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("articleListImage") + } + + object ArticleListDesc : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("articleListDesc") + } + + object ArticleListDate : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("articleListDate") + } + + object ArticleListTonalElevation : DataStoreKeys() { + override val key: Preferences.Key + get() = intPreferencesKey("articleListTonalElevation") + } + object InitialPage : DataStoreKeys() { override val key: Preferences.Key get() = intPreferencesKey("initialPage") diff --git a/app/src/main/java/me/ash/reader/ui/ext/StateFlowExt.kt b/app/src/main/java/me/ash/reader/ui/ext/StateFlowExt.kt index 28ec720..f968cf5 100644 --- a/app/src/main/java/me/ash/reader/ui/ext/StateFlowExt.kt +++ b/app/src/main/java/me/ash/reader/ui/ext/StateFlowExt.kt @@ -3,10 +3,17 @@ package me.ash.reader.ui.ext import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlin.coroutines.CoroutineContext @Composable fun StateFlow.collectAsStateValue( context: CoroutineContext = Dispatchers.Default -): T = collectAsState(context).value \ No newline at end of file +): T = collectAsState(context).value + +@Composable +fun Flow.collectAsStateValue( + initial: R, + context: CoroutineContext = Dispatchers.Default +): R = collectAsState(initial, context).value \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt index bd33513..8d8208e 100644 --- a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt +++ b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt @@ -22,6 +22,7 @@ import me.ash.reader.ui.page.home.flow.FlowPage import me.ash.reader.ui.page.home.read.ReadPage import me.ash.reader.ui.page.settings.SettingsPage import me.ash.reader.ui.page.settings.color.ColorAndStyle +import me.ash.reader.ui.page.settings.color.flow.FlowPageStyle import me.ash.reader.ui.page.settings.interaction.Interaction import me.ash.reader.ui.page.settings.tips.TipsAndSupport import me.ash.reader.ui.page.startup.StartupPage @@ -97,9 +98,12 @@ fun HomeEntry( navController = navController, startDestination = if (context.isFirstLaunch) RouteName.STARTUP else RouteName.FEEDS, ) { + // Startup animatedComposable(route = RouteName.STARTUP) { StartupPage(navController) } + + // Home animatedComposable(route = RouteName.FEEDS) { FeedsPage(navController = navController, homeViewModel = homeViewModel) } @@ -113,15 +117,26 @@ fun HomeEntry( animatedComposable(route = "${RouteName.READING}/{articleId}") { ReadPage(navController = navController) } + + // Settings animatedComposable(route = RouteName.SETTINGS) { SettingsPage(navController) } + + // Color & Style animatedComposable(route = RouteName.COLOR_AND_STYLE) { ColorAndStyle(navController) } + animatedComposable(route = RouteName.FLOW_PAGE_STYLE) { + FlowPageStyle(navController) + } + + // Interaction animatedComposable(route = RouteName.INTERACTION) { Interaction(navController) } + + // Tips & Support animatedComposable(route = RouteName.TIPS_AND_SUPPORT) { TipsAndSupport(navController) } diff --git a/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt b/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt index aa4accb..51aba6a 100644 --- a/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt +++ b/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt @@ -1,12 +1,24 @@ package me.ash.reader.ui.page.common object RouteName { + // Startup const val STARTUP = "startup" + + // Home const val FEEDS = "feeds" const val FLOW = "flow" const val READING = "reading" + + // Settings const val SETTINGS = "settings" + + // Color & Style const val COLOR_AND_STYLE = "color_and_style" + const val FLOW_PAGE_STYLE = "flow_page_style" + + // Interaction const val INTERACTION = "interaction" + + // Tips & Support const val TIPS_AND_SUPPORT = "tips_and_support" } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt b/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt index ab3cbb0..341d4fb 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt @@ -1,16 +1,27 @@ package me.ash.reader.ui.page.home import android.view.SoundEffectConstants -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.width import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex import com.google.accompanist.pager.ExperimentalPagerApi import me.ash.reader.data.entity.Filter +import me.ash.reader.data.preference.FilterBarFilledPreference +import me.ash.reader.data.preference.FilterBarFilledPreference.Companion.filterBarFilled +import me.ash.reader.data.preference.FilterBarPaddingPreference +import me.ash.reader.data.preference.FilterBarPaddingPreference.filterBarPadding +import me.ash.reader.data.preference.FilterBarStylePreference +import me.ash.reader.data.preference.FilterBarStylePreference.Companion.filterBarStyle +import me.ash.reader.data.preference.FilterBarTonalElevationPreference +import me.ash.reader.data.preference.FilterBarTonalElevationPreference.Companion.filterBarTonalElevation +import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.getName +import me.ash.reader.ui.theme.palette.onDark @OptIn(ExperimentalPagerApi::class) @Composable @@ -20,51 +31,67 @@ fun FilterBar( filterOnClick: (Filter) -> Unit = {}, ) { val view = LocalView.current + val context = LocalContext.current + val filterBarStyle = + context.filterBarStyle.collectAsStateValue(initial = FilterBarStylePreference.default) + val filterBarFilled = + context.filterBarFilled.collectAsStateValue(initial = FilterBarFilledPreference.default) + val filterBarPadding = + context.filterBarPadding.collectAsStateValue(initial = FilterBarPaddingPreference.default) + val filterBarTonalElevation = + context.filterBarTonalElevation.collectAsStateValue(initial = FilterBarTonalElevationPreference.default) - Box( -// modifier = Modifier.height(60.dp) + NavigationBar( + tonalElevation = filterBarTonalElevation.value.dp, ) { - Divider( - modifier = Modifier - .fillMaxWidth() - .height(1.dp) - .zIndex(1f), - color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.24f) - ) - NavigationBar( -// modifier = Modifier.fillMaxSize(), -// tonalElevation = 0.dp, - ) { - Spacer(modifier = Modifier.width(60.dp)) - listOf( - Filter.Starred, - Filter.Unread, - Filter.All, - ).forEach { item -> - NavigationBarItem( - icon = { - Icon( - imageVector = item.icon, - contentDescription = item.getName() + Spacer(modifier = Modifier.width(filterBarPadding.dp)) + listOf( + Filter.Starred, + Filter.Unread, + Filter.All, + ).forEach { item -> + NavigationBarItem( +// modifier = Modifier.height(60.dp), + alwaysShowLabel = when (filterBarStyle) { + is FilterBarStylePreference.Icon -> false + is FilterBarStylePreference.IconLabel -> true + is FilterBarStylePreference.IconLabelOnlySelected -> false + }, + icon = { + Icon( + imageVector = if (filter == item && filterBarFilled.value) { + item.iconFilled + } else { + item.iconOutline + }, + contentDescription = item.getName() + ) + }, + label = if (filterBarStyle is FilterBarStylePreference.Icon) { + null + } else { + { + Text( + text = item.getName(), + style = MaterialTheme.typography.labelLarge ) - }, - label = { Text(text = item.getName(), style = MaterialTheme.typography.labelMedium) }, - selected = filter == item, - onClick = { + } + }, + selected = filter == item, + onClick = { // view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) - view.playSoundEffect(SoundEffectConstants.CLICK) - filterOnClick(item) - }, - colors = NavigationBarItemDefaults.colors( + view.playSoundEffect(SoundEffectConstants.CLICK) + filterOnClick(item) + }, + colors = NavigationBarItemDefaults.colors( // selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer alwaysLight true, // unselectedIconColor = MaterialTheme.colorScheme.outline, // selectedTextColor = MaterialTheme.colorScheme.onSurface alwaysLight true, // unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant, -// indicatorColor = MaterialTheme.colorScheme.primaryContainer alwaysLight true, - ) + indicatorColor = MaterialTheme.colorScheme.primaryContainer onDark MaterialTheme.colorScheme.secondaryContainer, ) - } - Spacer(modifier = Modifier.width(60.dp)) + ) } + Spacer(modifier = Modifier.width(filterBarPadding.dp)) } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt index d13ffa3..e9bc7f0 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt @@ -174,7 +174,7 @@ fun FeedsPage( Banner( title = filterState.filter.getName(), desc = feedsViewState.importantCount, - icon = filterState.filter.icon, + icon = filterState.filter.iconOutline, action = { Icon( imageVector = Icons.Outlined.KeyboardArrowRight, @@ -241,9 +241,6 @@ fun FeedsPage( }, bottomBar = { FilterBar( - modifier = Modifier - .height(60.dp) - .fillMaxWidth(), filter = filterState.filter, filterOnClick = { filterChange( 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 10e569e..640cb8d 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 @@ -21,6 +21,13 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import me.ash.reader.R import me.ash.reader.data.entity.ArticleWithFeed +import me.ash.reader.data.preference.* +import me.ash.reader.data.preference.ArticleListDatePreference.Companion.articleListDate +import me.ash.reader.data.preference.ArticleListDescPreference.Companion.articleListDesc +import me.ash.reader.data.preference.ArticleListFeedIconPreference.Companion.articleListFeedIcon +import me.ash.reader.data.preference.ArticleListFeedNamePreference.Companion.articleListFeedName +import me.ash.reader.data.preference.ArticleListImagePreference.Companion.articleListImage +import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.formatAsString @Composable @@ -30,6 +37,16 @@ fun ArticleItem( onClick: (ArticleWithFeed) -> Unit = {}, ) { val context = LocalContext.current + val articleListFeedIcon = + context.articleListFeedIcon.collectAsStateValue(initial = ArticleListFeedIconPreference.default) + val articleListFeedName = + context.articleListFeedName.collectAsStateValue(initial = ArticleListFeedNamePreference.default) + val articleListImage = + context.articleListImage.collectAsStateValue(initial = ArticleListImagePreference.default) + val articleListDesc = + context.articleListDesc.collectAsStateValue(initial = ArticleListDescPreference.default) + val articleListDate = + context.articleListDate.collectAsStateValue(initial = ArticleListDatePreference.default) Column( modifier = Modifier @@ -44,67 +61,84 @@ fun ArticleItem( horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically, ) { - Text( - modifier = Modifier - .weight(1f) - .padding(start = 30.dp), - text = articleWithFeed.feed.name, - color = MaterialTheme.colorScheme.tertiary, - style = MaterialTheme.typography.labelMedium, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - ) - Row( - modifier = Modifier.padding(start = 6.dp), - verticalAlignment = Alignment.CenterVertically, - ) { - if (articleWithFeed.article.isStarred) { - Icon( - modifier = Modifier - .size(14.dp) - .padding(end = 2.dp), - imageVector = Icons.Rounded.Star, - contentDescription = stringResource(R.string.starred), - tint = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f), + // Feed name + if (articleListFeedName.value) { + Text( + modifier = Modifier + .weight(1f) + .padding(start = if (articleListFeedIcon.value) 30.dp else 0.dp), + text = articleWithFeed.feed.name, + color = MaterialTheme.colorScheme.tertiary, + style = MaterialTheme.typography.labelMedium, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + ) + } + + if (articleListDate.value) { + Row( + modifier = Modifier.padding(start = 6.dp), + verticalAlignment = Alignment.CenterVertically, + ) { + // Starred + if (articleWithFeed.article.isStarred) { + Icon( + modifier = Modifier + .size(14.dp) + .padding(end = 2.dp), + imageVector = Icons.Rounded.Star, + contentDescription = stringResource(R.string.starred), + tint = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f), + ) + } + + // Date + Text( + text = articleWithFeed.article.date.formatAsString( + context, + onlyHourMinute = true + ), + color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f), + style = MaterialTheme.typography.labelMedium, ) } - Text( - text = articleWithFeed.article.date.formatAsString( - context, - onlyHourMinute = true - ), - color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f), - style = MaterialTheme.typography.labelMedium, - ) } } Row( modifier = Modifier.fillMaxWidth(), ) { - Row( - modifier = Modifier - .size(20.dp) - .clip(CircleShape) - .background(MaterialTheme.colorScheme.outline.copy(alpha = 0.2f)) - ) {} - Spacer(modifier = Modifier.width(10.dp)) + // Feed icon + if (articleListFeedIcon.value) { + Row( + modifier = Modifier + .size(20.dp) + .clip(CircleShape) + .background(MaterialTheme.colorScheme.outline.copy(alpha = 0.2f)) + ) {} + Spacer(modifier = Modifier.width(10.dp)) + } + // Article Column( modifier = Modifier.fillMaxWidth(), ) { + // Title Text( text = articleWithFeed.article.title, color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.titleMedium, - maxLines = 2, - overflow = TextOverflow.Ellipsis, - ) - Text( - text = articleWithFeed.article.shortDescription, - color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f), - style = MaterialTheme.typography.bodySmall, - maxLines = 2, + maxLines = if (articleListDesc.value) 2 else 4, overflow = TextOverflow.Ellipsis, ) + // Description + if (articleListDesc.value) { + Text( + text = articleWithFeed.article.shortDescription, + color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f), + style = MaterialTheme.typography.bodySmall, + maxLines = 2, + overflow = TextOverflow.Ellipsis, + ) + } } } } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt index c1cd135..2d4f736 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt @@ -13,6 +13,8 @@ import me.ash.reader.data.entity.ArticleWithFeed @OptIn(ExperimentalFoundationApi::class) fun LazyListScope.ArticleList( pagingItems: LazyPagingItems, + articleListFeedIcon: Boolean, + articleListTonalElevation: Int, onClick: (ArticleWithFeed) -> Unit = {}, ) { for (index in 0 until pagingItems.itemCount) { @@ -30,7 +32,7 @@ fun LazyListScope.ArticleList( val separator = pagingItems[index] as FlowItemView.Date if (separator.showSpacer) item { Spacer(modifier = Modifier.height(40.dp)) } stickyHeader { - StickyHeader(separator.date) + StickyHeader(separator.date, articleListFeedIcon, articleListTonalElevation) } } else -> {} diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt index 80dcf20..678cdbd 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt @@ -15,6 +15,7 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource @@ -26,6 +27,10 @@ import androidx.paging.compose.LazyPagingItems import kotlinx.coroutines.delay import kotlinx.coroutines.launch import me.ash.reader.R +import me.ash.reader.data.preference.ArticleListFeedIconPreference +import me.ash.reader.data.preference.ArticleListFeedIconPreference.Companion.articleListFeedIcon +import me.ash.reader.data.preference.ArticleListTonalElevationPreference +import me.ash.reader.data.preference.ArticleListTonalElevationPreference.Companion.articleListTonalElevation import me.ash.reader.data.repository.SyncWorker.Companion.getIsSyncing import me.ash.reader.ui.component.DisplayText import me.ash.reader.ui.component.FeedbackIconButton @@ -52,6 +57,7 @@ fun FlowPage( homeViewModel: HomeViewModel, pagingItems: LazyPagingItems, ) { + val context = LocalContext.current val keyboardController = LocalSoftwareKeyboardController.current val scope = rememberCoroutineScope() @@ -64,6 +70,11 @@ fun FlowPage( val homeViewState = homeViewModel.viewState.collectAsStateValue() val listState = if (pagingItems.itemCount > 0) viewState.listState else rememberLazyListState() + val articleListTonalElevation = + context.articleListTonalElevation.collectAsStateValue(initial = ArticleListTonalElevationPreference.default) + val articleListFeedIcon = + context.articleListFeedIcon.collectAsStateValue(initial = ArticleListFeedIconPreference.default) + val owner = LocalLifecycleOwner.current var isSyncing by remember { mutableStateOf(false) } homeViewModel.syncWorkLiveData.observe(owner) { @@ -98,15 +109,17 @@ fun FlowPage( Scaffold( modifier = Modifier - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp)) .statusBarsPadding() .navigationBarsPadding(), - containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp), + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp), topBar = { SmallTopAppBar( title = {}, colors = TopAppBarDefaults.smallTopAppBarColors( - containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp), + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( + articleListTonalElevation.value.dp + ), ), navigationIcon = { FeedbackIconButton( @@ -115,7 +128,7 @@ fun FlowPage( tint = MaterialTheme.colorScheme.onSurface ) { onSearch = false - if(navController.previousBackStackEntry == null) { + if (navController.previousBackStackEntry == null) { navController.navigate(RouteName.FEEDS) { launchSingleTop = true } @@ -184,7 +197,7 @@ fun FlowPage( state = listState, ) { item { - DisplayTextHeader(filterState, isSyncing) + DisplayTextHeader(filterState, isSyncing, articleListFeedIcon.value) AnimatedVisibility( visible = markAsRead, enter = fadeIn() + expandVertically(), @@ -246,6 +259,8 @@ fun FlowPage( } ArticleList( pagingItems = pagingItems, + articleListFeedIcon = articleListFeedIcon.value, + articleListTonalElevation = articleListTonalElevation.value, ) { onSearch = false navController.navigate("${RouteName.READING}/${it.article.id}") { @@ -263,9 +278,6 @@ fun FlowPage( }, bottomBar = { FilterBar( - modifier = Modifier - .height(60.dp) - .fillMaxWidth(), filter = filterState.filter, filterOnClick = { flowViewModel.dispatch(FlowViewAction.ScrollToItem(0)) @@ -280,10 +292,11 @@ fun FlowPage( @Composable private fun DisplayTextHeader( filterState: FilterState, - isSyncing: Boolean + isSyncing: Boolean, + articleListFeedIcon: Boolean, ) { DisplayText( - modifier = Modifier.padding(start = 30.dp), + modifier = Modifier.padding(start = if (articleListFeedIcon) 30.dp else 0.dp), text = when { filterState.group != null -> filterState.group.name filterState.feed != null -> filterState.feed.name diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt index b2ef0e3..93125e0 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt @@ -13,16 +13,20 @@ import androidx.compose.ui.unit.dp import me.ash.reader.ui.ext.surfaceColorAtElevation @Composable -fun StickyHeader(currentItemDay: String) { +fun StickyHeader( + currentItemDay: String, + articleListFeedIcon: Boolean, + articleListTonalElevation: Int, +) { Row( modifier = Modifier .fillMaxWidth() - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)), + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.dp)), verticalAlignment = Alignment.CenterVertically ) { Text( modifier = Modifier - .padding(start = if (true) 54.dp else 24.dp, bottom = 4.dp), + .padding(start = if (articleListFeedIcon) 54.dp else 24.dp, bottom = 4.dp), text = currentItemDay, color = MaterialTheme.colorScheme.primary, style = MaterialTheme.typography.labelLarge, diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt index e3ba114..55e491b 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt @@ -30,6 +30,7 @@ import kotlinx.coroutines.launch import me.ash.reader.R import me.ash.reader.ui.component.* import me.ash.reader.ui.ext.* +import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.settings.SettingItem import me.ash.reader.ui.svg.PALETTE import me.ash.reader.ui.svg.SVGString @@ -167,8 +168,11 @@ fun ColorAndStyle( ) {} SettingItem( title = stringResource(R.string.flow_page), - enable = false, - onClick = {}, + onClick = { + navController.navigate(RouteName.FLOW_PAGE_STYLE) { + launchSingleTop = true + } + }, ) {} SettingItem( title = stringResource(R.string.reading_page), diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/feedsPageStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/feedsPageStyle.kt new file mode 100644 index 0000000..ab04904 --- /dev/null +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/feedsPageStyle.kt @@ -0,0 +1,346 @@ +package me.ash.reader.ui.page.settings.color.flow + +import android.annotation.SuppressLint +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.ArrowBack +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController +import me.ash.reader.R +import me.ash.reader.data.entity.Article +import me.ash.reader.data.entity.ArticleWithFeed +import me.ash.reader.data.entity.Feed +import me.ash.reader.data.entity.Filter +import me.ash.reader.data.preference.* +import me.ash.reader.data.preference.ArticleListDatePreference.Companion.articleListDate +import me.ash.reader.data.preference.ArticleListDescPreference.Companion.articleListDesc +import me.ash.reader.data.preference.ArticleListFeedIconPreference.Companion.articleListFeedIcon +import me.ash.reader.data.preference.ArticleListFeedNamePreference.Companion.articleListFeedName +import me.ash.reader.data.preference.ArticleListImagePreference.Companion.articleListImage +import me.ash.reader.data.preference.ArticleListTonalElevationPreference.Companion.articleListTonalElevation +import me.ash.reader.data.preference.FilterBarFilledPreference.Companion.filterBarFilled +import me.ash.reader.data.preference.FilterBarPaddingPreference.filterBarPadding +import me.ash.reader.data.preference.FilterBarStylePreference.Companion.filterBarStyle +import me.ash.reader.data.preference.FilterBarTonalElevationPreference.Companion.filterBarTonalElevation +import me.ash.reader.ui.component.* +import me.ash.reader.ui.ext.collectAsStateValue +import me.ash.reader.ui.ext.surfaceColorAtElevation +import me.ash.reader.ui.page.home.FilterBar +import me.ash.reader.ui.page.home.flow.ArticleItem +import me.ash.reader.ui.page.settings.SettingItem +import me.ash.reader.ui.theme.palette.onLight +import java.util.* + +@SuppressLint("FlowOperatorInvokedInComposition") +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun FlowPageStyle( + navController: NavHostController, +) { + val context = LocalContext.current + val scope = rememberCoroutineScope() + val filterBarStyle = + context.filterBarStyle.collectAsStateValue(initial = FilterBarStylePreference.default) + val filterBarFilled = + context.filterBarFilled.collectAsStateValue(initial = FilterBarFilledPreference.default) + val filterBarPadding = + context.filterBarPadding.collectAsStateValue(initial = FilterBarPaddingPreference.default) + val filterBarTonalElevation = + context.filterBarTonalElevation.collectAsStateValue(initial = FilterBarTonalElevationPreference.default) + val articleListFeedIcon = + context.articleListFeedIcon.collectAsStateValue(initial = ArticleListFeedIconPreference.default) + val articleListFeedName = + context.articleListFeedName.collectAsStateValue(initial = ArticleListFeedNamePreference.default) + val articleListImage = + context.articleListImage.collectAsStateValue(initial = ArticleListImagePreference.default) + val articleListDesc = + context.articleListDesc.collectAsStateValue(initial = ArticleListDescPreference.default) + val articleListDate = + context.articleListDate.collectAsStateValue(initial = ArticleListDatePreference.default) + val articleListTonalElevation = + context.articleListTonalElevation.collectAsStateValue(initial = ArticleListTonalElevationPreference.default) + + var filterBarStyleDialogVisible by remember { mutableStateOf(false) } + var filterBarPaddingDialogVisible by remember { mutableStateOf(false) } + var filterBarTonalElevationDialogVisible by remember { mutableStateOf(false) } + var articleListTonalElevationDialogVisible by remember { mutableStateOf(false) } + + var filterBarPaddingValue: Int? by remember { mutableStateOf(filterBarPadding) } + + Scaffold( + modifier = Modifier + .background(MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface) + .statusBarsPadding() + .navigationBarsPadding(), + containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface, + topBar = { + SmallTopAppBar( + colors = TopAppBarDefaults.smallTopAppBarColors( + containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface + ), + title = {}, + navigationIcon = { + FeedbackIconButton( + imageVector = Icons.Rounded.ArrowBack, + contentDescription = stringResource(R.string.back), + tint = MaterialTheme.colorScheme.onSurface + ) { + navController.popBackStack() + } + }, + actions = {} + ) + }, + content = { + LazyColumn { + item { + DisplayText(text = stringResource(R.string.flow_page), desc = "") + } + item { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp) + .clip(RoundedCornerShape(24.dp)) + .background( + MaterialTheme.colorScheme.inverseOnSurface + onLight MaterialTheme.colorScheme.surface.copy(0.7f) + ) + .clickable { }, + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + FeedsPagePreview(articleListTonalElevation) + } + Spacer(modifier = Modifier.height(24.dp)) + } + item { + Subtitle( + modifier = Modifier.padding(horizontal = 24.dp), + text = "过滤栏", + ) + SettingItem( + title = "样式", + desc = filterBarStyle.getDesc(context), + onClick = { + filterBarStyleDialogVisible = true + }, + ) {} + SettingItem( + title = "填充已选中的图标", + onClick = { + (!filterBarFilled).put(context, scope) + }, + ) { + Switch(activated = filterBarFilled.value) { + (!filterBarFilled).put(context, scope) + } + } + SettingItem( + title = "两端边距", + desc = "${filterBarPadding}dp", + onClick = { + filterBarPaddingDialogVisible = true + }, + ) {} + SettingItem( + title = "色调海拔", + desc = "${filterBarTonalElevation.value}dp", + onClick = { + filterBarTonalElevationDialogVisible = true + }, + ) {} + Spacer(modifier = Modifier.height(24.dp)) + } + item { + Subtitle( + modifier = Modifier.padding(horizontal = 24.dp), + text = "标题栏" + ) + SettingItem( + title = "“标记为已读”按钮的位置", + desc = "顶部", + onClick = {}, + ) {} + Spacer(modifier = Modifier.height(24.dp)) + } + item { + Subtitle( + modifier = Modifier.padding(horizontal = 24.dp), + text = "文章列表" + ) + SettingItem( + title = "显示订阅源图标", + onClick = { + (!articleListFeedIcon).put(context, scope) + }, + ) { + Switch(activated = articleListFeedIcon.value) { + (!articleListFeedIcon).put(context, scope) + } + } + SettingItem( + title = "显示订阅源名称", + onClick = { + (!articleListFeedName).put(context, scope) + }, + ) { + Switch(activated = articleListFeedName.value) { + (!articleListFeedName).put(context, scope) + } + } + SettingItem( + title = "显示文章插图", + onClick = {}, + ) { + Switch(activated = false, enable = false) + } + SettingItem( + title = "显示文章描述", + onClick = { + (!articleListDesc).put(context, scope) + }, + ) { + Switch(activated = articleListDesc.value) { + (!articleListDesc).put(context, scope) + } + } + SettingItem( + title = "显示文章发布时间", + onClick = { + (!articleListDate).put(context, scope) + }, + ) { + Switch(activated = articleListDate.value) { + (!articleListDate).put(context, scope) + } + } + SettingItem( + title = "色调海拔", + desc = "${articleListTonalElevation.value}dp", + onClick = { + articleListTonalElevationDialogVisible = true + }, + ) {} + Spacer(modifier = Modifier.height(24.dp)) + } + } + } + ) + + RadioDialog( + visible = filterBarStyleDialogVisible, + title = stringResource(R.string.initial_filter), + options = FilterBarStylePreference.values.map { + RadioDialogOption( + text = it.getDesc(context), + selected = filterBarStyle == it, + ) { + it.put(context, scope) + } + } + ) { + filterBarStyleDialogVisible = false + } + + TextFieldDialog( + visible = filterBarPaddingDialogVisible, + title = "两端边距", + value = (filterBarPaddingValue ?: "").toString(), + placeholder = stringResource(R.string.name), + onValueChange = { + filterBarPaddingValue = it.toIntOrNull() + }, + onDismissRequest = { + filterBarPaddingDialogVisible = false + }, + onConfirm = { + FilterBarPaddingPreference.put(context, scope, filterBarPaddingValue ?: 0) + filterBarPaddingDialogVisible = false + } + ) + + RadioDialog( + visible = filterBarTonalElevationDialogVisible, + title = stringResource(R.string.tonal_elevation), + options = FilterBarTonalElevationPreference.values.map { + RadioDialogOption( + text = it.getDesc(context), + selected = filterBarTonalElevation == it, + ) { + it.put(context, scope) + } + } + ) { + filterBarTonalElevationDialogVisible = false + } + + RadioDialog( + visible = articleListTonalElevationDialogVisible, + title = stringResource(R.string.tonal_elevation), + options = ArticleListTonalElevationPreference.values.map { + RadioDialogOption( + text = it.getDesc(context), + selected = articleListTonalElevation == it, + ) { + it.put(context, scope) + } + } + ) { + articleListTonalElevationDialogVisible = false + } +} + +@Composable +fun FeedsPagePreview( + articleListTonalElevation: ArticleListTonalElevationPreference, +) { + var filter by remember { mutableStateOf(Filter.Unread) } + + Column( + modifier = Modifier + .background( + color = MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp), + shape = RoundedCornerShape(24.dp) + ) + ) { + Spacer(modifier = Modifier.height(12.dp)) + ArticleItem( + articleWithFeed = ArticleWithFeed( + Article( + id = "", + title = "《黎明之剑》撒花完结,白金远瞳的“希灵三部曲”值得你通宵阅读", + shortDescription = "昨日在找书的时候无意间发现,“远瞳”的《黎明之剑》突然冲上了起点热搜榜首位,去小说中查找原因,原来是这部六百多万字的作品已经完结了。四年的时间,这部小说始终占据科幻分类前三甲的位置,不得不说“远瞳”的实力的确不容小觑。", + rawDescription = "昨日在找书的时候无意间发现,“远瞳”的《黎明之剑》突然冲上了起点热搜榜首位,去小说中查找原因,原来是这部六百多万字的作品已经完结了。四年的时间,这部小说始终占据科幻分类前三甲的位置,不得不说“远瞳”的实力的确不容小觑。", + link = "", + feedId = "", + accountId = 0, + date = Date(), + ), + feed = Feed( + id = "", + name = "佛门射手", + icon = "", + accountId = 0, + groupId = "", + url = "", + ) + ) + ) + Spacer(modifier = Modifier.height(12.dp)) + FilterBar(modifier = Modifier.padding(horizontal = 12.dp), filter = filter) { + filter = it + } + } +} \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 84ffc0d..5920644 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -79,7 +79,7 @@ 账户 本地、FreshRSS 颜色和样式 - 主题、色彩系统、字体大小 + 主题、色调样式、字体大小 交互 启动时、触感反馈 语言 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4aa92b7..114011d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -79,7 +79,7 @@ Accounts Local, FreshRSS Color & style - Theme, color system, font size + Theme, color style, font size Interaction On start, haptic feedback Languages From fa3c5e3601ce3e40919a693c104950ff844c4c36 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 2 May 2022 13:52:08 +0800 Subject: [PATCH 4/6] Add FeedsPage style settings --- .../preference/ArticleListImagePreference.kt | 45 --- .../FeedsFilterBarFilledPreference.kt | 45 +++ .../FeedsFilterBarPaddingPreference.kt | 28 ++ .../FeedsFilterBarStylePreference.kt | 49 +++ .../FeedsFilterBarTonalElevationPreference.kt | 57 +++ ...e.kt => FeedsGroupListExpandPreference.kt} | 18 +- .../FeedsGroupListTonalElevationPreference.kt | 57 +++ ...=> FeedsTopBarTonalElevationPreference.kt} | 20 +- ...ce.kt => FlowArticleListDatePreference.kt} | 18 +- ...ce.kt => FlowArticleListDescPreference.kt} | 18 +- .../FlowArticleListFeedIconPreference.kt | 45 +++ .../FlowArticleListFeedNamePreference.kt | 45 +++ ...e.kt => FlowArticleListImagePreference.kt} | 18 +- ...FlowArticleListTonalElevationPreference.kt | 57 +++ ...ce.kt => FlowFilterBarFilledPreference.kt} | 18 +- ...e.kt => FlowFilterBarPaddingPreference.kt} | 9 +- ...nce.kt => FlowFilterBarStylePreference.kt} | 21 +- .../FlowFilterBarTonalElevationPreference.kt | 57 +++ ... => FlowTopBarTonalElevationPreference.kt} | 20 +- .../reader/data/preference/ThemePreference.kt | 28 ++ .../java/me/ash/reader/ui/component/Tips.kt | 38 ++ .../java/me/ash/reader/ui/ext/ColorScheme.kt | 16 +- .../java/me/ash/reader/ui/ext/DataStoreExt.kt | 112 ++++-- .../me/ash/reader/ui/page/common/HomeEntry.kt | 4 + .../me/ash/reader/ui/page/common/RouteName.kt | 1 + .../me/ash/reader/ui/page/home/FilterBar.kt | 43 +- .../ash/reader/ui/page/home/HomeViewModel.kt | 2 +- .../ash/reader/ui/page/home/feeds/FeedItem.kt | 27 +- .../reader/ui/page/home/feeds/FeedsPage.kt | 43 +- .../reader/ui/page/home/feeds/GroupItem.kt | 14 +- .../reader/ui/page/home/flow/ArticleItem.kt | 41 +- .../ash/reader/ui/page/home/flow/FlowPage.kt | 47 ++- .../reader/ui/page/home/flow/StickyHeader.kt | 12 +- .../ui/page/settings/color/ColorAndStyle.kt | 24 +- .../settings/color/feeds/FeedsPageStyle.kt | 379 ++++++++++++++++++ .../{feedsPageStyle.kt => FlowPageStyle.kt} | 264 ++++++++---- .../ash/reader/ui/page/startup/StartupPage.kt | 32 +- .../java/me/ash/reader/ui/svg/SVGString.kt | 2 + .../main/java/me/ash/reader/ui/theme/Theme.kt | 124 +++++- .../ui/theme/palette/DynamicTonalPalette.kt | 2 + app/src/main/res/values-zh-rCN/strings.xml | 26 +- app/src/main/res/values/strings.xml | 30 +- 42 files changed, 1550 insertions(+), 406 deletions(-) delete mode 100644 app/src/main/java/me/ash/reader/data/preference/ArticleListImagePreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarFilledPreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarPaddingPreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarStylePreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt rename app/src/main/java/me/ash/reader/data/preference/{ArticleListDatePreference.kt => FeedsGroupListExpandPreference.kt} (59%) create mode 100644 app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt rename app/src/main/java/me/ash/reader/data/preference/{ArticleListTonalElevationPreference.kt => FeedsTopBarTonalElevationPreference.kt} (69%) rename app/src/main/java/me/ash/reader/data/preference/{ArticleListFeedNamePreference.kt => FlowArticleListDatePreference.kt} (62%) rename app/src/main/java/me/ash/reader/data/preference/{ArticleListFeedIconPreference.kt => FlowArticleListDescPreference.kt} (61%) create mode 100644 app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedIconPreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedNamePreference.kt rename app/src/main/java/me/ash/reader/data/preference/{ArticleListDescPreference.kt => FlowArticleListImagePreference.kt} (59%) create mode 100644 app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt rename app/src/main/java/me/ash/reader/data/preference/{FilterBarFilledPreference.kt => FlowFilterBarFilledPreference.kt} (59%) rename app/src/main/java/me/ash/reader/data/preference/{FilterBarPaddingPreference.kt => FlowFilterBarPaddingPreference.kt} (72%) rename app/src/main/java/me/ash/reader/data/preference/{FilterBarStylePreference.kt => FlowFilterBarStylePreference.kt} (59%) create mode 100644 app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt rename app/src/main/java/me/ash/reader/data/preference/{FilterBarTonalElevationPreference.kt => FlowTopBarTonalElevationPreference.kt} (66%) create mode 100644 app/src/main/java/me/ash/reader/data/preference/ThemePreference.kt create mode 100644 app/src/main/java/me/ash/reader/ui/component/Tips.kt create mode 100644 app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt rename app/src/main/java/me/ash/reader/ui/page/settings/color/flow/{feedsPageStyle.kt => FlowPageStyle.kt} (56%) diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListImagePreference.kt b/app/src/main/java/me/ash/reader/data/preference/ArticleListImagePreference.kt deleted file mode 100644 index 06bdde6..0000000 --- a/app/src/main/java/me/ash/reader/data/preference/ArticleListImagePreference.kt +++ /dev/null @@ -1,45 +0,0 @@ -package me.ash.reader.data.preference - -import android.content.Context -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.launch -import me.ash.reader.ui.ext.DataStoreKeys -import me.ash.reader.ui.ext.dataStore -import me.ash.reader.ui.ext.put - -sealed class ArticleListImagePreference(val value: Boolean) : Preference() { - object ON : ArticleListImagePreference(true) - object OFF : ArticleListImagePreference(false) - - override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { - context.dataStore.put( - DataStoreKeys.ArticleListImage, - value - ) - } - } - - companion object { - val default = ON - val values = listOf(ON, OFF) - - val Context.articleListImage: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.ArticleListImage.key]) { - true -> ON - false -> OFF - else -> default - } - } - } -} - -operator fun ArticleListImagePreference.not(): ArticleListImagePreference = - when (value) { - true -> ArticleListImagePreference.OFF - false -> ArticleListImagePreference.ON - } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarFilledPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarFilledPreference.kt new file mode 100644 index 0000000..73dcf13 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarFilledPreference.kt @@ -0,0 +1,45 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FeedsFilterBarFilledPreference(val value: Boolean) : Preference() { + object ON : FeedsFilterBarFilledPreference(true) + object OFF : FeedsFilterBarFilledPreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FeedsFilterBarFilled, + value + ) + } + } + + companion object { + val default = OFF + val values = listOf(ON, OFF) + + val Context.feedsFilterBarFilled: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FeedsFilterBarFilled.key]) { + true -> ON + false -> OFF + else -> default + } + } + } +} + +operator fun FeedsFilterBarFilledPreference.not(): FeedsFilterBarFilledPreference = + when (value) { + true -> FeedsFilterBarFilledPreference.OFF + false -> FeedsFilterBarFilledPreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarPaddingPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarPaddingPreference.kt new file mode 100644 index 0000000..6f2bf15 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarPaddingPreference.kt @@ -0,0 +1,28 @@ +package me.ash.reader.data.preference + +import android.content.Context +import androidx.compose.runtime.Immutable +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +@Immutable +object FeedsFilterBarPaddingPreference { + const val default = 0 + + val Context.feedsFilterBarPadding: Flow + get() = this.dataStore.data.map { + it[DataStoreKeys.FeedsFilterBarPadding.key] ?: default + } + + fun put(context: Context, scope: CoroutineScope, value: Int) { + scope.launch(Dispatchers.IO) { + context.dataStore.put(DataStoreKeys.FeedsFilterBarPadding, value) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarStylePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarStylePreference.kt new file mode 100644 index 0000000..f7db9d3 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarStylePreference.kt @@ -0,0 +1,49 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +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 FeedsFilterBarStylePreference(val value: Int) : Preference() { + object Icon : FeedsFilterBarStylePreference(0) + object IconLabel : FeedsFilterBarStylePreference(1) + object IconLabelOnlySelected : FeedsFilterBarStylePreference(2) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FeedsFilterBarStyle, + value + ) + } + } + + fun getDesc(context: Context): String = + when (this) { + Icon -> context.getString(R.string.icons) + IconLabel -> context.getString(R.string.icons_and_labels) + IconLabelOnlySelected -> context.getString(R.string.icons_and_label_only_selected) + } + + companion object { + val default = Icon + val values = listOf(Icon, IconLabel, IconLabelOnlySelected) + + val Context.feedsFilterBarStyle: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FeedsFilterBarStyle.key]) { + 0 -> Icon + 1 -> IconLabel + 2 -> IconLabelOnlySelected + else -> default + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt new file mode 100644 index 0000000..7afc42b --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt @@ -0,0 +1,57 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FeedsFilterBarTonalElevationPreference(val value: Int) : Preference() { + object Level0 : FeedsFilterBarTonalElevationPreference(0) + object Level1 : FeedsFilterBarTonalElevationPreference(1) + object Level2 : FeedsFilterBarTonalElevationPreference(3) + object Level3 : FeedsFilterBarTonalElevationPreference(6) + object Level4 : FeedsFilterBarTonalElevationPreference(8) + object Level5 : FeedsFilterBarTonalElevationPreference(12) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FeedsFilterBarTonalElevation, + value + ) + } + } + + fun getDesc(context: Context): String = + when (this) { + Level0 -> "Level 0 (0dp)" + Level1 -> "Level 1 (1dp)" + Level2 -> "Level 2 (3dp)" + Level3 -> "Level 3 (6dp)" + Level4 -> "Level 4 (8dp)" + Level5 -> "Level 5 (12dp)" + } + + companion object { + val default = Level0 + val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) + + val Context.feedsFilterBarTonalElevation: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FeedsFilterBarTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListDatePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListExpandPreference.kt similarity index 59% rename from app/src/main/java/me/ash/reader/data/preference/ArticleListDatePreference.kt rename to app/src/main/java/me/ash/reader/data/preference/FeedsGroupListExpandPreference.kt index b89720a..bad79bd 100644 --- a/app/src/main/java/me/ash/reader/data/preference/ArticleListDatePreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListExpandPreference.kt @@ -10,14 +10,14 @@ import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put -sealed class ArticleListDatePreference(val value: Boolean) : Preference() { - object ON : ArticleListDatePreference(true) - object OFF : ArticleListDatePreference(false) +sealed class FeedsGroupListExpandPreference(val value: Boolean) : Preference() { + object ON : FeedsGroupListExpandPreference(true) + object OFF : FeedsGroupListExpandPreference(false) override fun put(context: Context, scope: CoroutineScope) { scope.launch(Dispatchers.IO) { context.dataStore.put( - DataStoreKeys.ArticleListDate, + DataStoreKeys.FeedsGroupListExpand, value ) } @@ -27,9 +27,9 @@ sealed class ArticleListDatePreference(val value: Boolean) : Preference() { val default = ON val values = listOf(ON, OFF) - val Context.articleListDate: Flow + val Context.feedsGroupListExpand: Flow get() = this.dataStore.data.map { - when (it[DataStoreKeys.ArticleListDate.key]) { + when (it[DataStoreKeys.FeedsGroupListExpand.key]) { true -> ON false -> OFF else -> default @@ -38,8 +38,8 @@ sealed class ArticleListDatePreference(val value: Boolean) : Preference() { } } -operator fun ArticleListDatePreference.not(): ArticleListDatePreference = +operator fun FeedsGroupListExpandPreference.not(): FeedsGroupListExpandPreference = when (value) { - true -> ArticleListDatePreference.OFF - false -> ArticleListDatePreference.ON + true -> FeedsGroupListExpandPreference.OFF + false -> FeedsGroupListExpandPreference.ON } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt new file mode 100644 index 0000000..03148e5 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt @@ -0,0 +1,57 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FeedsGroupListTonalElevationPreference(val value: Int) : Preference() { + object Level0 : FeedsGroupListTonalElevationPreference(0) + object Level1 : FeedsGroupListTonalElevationPreference(1) + object Level2 : FeedsGroupListTonalElevationPreference(3) + object Level3 : FeedsGroupListTonalElevationPreference(6) + object Level4 : FeedsGroupListTonalElevationPreference(8) + object Level5 : FeedsGroupListTonalElevationPreference(12) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FeedsGroupListTonalElevation, + value + ) + } + } + + fun getDesc(context: Context): String = + when (this) { + Level0 -> "Level 0 (0dp)" + Level1 -> "Level 1 (1dp)" + Level2 -> "Level 2 (3dp)" + Level3 -> "Level 3 (6dp)" + Level4 -> "Level 4 (8dp)" + Level5 -> "Level 5 (12dp)" + } + + companion object { + val default = Level0 + val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) + + val Context.feedsGroupListTonalElevation: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FeedsGroupListTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt similarity index 69% rename from app/src/main/java/me/ash/reader/data/preference/ArticleListTonalElevationPreference.kt rename to app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt index 79a862a..c1e9e4c 100644 --- a/app/src/main/java/me/ash/reader/data/preference/ArticleListTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt @@ -10,18 +10,18 @@ import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put -sealed class ArticleListTonalElevationPreference(val value: Int) : Preference() { - object Level0 : ArticleListTonalElevationPreference(0) - object Level1 : ArticleListTonalElevationPreference(1) - object Level2 : ArticleListTonalElevationPreference(3) - object Level3 : ArticleListTonalElevationPreference(6) - object Level4 : ArticleListTonalElevationPreference(8) - object Level5 : ArticleListTonalElevationPreference(12) +sealed class FeedsTopBarTonalElevationPreference(val value: Int) : Preference() { + object Level0 : FeedsTopBarTonalElevationPreference(0) + object Level1 : FeedsTopBarTonalElevationPreference(1) + object Level2 : FeedsTopBarTonalElevationPreference(3) + object Level3 : FeedsTopBarTonalElevationPreference(6) + object Level4 : FeedsTopBarTonalElevationPreference(8) + object Level5 : FeedsTopBarTonalElevationPreference(12) override fun put(context: Context, scope: CoroutineScope) { scope.launch(Dispatchers.IO) { context.dataStore.put( - DataStoreKeys.ArticleListTonalElevation, + DataStoreKeys.FeedsTopBarTonalElevation, value ) } @@ -41,9 +41,9 @@ sealed class ArticleListTonalElevationPreference(val value: Int) : Preference() val default = Level0 val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) - val Context.articleListTonalElevation: Flow + val Context.feedsTopBarTonalElevation: Flow get() = this.dataStore.data.map { - when (it[DataStoreKeys.ArticleListTonalElevation.key]) { + when (it[DataStoreKeys.FeedsTopBarTonalElevation.key]) { 0 -> Level0 1 -> Level1 3 -> Level2 diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListFeedNamePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDatePreference.kt similarity index 62% rename from app/src/main/java/me/ash/reader/data/preference/ArticleListFeedNamePreference.kt rename to app/src/main/java/me/ash/reader/data/preference/FlowArticleListDatePreference.kt index 9269d4b..119096c 100644 --- a/app/src/main/java/me/ash/reader/data/preference/ArticleListFeedNamePreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDatePreference.kt @@ -10,14 +10,14 @@ import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put -sealed class ArticleListFeedNamePreference(val value: Boolean) : Preference() { - object ON : ArticleListFeedNamePreference(true) - object OFF : ArticleListFeedNamePreference(false) +sealed class FlowArticleListDatePreference(val value: Boolean) : Preference() { + object ON : FlowArticleListDatePreference(true) + object OFF : FlowArticleListDatePreference(false) override fun put(context: Context, scope: CoroutineScope) { scope.launch(Dispatchers.IO) { context.dataStore.put( - DataStoreKeys.ArticleListFeedName, + DataStoreKeys.FlowArticleListDate, value ) } @@ -27,9 +27,9 @@ sealed class ArticleListFeedNamePreference(val value: Boolean) : Preference() { val default = ON val values = listOf(ON, OFF) - val Context.articleListFeedName: Flow + val Context.flowArticleListDate: Flow get() = this.dataStore.data.map { - when (it[DataStoreKeys.ArticleListFeedName.key]) { + when (it[DataStoreKeys.FlowArticleListDate.key]) { true -> ON false -> OFF else -> default @@ -38,8 +38,8 @@ sealed class ArticleListFeedNamePreference(val value: Boolean) : Preference() { } } -operator fun ArticleListFeedNamePreference.not(): ArticleListFeedNamePreference = +operator fun FlowArticleListDatePreference.not(): FlowArticleListDatePreference = when (value) { - true -> ArticleListFeedNamePreference.OFF - false -> ArticleListFeedNamePreference.ON + true -> FlowArticleListDatePreference.OFF + false -> FlowArticleListDatePreference.ON } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListFeedIconPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDescPreference.kt similarity index 61% rename from app/src/main/java/me/ash/reader/data/preference/ArticleListFeedIconPreference.kt rename to app/src/main/java/me/ash/reader/data/preference/FlowArticleListDescPreference.kt index 796aa61..a1f483f 100644 --- a/app/src/main/java/me/ash/reader/data/preference/ArticleListFeedIconPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDescPreference.kt @@ -10,14 +10,14 @@ import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put -sealed class ArticleListFeedIconPreference(val value: Boolean) : Preference() { - object ON : ArticleListFeedIconPreference(true) - object OFF : ArticleListFeedIconPreference(false) +sealed class FlowArticleListDescPreference(val value: Boolean) : Preference() { + object ON : FlowArticleListDescPreference(true) + object OFF : FlowArticleListDescPreference(false) override fun put(context: Context, scope: CoroutineScope) { scope.launch(Dispatchers.IO) { context.dataStore.put( - DataStoreKeys.ArticleListFeedIcon, + DataStoreKeys.FlowArticleListDesc, value ) } @@ -27,9 +27,9 @@ sealed class ArticleListFeedIconPreference(val value: Boolean) : Preference() { val default = ON val values = listOf(ON, OFF) - val Context.articleListFeedIcon: Flow + val Context.flowArticleListDesc: Flow get() = this.dataStore.data.map { - when (it[DataStoreKeys.ArticleListFeedIcon.key]) { + when (it[DataStoreKeys.FlowArticleListDesc.key]) { true -> ON false -> OFF else -> default @@ -38,8 +38,8 @@ sealed class ArticleListFeedIconPreference(val value: Boolean) : Preference() { } } -operator fun ArticleListFeedIconPreference.not(): ArticleListFeedIconPreference = +operator fun FlowArticleListDescPreference.not(): FlowArticleListDescPreference = when (value) { - true -> ArticleListFeedIconPreference.OFF - false -> ArticleListFeedIconPreference.ON + true -> FlowArticleListDescPreference.OFF + false -> FlowArticleListDescPreference.ON } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedIconPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedIconPreference.kt new file mode 100644 index 0000000..f00e873 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedIconPreference.kt @@ -0,0 +1,45 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FlowArticleListFeedIconPreference(val value: Boolean) : Preference() { + object ON : FlowArticleListFeedIconPreference(true) + object OFF : FlowArticleListFeedIconPreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FlowArticleListFeedIcon, + value + ) + } + } + + companion object { + val default = ON + val values = listOf(ON, OFF) + + val Context.flowArticleListFeedIcon: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FlowArticleListFeedIcon.key]) { + true -> ON + false -> OFF + else -> default + } + } + } +} + +operator fun FlowArticleListFeedIconPreference.not(): FlowArticleListFeedIconPreference = + when (value) { + true -> FlowArticleListFeedIconPreference.OFF + false -> FlowArticleListFeedIconPreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedNamePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedNamePreference.kt new file mode 100644 index 0000000..4fae700 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedNamePreference.kt @@ -0,0 +1,45 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FlowArticleListFeedNamePreference(val value: Boolean) : Preference() { + object ON : FlowArticleListFeedNamePreference(true) + object OFF : FlowArticleListFeedNamePreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FlowArticleListFeedName, + value + ) + } + } + + companion object { + val default = ON + val values = listOf(ON, OFF) + + val Context.flowArticleListFeedName: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FlowArticleListFeedName.key]) { + true -> ON + false -> OFF + else -> default + } + } + } +} + +operator fun FlowArticleListFeedNamePreference.not(): FlowArticleListFeedNamePreference = + when (value) { + true -> FlowArticleListFeedNamePreference.OFF + false -> FlowArticleListFeedNamePreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/ArticleListDescPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListImagePreference.kt similarity index 59% rename from app/src/main/java/me/ash/reader/data/preference/ArticleListDescPreference.kt rename to app/src/main/java/me/ash/reader/data/preference/FlowArticleListImagePreference.kt index 10dc06a..ef7d776 100644 --- a/app/src/main/java/me/ash/reader/data/preference/ArticleListDescPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListImagePreference.kt @@ -10,14 +10,14 @@ import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put -sealed class ArticleListDescPreference(val value: Boolean) : Preference() { - object ON : ArticleListDescPreference(true) - object OFF : ArticleListDescPreference(false) +sealed class FlowArticleListImagePreference(val value: Boolean) : Preference() { + object ON : FlowArticleListImagePreference(true) + object OFF : FlowArticleListImagePreference(false) override fun put(context: Context, scope: CoroutineScope) { scope.launch(Dispatchers.IO) { context.dataStore.put( - DataStoreKeys.ArticleListDesc, + DataStoreKeys.FlowArticleListImage, value ) } @@ -27,9 +27,9 @@ sealed class ArticleListDescPreference(val value: Boolean) : Preference() { val default = ON val values = listOf(ON, OFF) - val Context.articleListDesc: Flow + val Context.flowArticleListImage: Flow get() = this.dataStore.data.map { - when (it[DataStoreKeys.ArticleListDesc.key]) { + when (it[DataStoreKeys.FlowArticleListImage.key]) { true -> ON false -> OFF else -> default @@ -38,8 +38,8 @@ sealed class ArticleListDescPreference(val value: Boolean) : Preference() { } } -operator fun ArticleListDescPreference.not(): ArticleListDescPreference = +operator fun FlowArticleListImagePreference.not(): FlowArticleListImagePreference = when (value) { - true -> ArticleListDescPreference.OFF - false -> ArticleListDescPreference.ON + true -> FlowArticleListImagePreference.OFF + false -> FlowArticleListImagePreference.ON } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt new file mode 100644 index 0000000..e6febf7 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt @@ -0,0 +1,57 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FlowArticleListTonalElevationPreference(val value: Int) : Preference() { + object Level0 : FlowArticleListTonalElevationPreference(0) + object Level1 : FlowArticleListTonalElevationPreference(1) + object Level2 : FlowArticleListTonalElevationPreference(3) + object Level3 : FlowArticleListTonalElevationPreference(6) + object Level4 : FlowArticleListTonalElevationPreference(8) + object Level5 : FlowArticleListTonalElevationPreference(12) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FlowArticleListTonalElevation, + value + ) + } + } + + fun getDesc(context: Context): String = + when (this) { + Level0 -> "Level 0 (0dp)" + Level1 -> "Level 1 (1dp)" + Level2 -> "Level 2 (3dp)" + Level3 -> "Level 3 (6dp)" + Level4 -> "Level 4 (8dp)" + Level5 -> "Level 5 (12dp)" + } + + companion object { + val default = Level0 + val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) + + val Context.flowArticleListTonalElevation: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FlowArticleListTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FilterBarFilledPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarFilledPreference.kt similarity index 59% rename from app/src/main/java/me/ash/reader/data/preference/FilterBarFilledPreference.kt rename to app/src/main/java/me/ash/reader/data/preference/FlowFilterBarFilledPreference.kt index c6265da..367507d 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FilterBarFilledPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarFilledPreference.kt @@ -10,14 +10,14 @@ import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put -sealed class FilterBarFilledPreference(val value: Boolean) : Preference() { - object ON : FilterBarFilledPreference(true) - object OFF : FilterBarFilledPreference(false) +sealed class FlowFilterBarFilledPreference(val value: Boolean) : Preference() { + object ON : FlowFilterBarFilledPreference(true) + object OFF : FlowFilterBarFilledPreference(false) override fun put(context: Context, scope: CoroutineScope) { scope.launch(Dispatchers.IO) { context.dataStore.put( - DataStoreKeys.FilterBarFilled, + DataStoreKeys.FlowFilterBarFilled, value ) } @@ -27,9 +27,9 @@ sealed class FilterBarFilledPreference(val value: Boolean) : Preference() { val default = OFF val values = listOf(ON, OFF) - val Context.filterBarFilled: Flow + val Context.flowFilterBarFilled: Flow get() = this.dataStore.data.map { - when (it[DataStoreKeys.FilterBarFilled.key]) { + when (it[DataStoreKeys.FlowFilterBarFilled.key]) { true -> ON false -> OFF else -> default @@ -38,8 +38,8 @@ sealed class FilterBarFilledPreference(val value: Boolean) : Preference() { } } -operator fun FilterBarFilledPreference.not(): FilterBarFilledPreference = +operator fun FlowFilterBarFilledPreference.not(): FlowFilterBarFilledPreference = when (value) { - true -> FilterBarFilledPreference.OFF - false -> FilterBarFilledPreference.ON + true -> FlowFilterBarFilledPreference.OFF + false -> FlowFilterBarFilledPreference.ON } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FilterBarPaddingPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarPaddingPreference.kt similarity index 72% rename from app/src/main/java/me/ash/reader/data/preference/FilterBarPaddingPreference.kt rename to app/src/main/java/me/ash/reader/data/preference/FlowFilterBarPaddingPreference.kt index 516453f..b564ff3 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FilterBarPaddingPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarPaddingPreference.kt @@ -1,7 +1,6 @@ package me.ash.reader.data.preference import android.content.Context -import android.util.Log import androidx.compose.runtime.Immutable import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -13,17 +12,17 @@ import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put @Immutable -object FilterBarPaddingPreference { +object FlowFilterBarPaddingPreference { const val default = 0 - val Context.filterBarPadding: Flow + val Context.flowFilterBarPadding: Flow get() = this.dataStore.data.map { - it[DataStoreKeys.FilterBarPadding.key] ?: 0 + it[DataStoreKeys.FlowFilterBarPadding.key] ?: default } fun put(context: Context, scope: CoroutineScope, value: Int) { scope.launch(Dispatchers.IO) { - context.dataStore.put(DataStoreKeys.FilterBarPadding, value) + context.dataStore.put(DataStoreKeys.FlowFilterBarPadding, value) } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FilterBarStylePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarStylePreference.kt similarity index 59% rename from app/src/main/java/me/ash/reader/data/preference/FilterBarStylePreference.kt rename to app/src/main/java/me/ash/reader/data/preference/FlowFilterBarStylePreference.kt index 50e6c7b..10a5c9c 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FilterBarStylePreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarStylePreference.kt @@ -6,19 +6,20 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map 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 FilterBarStylePreference(val value: Int) : Preference() { - object Icon : FilterBarStylePreference(0) - object IconLabel : FilterBarStylePreference(1) - object IconLabelOnlySelected : FilterBarStylePreference(2) +sealed class FlowFilterBarStylePreference(val value: Int) : Preference() { + object Icon : FlowFilterBarStylePreference(0) + object IconLabel : FlowFilterBarStylePreference(1) + object IconLabelOnlySelected : FlowFilterBarStylePreference(2) override fun put(context: Context, scope: CoroutineScope) { scope.launch(Dispatchers.IO) { context.dataStore.put( - DataStoreKeys.FilterBarStyle, + DataStoreKeys.FlowFilterBarStyle, value ) } @@ -26,18 +27,18 @@ sealed class FilterBarStylePreference(val value: Int) : Preference() { fun getDesc(context: Context): String = when (this) { - Icon -> "图标" - IconLabel -> "图标 + 标签" - IconLabelOnlySelected -> "图标 + 标签(仅选中时)" + Icon -> context.getString(R.string.icons) + IconLabel -> context.getString(R.string.icons_and_labels) + IconLabelOnlySelected -> context.getString(R.string.icons_and_label_only_selected) } companion object { val default = Icon val values = listOf(Icon, IconLabel, IconLabelOnlySelected) - val Context.filterBarStyle: Flow + val Context.flowFilterBarStyle: Flow get() = this.dataStore.data.map { - when (it[DataStoreKeys.FilterBarStyle.key]) { + when (it[DataStoreKeys.FlowFilterBarStyle.key]) { 0 -> Icon 1 -> IconLabel 2 -> IconLabelOnlySelected diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt new file mode 100644 index 0000000..620b2f7 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt @@ -0,0 +1,57 @@ +package me.ash.reader.data.preference + +import android.content.Context +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FlowFilterBarTonalElevationPreference(val value: Int) : Preference() { + object Level0 : FlowFilterBarTonalElevationPreference(0) + object Level1 : FlowFilterBarTonalElevationPreference(1) + object Level2 : FlowFilterBarTonalElevationPreference(3) + object Level3 : FlowFilterBarTonalElevationPreference(6) + object Level4 : FlowFilterBarTonalElevationPreference(8) + object Level5 : FlowFilterBarTonalElevationPreference(12) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch(Dispatchers.IO) { + context.dataStore.put( + DataStoreKeys.FlowFilterBarTonalElevation, + value + ) + } + } + + fun getDesc(context: Context): String = + when (this) { + Level0 -> "Level 0 (0dp)" + Level1 -> "Level 1 (1dp)" + Level2 -> "Level 2 (3dp)" + Level3 -> "Level 3 (6dp)" + Level4 -> "Level 4 (8dp)" + Level5 -> "Level 5 (12dp)" + } + + companion object { + val default = Level0 + val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) + + val Context.flowFilterBarTonalElevation: Flow + get() = this.dataStore.data.map { + when (it[DataStoreKeys.FlowFilterBarTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FilterBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt similarity index 66% rename from app/src/main/java/me/ash/reader/data/preference/FilterBarTonalElevationPreference.kt rename to app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt index 6c6fced..a01e263 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FilterBarTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt @@ -10,18 +10,18 @@ import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put -sealed class FilterBarTonalElevationPreference(val value: Int) : Preference() { - object Level0 : FilterBarTonalElevationPreference(0) - object Level1 : FilterBarTonalElevationPreference(1) - object Level2 : FilterBarTonalElevationPreference(3) - object Level3 : FilterBarTonalElevationPreference(6) - object Level4 : FilterBarTonalElevationPreference(8) - object Level5 : FilterBarTonalElevationPreference(12) +sealed class FlowTopBarTonalElevationPreference(val value: Int) : Preference() { + object Level0 : FlowTopBarTonalElevationPreference(0) + object Level1 : FlowTopBarTonalElevationPreference(1) + object Level2 : FlowTopBarTonalElevationPreference(3) + object Level3 : FlowTopBarTonalElevationPreference(6) + object Level4 : FlowTopBarTonalElevationPreference(8) + object Level5 : FlowTopBarTonalElevationPreference(12) override fun put(context: Context, scope: CoroutineScope) { scope.launch(Dispatchers.IO) { context.dataStore.put( - DataStoreKeys.FilterBarTonalElevation, + DataStoreKeys.FlowTopBarTonalElevation, value ) } @@ -41,9 +41,9 @@ sealed class FilterBarTonalElevationPreference(val value: Int) : Preference() { val default = Level0 val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) - val Context.filterBarTonalElevation: Flow + val Context.flowTopBarTonalElevation: Flow get() = this.dataStore.data.map { - when (it[DataStoreKeys.FilterBarTonalElevation.key]) { + when (it[DataStoreKeys.FlowTopBarTonalElevation.key]) { 0 -> Level0 1 -> Level1 3 -> Level2 diff --git a/app/src/main/java/me/ash/reader/data/preference/ThemePreference.kt b/app/src/main/java/me/ash/reader/data/preference/ThemePreference.kt new file mode 100644 index 0000000..3f006a7 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/ThemePreference.kt @@ -0,0 +1,28 @@ +package me.ash.reader.data.preference + +import android.content.Context +import androidx.compose.runtime.Immutable +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +@Immutable +object ThemePreference { + const val default = 5 + + val Context.Theme: Flow + get() = this.dataStore.data.map { + it[DataStoreKeys.ThemeIndex.key] ?: default + } + + fun put(context: Context, scope: CoroutineScope, value: Int) { + scope.launch(Dispatchers.IO) { + context.dataStore.put(DataStoreKeys.ThemeIndex, value) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/component/Tips.kt b/app/src/main/java/me/ash/reader/ui/component/Tips.kt new file mode 100644 index 0000000..bab7833 --- /dev/null +++ b/app/src/main/java/me/ash/reader/ui/component/Tips.kt @@ -0,0 +1,38 @@ +package me.ash.reader.ui.component + +import androidx.compose.foundation.layout.* +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Info +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import me.ash.reader.R + +@Composable +fun Tips( + modifier: Modifier = Modifier, + text: String, +) { + Column( + modifier = modifier + .fillMaxWidth() + .padding(horizontal = 24.dp, vertical = 16.dp), + ) { + Icon( + imageVector = Icons.Outlined.Info, + contentDescription = stringResource(R.string.tips_and_support), + tint = MaterialTheme.colorScheme.onSurfaceVariant, + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = text, + style = MaterialTheme.typography.labelLarge.copy(fontWeight = FontWeight.Light), + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/ext/ColorScheme.kt b/app/src/main/java/me/ash/reader/ui/ext/ColorScheme.kt index d7fb5f5..1e2276f 100644 --- a/app/src/main/java/me/ash/reader/ui/ext/ColorScheme.kt +++ b/app/src/main/java/me/ash/reader/ui/ext/ColorScheme.kt @@ -9,8 +9,16 @@ import kotlin.math.ln fun ColorScheme.surfaceColorAtElevation( elevation: Dp, + color: Color = surface, +): Color = color.atElevation(surfaceTint, elevation) + +fun Color.atElevation( + sourceColor: Color, + elevation: Dp, ): Color { - if (elevation == 0.dp) return surface - val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f - return primary.copy(alpha = alpha).compositeOver(surface) -} \ No newline at end of file + if (elevation == 0.dp) return this + return sourceColor.copy(alpha = elevation.alphaLN(constant = 4.5f)).compositeOver(this) +} + +fun Dp.alphaLN(constant: Float = 1f, weight: Float = 0f): Float = + ((constant * ln(value + 1) + weight) + 2f) / 100f 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 0dd5463..687f4be 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 @@ -31,8 +31,6 @@ val Context.currentAccountId: Int get() = this.dataStore.get(DataStoreKeys.CurrentAccountId)!! val Context.currentAccountType: Int get() = this.dataStore.get(DataStoreKeys.CurrentAccountType)!! -val Context.themeIndex: Int - get() = this.dataStore.get(DataStoreKeys.ThemeIndex) ?: 5 val Context.customPrimaryColor: String get() = this.dataStore.get(DataStoreKeys.CustomPrimaryColor) ?: "" @@ -130,54 +128,94 @@ sealed class DataStoreKeys { get() = stringPreferencesKey("customPrimaryColor") } - object FilterBarStyle : DataStoreKeys() { + object FeedsFilterBarStyle : DataStoreKeys() { override val key: Preferences.Key - get() = intPreferencesKey("filterBarStyle") + get() = intPreferencesKey("feedsFilterBarStyle") } - object FilterBarFilled : DataStoreKeys() { + object FeedsFilterBarFilled : DataStoreKeys() { override val key: Preferences.Key - get() = booleanPreferencesKey("filterBarFilled") + get() = booleanPreferencesKey("feedsFilterBarFilled") } - object FilterBarPadding : DataStoreKeys() { + object FeedsFilterBarPadding : DataStoreKeys() { override val key: Preferences.Key - get() = intPreferencesKey("filterBarPadding") + get() = intPreferencesKey("feedsFilterBarPadding") } - object FilterBarTonalElevation : DataStoreKeys() { + object FeedsFilterBarTonalElevation : DataStoreKeys() { override val key: Preferences.Key - get() = intPreferencesKey("filterBarTonalElevation") + get() = intPreferencesKey("feedsFilterBarTonalElevation") } - object ArticleListFeedIcon : DataStoreKeys() { - override val key: Preferences.Key - get() = booleanPreferencesKey("articleListFeedIcon") - } - - object ArticleListFeedName : DataStoreKeys() { - override val key: Preferences.Key - get() = booleanPreferencesKey("articleListFeedName") - } - - object ArticleListImage : DataStoreKeys() { - override val key: Preferences.Key - get() = booleanPreferencesKey("articleListImage") - } - - object ArticleListDesc : DataStoreKeys() { - override val key: Preferences.Key - get() = booleanPreferencesKey("articleListDesc") - } - - object ArticleListDate : DataStoreKeys() { - override val key: Preferences.Key - get() = booleanPreferencesKey("articleListDate") - } - - object ArticleListTonalElevation : DataStoreKeys() { + object FeedsTopBarTonalElevation : DataStoreKeys() { override val key: Preferences.Key - get() = intPreferencesKey("articleListTonalElevation") + get() = intPreferencesKey("feedsTopBarTonalElevation") + } + + object FeedsGroupListExpand : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("feedsGroupListExpand") + } + + object FeedsGroupListTonalElevation : DataStoreKeys() { + override val key: Preferences.Key + get() = intPreferencesKey("feedsGroupListTonalElevation") + } + + object FlowFilterBarStyle : DataStoreKeys() { + override val key: Preferences.Key + get() = intPreferencesKey("flowFilterBarStyle") + } + + object FlowFilterBarFilled : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("flowFilterBarFilled") + } + + object FlowFilterBarPadding : DataStoreKeys() { + override val key: Preferences.Key + get() = intPreferencesKey("flowFilterBarPadding") + } + + object FlowFilterBarTonalElevation : DataStoreKeys() { + override val key: Preferences.Key + get() = intPreferencesKey("flowFilterBarTonalElevation") + } + + object FlowTopBarTonalElevation : DataStoreKeys() { + override val key: Preferences.Key + get() = intPreferencesKey("flowTopBarTonalElevation") + } + + object FlowArticleListFeedIcon : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("flowArticleListFeedIcon") + } + + object FlowArticleListFeedName : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("flowArticleListFeedName") + } + + object FlowArticleListImage : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("flowArticleListImage") + } + + object FlowArticleListDesc : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("flowArticleListDesc") + } + + object FlowArticleListDate : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("flowArticleListDate") + } + + object FlowArticleListTonalElevation : DataStoreKeys() { + override val key: Preferences.Key + get() = intPreferencesKey("flowArticleListTonalElevation") } object InitialPage : DataStoreKeys() { diff --git a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt index 8d8208e..76453a5 100644 --- a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt +++ b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt @@ -22,6 +22,7 @@ import me.ash.reader.ui.page.home.flow.FlowPage import me.ash.reader.ui.page.home.read.ReadPage import me.ash.reader.ui.page.settings.SettingsPage import me.ash.reader.ui.page.settings.color.ColorAndStyle +import me.ash.reader.ui.page.settings.color.feeds.FeedsPageStyle import me.ash.reader.ui.page.settings.color.flow.FlowPageStyle import me.ash.reader.ui.page.settings.interaction.Interaction import me.ash.reader.ui.page.settings.tips.TipsAndSupport @@ -127,6 +128,9 @@ fun HomeEntry( animatedComposable(route = RouteName.COLOR_AND_STYLE) { ColorAndStyle(navController) } + animatedComposable(route = RouteName.FEEDS_PAGE_STYLE) { + FeedsPageStyle(navController) + } animatedComposable(route = RouteName.FLOW_PAGE_STYLE) { FlowPageStyle(navController) } diff --git a/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt b/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt index 51aba6a..baf917a 100644 --- a/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt +++ b/app/src/main/java/me/ash/reader/ui/page/common/RouteName.kt @@ -14,6 +14,7 @@ object RouteName { // Color & Style const val COLOR_AND_STYLE = "color_and_style" + const val FEEDS_PAGE_STYLE = "feeds_page_style" const val FLOW_PAGE_STYLE = "flow_page_style" // Interaction diff --git a/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt b/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt index 341d4fb..75b517a 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/FilterBar.kt @@ -6,20 +6,11 @@ import androidx.compose.foundation.layout.width import androidx.compose.material3.* import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalView -import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.Dp import com.google.accompanist.pager.ExperimentalPagerApi import me.ash.reader.data.entity.Filter -import me.ash.reader.data.preference.FilterBarFilledPreference -import me.ash.reader.data.preference.FilterBarFilledPreference.Companion.filterBarFilled -import me.ash.reader.data.preference.FilterBarPaddingPreference -import me.ash.reader.data.preference.FilterBarPaddingPreference.filterBarPadding -import me.ash.reader.data.preference.FilterBarStylePreference -import me.ash.reader.data.preference.FilterBarStylePreference.Companion.filterBarStyle -import me.ash.reader.data.preference.FilterBarTonalElevationPreference -import me.ash.reader.data.preference.FilterBarTonalElevationPreference.Companion.filterBarTonalElevation -import me.ash.reader.ui.ext.collectAsStateValue +import me.ash.reader.data.preference.FlowFilterBarStylePreference import me.ash.reader.ui.ext.getName import me.ash.reader.ui.theme.palette.onDark @@ -28,23 +19,18 @@ import me.ash.reader.ui.theme.palette.onDark fun FilterBar( modifier: Modifier = Modifier, filter: Filter, + filterBarStyle: Int, + filterBarFilled: Boolean, + filterBarPadding: Dp, + filterBarTonalElevation: Dp, filterOnClick: (Filter) -> Unit = {}, ) { val view = LocalView.current - val context = LocalContext.current - val filterBarStyle = - context.filterBarStyle.collectAsStateValue(initial = FilterBarStylePreference.default) - val filterBarFilled = - context.filterBarFilled.collectAsStateValue(initial = FilterBarFilledPreference.default) - val filterBarPadding = - context.filterBarPadding.collectAsStateValue(initial = FilterBarPaddingPreference.default) - val filterBarTonalElevation = - context.filterBarTonalElevation.collectAsStateValue(initial = FilterBarTonalElevationPreference.default) NavigationBar( - tonalElevation = filterBarTonalElevation.value.dp, + tonalElevation = filterBarTonalElevation, ) { - Spacer(modifier = Modifier.width(filterBarPadding.dp)) + Spacer(modifier = Modifier.width(filterBarPadding)) listOf( Filter.Starred, Filter.Unread, @@ -53,13 +39,14 @@ fun FilterBar( NavigationBarItem( // modifier = Modifier.height(60.dp), alwaysShowLabel = when (filterBarStyle) { - is FilterBarStylePreference.Icon -> false - is FilterBarStylePreference.IconLabel -> true - is FilterBarStylePreference.IconLabelOnlySelected -> false + FlowFilterBarStylePreference.Icon.value -> false + FlowFilterBarStylePreference.IconLabel.value -> true + FlowFilterBarStylePreference.IconLabelOnlySelected.value -> false + else -> false }, icon = { Icon( - imageVector = if (filter == item && filterBarFilled.value) { + imageVector = if (filter == item && filterBarFilled) { item.iconFilled } else { item.iconOutline @@ -67,7 +54,7 @@ fun FilterBar( contentDescription = item.getName() ) }, - label = if (filterBarStyle is FilterBarStylePreference.Icon) { + label = if (filterBarStyle == FlowFilterBarStylePreference.Icon.value) { null } else { { @@ -92,6 +79,6 @@ fun FilterBar( ) ) } - Spacer(modifier = Modifier.width(filterBarPadding.dp)) + Spacer(modifier = Modifier.width(filterBarPadding)) } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt b/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt index e2ea70b..e787100 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/HomeViewModel.kt @@ -62,7 +62,7 @@ class HomeViewModel @Inject constructor( private fun fetchArticles() { _viewState.update { it.copy( - pagingData = Pager(PagingConfig(pageSize = 10)) { + pagingData = Pager(PagingConfig(pageSize = 15)) { if (_viewState.value.searchContent.isNotBlank()) { rssRepository.get().searchArticles( content = _viewState.value.searchContent.trim(), diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedItem.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedItem.kt index db5c130..87284a2 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedItem.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedItem.kt @@ -16,11 +16,13 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalView import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import me.ash.reader.data.entity.Feed import me.ash.reader.ui.page.home.feeds.option.feed.FeedOptionViewAction import me.ash.reader.ui.page.home.feeds.option.feed.FeedOptionViewModel +import kotlin.math.ln @OptIn( androidx.compose.foundation.ExperimentalFoundationApi::class, @@ -31,6 +33,7 @@ fun FeedItem( modifier: Modifier = Modifier, feed: Feed, feedOptionViewModel: FeedOptionViewModel = hiltViewModel(), + tonalElevation: Dp, onClick: () -> Unit = {}, ) { val view = LocalView.current @@ -76,18 +79,18 @@ fun FeedItem( ) } if (feed.important ?: 0 != 0) { - Row() { - Badge( - containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.24f), - contentColor = MaterialTheme.colorScheme.outline, - content = { - Text( - text = feed.important.toString(), - style = MaterialTheme.typography.labelSmall - ) - }, - ) - } + Badge( + containerColor = MaterialTheme.colorScheme.surfaceTint.copy( + alpha = (ln(tonalElevation.value + 1.4f) + 2f) / 100f + ), + contentColor = MaterialTheme.colorScheme.outline, + content = { + Text( + text = feed.important.toString(), + style = MaterialTheme.typography.labelSmall + ) + }, + ) } } } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt index e9bc7f0..db5ac4c 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt @@ -45,6 +45,8 @@ import me.ash.reader.ui.page.home.feeds.option.group.GroupOptionDrawer import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeDialog import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeViewAction import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeViewModel +import me.ash.reader.ui.theme.* +import me.ash.reader.ui.theme.palette.onDark @SuppressLint("FlowOperatorInvokedInComposition") @OptIn( @@ -59,6 +61,14 @@ fun FeedsPage( homeViewModel: HomeViewModel, ) { val context = LocalContext.current + val topBarTonalElevation = LocalFeedsTopBarTonalElevation.current + val groupListTonalElevation = LocalFeedsGroupListTonalElevation.current + val groupListExpand = LocalFeedsGroupListExpand.current + val filterBarStyle = LocalFeedsFilterBarStyle.current + val filterBarFilled = LocalFeedsFilterBarFilled.current + val filterBarPadding = LocalFeedsFilterBarPadding.current + val filterBarTonalElevation = LocalFeedsFilterBarTonalElevation.current + val feedsViewState = feedsViewModel.viewState.collectAsStateValue() val filterState = homeViewModel.filterState.collectAsStateValue() @@ -117,11 +127,19 @@ fun FeedsPage( Scaffold( modifier = Modifier - .background(MaterialTheme.colorScheme.surface) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(topBarTonalElevation.dp)) .statusBarsPadding() .navigationBarsPadding(), + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( + groupListTonalElevation.dp + ) onDark MaterialTheme.colorScheme.surface, topBar = { SmallTopAppBar( + colors = TopAppBarDefaults.smallTopAppBarColors( + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( + topBarTonalElevation.dp + ), + ), title = {}, navigationIcon = { FeedbackIconButton( @@ -204,6 +222,8 @@ fun FeedsPage( // Crossfade(targetState = groupWithFeed) { groupWithFeed -> Column { GroupItem( + isExpanded = groupListExpand, + tonalElevation = groupListTonalElevation.dp, group = groupWithFeed.group, feeds = groupWithFeed.feeds, groupOnClick = { @@ -242,15 +262,18 @@ fun FeedsPage( bottomBar = { FilterBar( filter = filterState.filter, - filterOnClick = { - filterChange( - navController = navController, - homeViewModel = homeViewModel, - filterState = filterState.copy(filter = it), - isNavigate = false, - ) - }, - ) + filterBarStyle = filterBarStyle, + filterBarFilled = filterBarFilled, + filterBarPadding = filterBarPadding.dp, + filterBarTonalElevation = filterBarTonalElevation.dp, + ) { + filterChange( + navController = navController, + homeViewModel = homeViewModel, + filterState = filterState.copy(filter = it), + isNavigate = false, + ) + } } ) diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/GroupItem.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/GroupItem.kt index 3f32954..3563a00 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/GroupItem.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/GroupItem.kt @@ -22,11 +22,13 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import me.ash.reader.R import me.ash.reader.data.entity.Feed import me.ash.reader.data.entity.Group +import me.ash.reader.ui.ext.alphaLN import me.ash.reader.ui.page.home.feeds.option.group.GroupOptionViewAction import me.ash.reader.ui.page.home.feeds.option.group.GroupOptionViewModel @@ -34,6 +36,7 @@ import me.ash.reader.ui.page.home.feeds.option.group.GroupOptionViewModel @Composable fun GroupItem( modifier: Modifier = Modifier, + tonalElevation: Dp, group: Group, feeds: List, isExpanded: Boolean = true, @@ -50,7 +53,9 @@ fun GroupItem( .fillMaxWidth() .padding(horizontal = 16.dp) .clip(RoundedCornerShape(32.dp)) - .background(MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.14f)) + .background( + MaterialTheme.colorScheme.secondary.copy(alpha = tonalElevation.alphaLN(weight = 1.2f)) + ) .combinedClickable( onClick = { groupOnClick() @@ -82,7 +87,11 @@ fun GroupItem( .padding(end = 20.dp) .size(24.dp) .clip(CircleShape) - .background(MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.24f)) + .background( + MaterialTheme.colorScheme.surfaceTint.copy( + alpha = tonalElevation.alphaLN(weight = 1.4f) + ) + ) .clickable { expanded = !expanded }, @@ -107,6 +116,7 @@ fun GroupItem( FeedItem( modifier = Modifier.padding(horizontal = 20.dp), feed = feed, + tonalElevation = tonalElevation, ) { feedOnClick(feed) } 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 640cb8d..c4e30f2 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 @@ -21,14 +21,8 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import me.ash.reader.R import me.ash.reader.data.entity.ArticleWithFeed -import me.ash.reader.data.preference.* -import me.ash.reader.data.preference.ArticleListDatePreference.Companion.articleListDate -import me.ash.reader.data.preference.ArticleListDescPreference.Companion.articleListDesc -import me.ash.reader.data.preference.ArticleListFeedIconPreference.Companion.articleListFeedIcon -import me.ash.reader.data.preference.ArticleListFeedNamePreference.Companion.articleListFeedName -import me.ash.reader.data.preference.ArticleListImagePreference.Companion.articleListImage -import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.formatAsString +import me.ash.reader.ui.theme.* @Composable fun ArticleItem( @@ -37,16 +31,11 @@ fun ArticleItem( onClick: (ArticleWithFeed) -> Unit = {}, ) { val context = LocalContext.current - val articleListFeedIcon = - context.articleListFeedIcon.collectAsStateValue(initial = ArticleListFeedIconPreference.default) - val articleListFeedName = - context.articleListFeedName.collectAsStateValue(initial = ArticleListFeedNamePreference.default) - val articleListImage = - context.articleListImage.collectAsStateValue(initial = ArticleListImagePreference.default) - val articleListDesc = - context.articleListDesc.collectAsStateValue(initial = ArticleListDescPreference.default) - val articleListDate = - context.articleListDate.collectAsStateValue(initial = ArticleListDatePreference.default) + val articleListFeedIcon = LocalFlowArticleListFeedIcon.current + val articleListFeedName = LocalFlowArticleListFeedName.current + val articleListImage = LocalFlowArticleListImage.current + val articleListDesc = LocalFlowArticleListDesc.current + val articleListDate = LocalFlowArticleListDate.current Column( modifier = Modifier @@ -62,11 +51,11 @@ fun ArticleItem( verticalAlignment = Alignment.CenterVertically, ) { // Feed name - if (articleListFeedName.value) { + if (articleListFeedName) { Text( modifier = Modifier .weight(1f) - .padding(start = if (articleListFeedIcon.value) 30.dp else 0.dp), + .padding(start = if (articleListFeedIcon) 30.dp else 0.dp), text = articleWithFeed.feed.name, color = MaterialTheme.colorScheme.tertiary, style = MaterialTheme.typography.labelMedium, @@ -75,11 +64,13 @@ fun ArticleItem( ) } - if (articleListDate.value) { + if (articleListDate) { Row( - modifier = Modifier.padding(start = 6.dp), verticalAlignment = Alignment.CenterVertically, ) { + if (!articleListFeedName) { + Spacer(Modifier.width(if (articleListFeedIcon) 30.dp else 0.dp)) + } // Starred if (articleWithFeed.article.isStarred) { Icon( @@ -91,7 +82,7 @@ fun ArticleItem( tint = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f), ) } - + // Date Text( text = articleWithFeed.article.date.formatAsString( @@ -108,7 +99,7 @@ fun ArticleItem( modifier = Modifier.fillMaxWidth(), ) { // Feed icon - if (articleListFeedIcon.value) { + if (articleListFeedIcon) { Row( modifier = Modifier .size(20.dp) @@ -126,11 +117,11 @@ fun ArticleItem( text = articleWithFeed.article.title, color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.titleMedium, - maxLines = if (articleListDesc.value) 2 else 4, + maxLines = if (articleListDesc) 2 else 4, overflow = TextOverflow.Ellipsis, ) // Description - if (articleListDesc.value) { + if (articleListDesc) { Text( text = articleWithFeed.article.shortDescription, color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f), diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt index 678cdbd..8ed73cb 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt @@ -27,10 +27,6 @@ import androidx.paging.compose.LazyPagingItems import kotlinx.coroutines.delay import kotlinx.coroutines.launch import me.ash.reader.R -import me.ash.reader.data.preference.ArticleListFeedIconPreference -import me.ash.reader.data.preference.ArticleListFeedIconPreference.Companion.articleListFeedIcon -import me.ash.reader.data.preference.ArticleListTonalElevationPreference -import me.ash.reader.data.preference.ArticleListTonalElevationPreference.Companion.articleListTonalElevation import me.ash.reader.data.repository.SyncWorker.Companion.getIsSyncing import me.ash.reader.ui.component.DisplayText import me.ash.reader.ui.component.FeedbackIconButton @@ -43,6 +39,8 @@ import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.FilterState import me.ash.reader.ui.page.home.HomeViewAction import me.ash.reader.ui.page.home.HomeViewModel +import me.ash.reader.ui.theme.* +import me.ash.reader.ui.theme.palette.onDark @OptIn( ExperimentalMaterial3Api::class, @@ -59,6 +57,13 @@ fun FlowPage( ) { val context = LocalContext.current val keyboardController = LocalSoftwareKeyboardController.current + val topBarTonalElevation = LocalFlowTopBarTonalElevation.current + val articleListTonalElevation = LocalFlowArticleListTonalElevation.current + val articleListFeedIcon = LocalFlowArticleListFeedIcon.current + val filterBarStyle = LocalFlowFilterBarStyle.current + val filterBarFilled = LocalFlowFilterBarFilled.current + val filterBarPadding = LocalFlowFilterBarPadding.current + val filterBarTonalElevation = LocalFlowFilterBarTonalElevation.current val scope = rememberCoroutineScope() val focusRequester = remember { FocusRequester() } @@ -70,11 +75,6 @@ fun FlowPage( val homeViewState = homeViewModel.viewState.collectAsStateValue() val listState = if (pagingItems.itemCount > 0) viewState.listState else rememberLazyListState() - val articleListTonalElevation = - context.articleListTonalElevation.collectAsStateValue(initial = ArticleListTonalElevationPreference.default) - val articleListFeedIcon = - context.articleListFeedIcon.collectAsStateValue(initial = ArticleListFeedIconPreference.default) - val owner = LocalLifecycleOwner.current var isSyncing by remember { mutableStateOf(false) } homeViewModel.syncWorkLiveData.observe(owner) { @@ -109,16 +109,18 @@ fun FlowPage( Scaffold( modifier = Modifier - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp)) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(topBarTonalElevation.dp)) .statusBarsPadding() .navigationBarsPadding(), - containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp), + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( + articleListTonalElevation.dp + ) onDark MaterialTheme.colorScheme.surface, topBar = { SmallTopAppBar( title = {}, colors = TopAppBarDefaults.smallTopAppBarColors( containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( - articleListTonalElevation.value.dp + topBarTonalElevation.dp ), ), navigationIcon = { @@ -197,7 +199,7 @@ fun FlowPage( state = listState, ) { item { - DisplayTextHeader(filterState, isSyncing, articleListFeedIcon.value) + DisplayTextHeader(filterState, isSyncing, articleListFeedIcon) AnimatedVisibility( visible = markAsRead, enter = fadeIn() + expandVertically(), @@ -259,8 +261,8 @@ fun FlowPage( } ArticleList( pagingItems = pagingItems, - articleListFeedIcon = articleListFeedIcon.value, - articleListTonalElevation = articleListTonalElevation.value, + articleListFeedIcon = articleListFeedIcon, + articleListTonalElevation = articleListTonalElevation, ) { onSearch = false navController.navigate("${RouteName.READING}/${it.article.id}") { @@ -279,12 +281,15 @@ fun FlowPage( bottomBar = { FilterBar( filter = filterState.filter, - filterOnClick = { - flowViewModel.dispatch(FlowViewAction.ScrollToItem(0)) - homeViewModel.dispatch(HomeViewAction.ChangeFilter(filterState.copy(filter = it))) - homeViewModel.dispatch(HomeViewAction.FetchArticles) - }, - ) + filterBarStyle = filterBarStyle, + filterBarFilled = filterBarFilled, + filterBarPadding = filterBarPadding.dp, + filterBarTonalElevation = filterBarTonalElevation.dp, + ) { + flowViewModel.dispatch(FlowViewAction.ScrollToItem(0)) + homeViewModel.dispatch(HomeViewAction.ChangeFilter(filterState.copy(filter = it))) + homeViewModel.dispatch(HomeViewAction.FetchArticles) + } } ) } diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt index 93125e0..dcda056 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/StickyHeader.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import me.ash.reader.ui.ext.surfaceColorAtElevation +import me.ash.reader.ui.theme.palette.onDark @Composable fun StickyHeader( @@ -21,12 +22,17 @@ fun StickyHeader( Row( modifier = Modifier .fillMaxWidth() - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.dp)), + .background( + MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.dp) + onDark MaterialTheme.colorScheme.surface + ), verticalAlignment = Alignment.CenterVertically ) { Text( - modifier = Modifier - .padding(start = if (articleListFeedIcon) 54.dp else 24.dp, bottom = 4.dp), + modifier = Modifier.padding( + start = if (articleListFeedIcon) 54.dp else 24.dp, + bottom = 4.dp + ), text = currentItemDay, color = MaterialTheme.colorScheme.primary, style = MaterialTheme.typography.labelLarge, diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt index 55e491b..b7c8db7 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt @@ -28,12 +28,17 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.R +import me.ash.reader.data.preference.ThemePreference import me.ash.reader.ui.component.* -import me.ash.reader.ui.ext.* +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.customPrimaryColor +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.settings.SettingItem import me.ash.reader.ui.svg.PALETTE import me.ash.reader.ui.svg.SVGString +import me.ash.reader.ui.theme.LocalTheme import me.ash.reader.ui.theme.LocalUseDarkTheme import me.ash.reader.ui.theme.palette.* import me.ash.reader.ui.theme.palette.TonalPalettes.Companion.toTonalPalettes @@ -47,8 +52,9 @@ fun ColorAndStyle( ) { val context = LocalContext.current val useDarkTheme = LocalUseDarkTheme.current + val theme = LocalTheme.current val wallpaperTonalPalettes = extractTonalPalettesFromUserWallpaper() - var radioButtonSelected by remember { mutableStateOf(if (context.themeIndex > 4) 0 else 1) } + var radioButtonSelected by remember { mutableStateOf(if (theme > 4) 0 else 1) } Scaffold( modifier = Modifier @@ -163,8 +169,11 @@ fun ColorAndStyle( ) SettingItem( title = stringResource(R.string.feeds_page), - enable = false, - onClick = {}, + onClick = { + navController.navigate(RouteName.FEEDS_PAGE_STYLE) { + launchSingleTop = true + } + }, ) {} SettingItem( title = stringResource(R.string.flow_page), @@ -245,12 +254,7 @@ fun Palettes( if (isCustom) { addDialogVisible = true } else { - scope.launch(Dispatchers.IO) { - context.dataStore.put( - DataStoreKeys.ThemeIndex, - themeIndexPrefix + index - ) - } + ThemePreference.put(context, scope, themeIndexPrefix + index) } }, palette = if (isCustom) tonalPalettes else palette diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt new file mode 100644 index 0000000..fdb19bc --- /dev/null +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt @@ -0,0 +1,379 @@ +package me.ash.reader.ui.page.settings.color.feeds + +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Add +import androidx.compose.material.icons.rounded.ArrowBack +import androidx.compose.material.icons.rounded.Refresh +import androidx.compose.material3.* +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import androidx.navigation.NavHostController +import me.ash.reader.R +import me.ash.reader.data.entity.Feed +import me.ash.reader.data.entity.Filter +import me.ash.reader.data.entity.Group +import me.ash.reader.data.preference.* +import me.ash.reader.data.preference.FeedsFilterBarFilledPreference.Companion.feedsFilterBarFilled +import me.ash.reader.data.preference.FeedsFilterBarPaddingPreference.feedsFilterBarPadding +import me.ash.reader.data.preference.FeedsFilterBarStylePreference.Companion.feedsFilterBarStyle +import me.ash.reader.data.preference.FeedsFilterBarTonalElevationPreference.Companion.feedsFilterBarTonalElevation +import me.ash.reader.data.preference.FeedsGroupListExpandPreference.Companion.feedsGroupListExpand +import me.ash.reader.data.preference.FeedsGroupListTonalElevationPreference.Companion.feedsGroupListTonalElevation +import me.ash.reader.data.preference.FeedsTopBarTonalElevationPreference.Companion.feedsTopBarTonalElevation +import me.ash.reader.ui.component.* +import me.ash.reader.ui.ext.collectAsStateValue +import me.ash.reader.ui.ext.surfaceColorAtElevation +import me.ash.reader.ui.page.home.FilterBar +import me.ash.reader.ui.page.home.feeds.GroupItem +import me.ash.reader.ui.page.settings.SettingItem +import me.ash.reader.ui.theme.palette.onDark +import me.ash.reader.ui.theme.palette.onLight + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun FeedsPageStyle( + navController: NavHostController, +) { + val context = LocalContext.current + val scope = rememberCoroutineScope() + val filterBarStyle = + context.feedsFilterBarStyle.collectAsStateValue(initial = FeedsFilterBarStylePreference.default) + val filterBarFilled = + context.feedsFilterBarFilled.collectAsStateValue(initial = FeedsFilterBarFilledPreference.default) + val filterBarPadding = + context.feedsFilterBarPadding.collectAsStateValue(initial = FeedsFilterBarPaddingPreference.default) + val filterBarTonalElevation = + context.feedsFilterBarTonalElevation.collectAsStateValue(initial = FeedsFilterBarTonalElevationPreference.default) + val topBarTonalElevation = + context.feedsTopBarTonalElevation.collectAsStateValue(initial = FeedsTopBarTonalElevationPreference.default) + val groupListExpand = + context.feedsGroupListExpand.collectAsStateValue(initial = FeedsGroupListExpandPreference.default) + val groupListTonalElevation = + context.feedsGroupListTonalElevation.collectAsStateValue(initial = FeedsGroupListTonalElevationPreference.default) + + var filterBarStyleDialogVisible by remember { mutableStateOf(false) } + var filterBarPaddingDialogVisible by remember { mutableStateOf(false) } + var filterBarTonalElevationDialogVisible by remember { mutableStateOf(false) } + var topBarTonalElevationDialogVisible by remember { mutableStateOf(false) } + var groupListTonalElevationDialogVisible by remember { mutableStateOf(false) } + + var filterBarPaddingValue: Int? by remember { mutableStateOf(filterBarPadding) } + + Scaffold( + modifier = Modifier + .background(MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface) + .statusBarsPadding() + .navigationBarsPadding(), + containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface, + topBar = { + SmallTopAppBar( + colors = TopAppBarDefaults.smallTopAppBarColors( + containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface + ), + title = {}, + navigationIcon = { + FeedbackIconButton( + imageVector = Icons.Rounded.ArrowBack, + contentDescription = stringResource(R.string.back), + tint = MaterialTheme.colorScheme.onSurface + ) { + navController.popBackStack() + } + }, + actions = {} + ) + }, + content = { + LazyColumn { + item { + DisplayText(text = stringResource(R.string.feeds_page), desc = "") + } + + // Preview + item { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 24.dp) + .clip(RoundedCornerShape(24.dp)) + .background( + MaterialTheme.colorScheme.inverseOnSurface + onLight MaterialTheme.colorScheme.surface.copy(0.7f) + ) + .clickable { }, + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.CenterVertically + ) { + FeedsPagePreview( + topBarTonalElevation = topBarTonalElevation, + groupListExpand = groupListExpand, + groupListTonalElevation = groupListTonalElevation, + filterBarStyle = filterBarStyle.value, + filterBarFilled = filterBarFilled.value, + filterBarPadding = filterBarPadding.dp, + filterBarTonalElevation = filterBarTonalElevation.value.dp, + ) + } + Spacer(modifier = Modifier.height(24.dp)) + } + + // Top Bar + item { + Subtitle( + modifier = Modifier.padding(horizontal = 24.dp), + text = stringResource(R.string.top_bar) + ) + SettingItem( + title = stringResource(R.string.tonal_elevation), + desc = "${topBarTonalElevation.value}dp", + onClick = { + topBarTonalElevationDialogVisible = true + }, + ) {} + Tips(text = stringResource(R.string.tips_top_bar_tonal_elevation)) + Spacer(modifier = Modifier.height(24.dp)) + } + + // Group List + item { + Subtitle( + modifier = Modifier.padding(horizontal = 24.dp), + text = stringResource(R.string.group_list) + ) + SettingItem( + title = stringResource(R.string.always_expand), + onClick = { + (!groupListExpand).put(context, scope) + }, + ) { + Switch(activated = groupListExpand.value) { + (!groupListExpand).put(context, scope) + } + } + SettingItem( + title = stringResource(R.string.tonal_elevation), + desc = "${groupListTonalElevation.value}dp", + onClick = { + groupListTonalElevationDialogVisible = true + }, + ) {} + Tips(text = stringResource(R.string.tips_group_list_tonal_elevation)) + Spacer(modifier = Modifier.height(24.dp)) + } + + // Filter Bar + item { + Subtitle( + modifier = Modifier.padding(horizontal = 24.dp), + text = stringResource(R.string.filter_bar), + ) + SettingItem( + title = stringResource(R.string.style), + desc = filterBarStyle.getDesc(context), + onClick = { + filterBarStyleDialogVisible = true + }, + ) {} + SettingItem( + title = stringResource(R.string.fill_selected_icon), + onClick = { + (!filterBarFilled).put(context, scope) + }, + ) { + Switch(activated = filterBarFilled.value) { + (!filterBarFilled).put(context, scope) + } + } + SettingItem( + title = stringResource(R.string.padding_on_both_ends), + desc = "${filterBarPadding}dp", + onClick = { + filterBarPaddingValue = filterBarPadding + filterBarPaddingDialogVisible = true + }, + ) {} + SettingItem( + title = stringResource(R.string.tonal_elevation), + desc = "${filterBarTonalElevation.value}dp", + onClick = { + filterBarTonalElevationDialogVisible = true + }, + ) {} + Spacer(modifier = Modifier.height(24.dp)) + } + } + } + ) + + RadioDialog( + visible = filterBarStyleDialogVisible, + title = stringResource(R.string.style), + options = FeedsFilterBarStylePreference.values.map { + RadioDialogOption( + text = it.getDesc(context), + selected = filterBarStyle == it, + ) { + it.put(context, scope) + } + } + ) { + filterBarStyleDialogVisible = false + } + + TextFieldDialog( + visible = filterBarPaddingDialogVisible, + title = stringResource(R.string.padding_on_both_ends), + value = (filterBarPaddingValue ?: "").toString(), + placeholder = stringResource(R.string.value), + onValueChange = { + filterBarPaddingValue = it.filter { it.isDigit() }.toIntOrNull() + }, + onDismissRequest = { + filterBarPaddingDialogVisible = false + }, + onConfirm = { + FeedsFilterBarPaddingPreference.put(context, scope, filterBarPaddingValue ?: 0) + filterBarPaddingDialogVisible = false + } + ) + + RadioDialog( + visible = filterBarTonalElevationDialogVisible, + title = stringResource(R.string.tonal_elevation), + options = FeedsFilterBarTonalElevationPreference.values.map { + RadioDialogOption( + text = it.getDesc(context), + selected = filterBarTonalElevation == it, + ) { + it.put(context, scope) + } + } + ) { + filterBarTonalElevationDialogVisible = false + } + + RadioDialog( + visible = topBarTonalElevationDialogVisible, + title = stringResource(R.string.tonal_elevation), + options = FeedsTopBarTonalElevationPreference.values.map { + RadioDialogOption( + text = it.getDesc(context), + selected = topBarTonalElevation == it, + ) { + it.put(context, scope) + } + } + ) { + topBarTonalElevationDialogVisible = false + } + + RadioDialog( + visible = groupListTonalElevationDialogVisible, + title = stringResource(R.string.tonal_elevation), + options = FeedsGroupListTonalElevationPreference.values.map { + RadioDialogOption( + text = it.getDesc(context), + selected = groupListTonalElevation == it, + ) { + it.put(context, scope) + } + } + ) { + groupListTonalElevationDialogVisible = false + } +} + +@Composable +fun FeedsPagePreview( + topBarTonalElevation: FeedsTopBarTonalElevationPreference, + groupListExpand: FeedsGroupListExpandPreference, + groupListTonalElevation: FeedsGroupListTonalElevationPreference, + filterBarStyle: Int, + filterBarFilled: Boolean, + filterBarPadding: Dp, + filterBarTonalElevation: Dp, +) { + var filter by remember { mutableStateOf(Filter.Unread) } + + Column( + modifier = Modifier + .background( + color = MaterialTheme.colorScheme.surfaceColorAtElevation( + groupListTonalElevation.value.dp + ) onDark MaterialTheme.colorScheme.surface, + shape = RoundedCornerShape(24.dp) + ) + ) { + SmallTopAppBar( + title = {}, + colors = TopAppBarDefaults.smallTopAppBarColors( + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( + topBarTonalElevation.value.dp + ), + ), + navigationIcon = { + FeedbackIconButton( + imageVector = Icons.Rounded.ArrowBack, + contentDescription = stringResource(R.string.back), + tint = MaterialTheme.colorScheme.onSurface + ) {} + }, + actions = { + FeedbackIconButton( + imageVector = Icons.Rounded.Refresh, + contentDescription = stringResource(R.string.refresh), + tint = MaterialTheme.colorScheme.onSurface, + ) {} + FeedbackIconButton( + imageVector = Icons.Rounded.Add, + contentDescription = stringResource(R.string.subscribe), + tint = MaterialTheme.colorScheme.onSurface, + ) {} + } + ) + Spacer(modifier = Modifier.height(12.dp)) + GroupItem( + isExpanded = groupListExpand.value, + tonalElevation = groupListTonalElevation.value.dp, + group = Group( + id = "", + name = stringResource(R.string.defaults), + accountId = 0, + ), + feeds = listOf( + Feed( + id = "", + name = stringResource(R.string.preview_feed_name), + icon = "", + accountId = 0, + groupId = "", + url = "", + ).apply { + important = 100 + } + ), + ) + Spacer(modifier = Modifier.height(12.dp)) + FilterBar( + modifier = Modifier.padding(horizontal = 12.dp), + filter = filter, + filterBarStyle = filterBarStyle, + filterBarFilled = filterBarFilled, + filterBarPadding = filterBarPadding, + filterBarTonalElevation = filterBarTonalElevation, + ) { + filter = it + } + } +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/feedsPageStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt similarity index 56% rename from app/src/main/java/me/ash/reader/ui/page/settings/color/flow/feedsPageStyle.kt rename to app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt index ab04904..046c939 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/feedsPageStyle.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt @@ -8,6 +8,8 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.ArrowBack +import androidx.compose.material.icons.rounded.DoneAll +import androidx.compose.material.icons.rounded.Search import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Alignment @@ -15,6 +17,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController import me.ash.reader.R @@ -23,22 +26,24 @@ import me.ash.reader.data.entity.ArticleWithFeed import me.ash.reader.data.entity.Feed import me.ash.reader.data.entity.Filter import me.ash.reader.data.preference.* -import me.ash.reader.data.preference.ArticleListDatePreference.Companion.articleListDate -import me.ash.reader.data.preference.ArticleListDescPreference.Companion.articleListDesc -import me.ash.reader.data.preference.ArticleListFeedIconPreference.Companion.articleListFeedIcon -import me.ash.reader.data.preference.ArticleListFeedNamePreference.Companion.articleListFeedName -import me.ash.reader.data.preference.ArticleListImagePreference.Companion.articleListImage -import me.ash.reader.data.preference.ArticleListTonalElevationPreference.Companion.articleListTonalElevation -import me.ash.reader.data.preference.FilterBarFilledPreference.Companion.filterBarFilled -import me.ash.reader.data.preference.FilterBarPaddingPreference.filterBarPadding -import me.ash.reader.data.preference.FilterBarStylePreference.Companion.filterBarStyle -import me.ash.reader.data.preference.FilterBarTonalElevationPreference.Companion.filterBarTonalElevation +import me.ash.reader.data.preference.FlowArticleListDatePreference.Companion.flowArticleListDate +import me.ash.reader.data.preference.FlowArticleListDescPreference.Companion.flowArticleListDesc +import me.ash.reader.data.preference.FlowArticleListFeedIconPreference.Companion.flowArticleListFeedIcon +import me.ash.reader.data.preference.FlowArticleListFeedNamePreference.Companion.flowArticleListFeedName +import me.ash.reader.data.preference.FlowArticleListImagePreference.Companion.flowArticleListImage +import me.ash.reader.data.preference.FlowArticleListTonalElevationPreference.Companion.flowArticleListTonalElevation +import me.ash.reader.data.preference.FlowFilterBarFilledPreference.Companion.flowFilterBarFilled +import me.ash.reader.data.preference.FlowFilterBarPaddingPreference.flowFilterBarPadding +import me.ash.reader.data.preference.FlowFilterBarStylePreference.Companion.flowFilterBarStyle +import me.ash.reader.data.preference.FlowFilterBarTonalElevationPreference.Companion.flowFilterBarTonalElevation +import me.ash.reader.data.preference.FlowTopBarTonalElevationPreference.Companion.flowTopBarTonalElevation import me.ash.reader.ui.component.* import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.surfaceColorAtElevation import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.flow.ArticleItem import me.ash.reader.ui.page.settings.SettingItem +import me.ash.reader.ui.theme.palette.onDark import me.ash.reader.ui.theme.palette.onLight import java.util.* @@ -51,29 +56,32 @@ fun FlowPageStyle( val context = LocalContext.current val scope = rememberCoroutineScope() val filterBarStyle = - context.filterBarStyle.collectAsStateValue(initial = FilterBarStylePreference.default) + context.flowFilterBarStyle.collectAsStateValue(initial = FlowFilterBarStylePreference.default) val filterBarFilled = - context.filterBarFilled.collectAsStateValue(initial = FilterBarFilledPreference.default) + context.flowFilterBarFilled.collectAsStateValue(initial = FlowFilterBarFilledPreference.default) val filterBarPadding = - context.filterBarPadding.collectAsStateValue(initial = FilterBarPaddingPreference.default) + context.flowFilterBarPadding.collectAsStateValue(initial = FlowFilterBarPaddingPreference.default) val filterBarTonalElevation = - context.filterBarTonalElevation.collectAsStateValue(initial = FilterBarTonalElevationPreference.default) + context.flowFilterBarTonalElevation.collectAsStateValue(initial = FlowFilterBarTonalElevationPreference.default) + val topBarTonalElevation = + context.flowTopBarTonalElevation.collectAsStateValue(initial = FlowTopBarTonalElevationPreference.default) val articleListFeedIcon = - context.articleListFeedIcon.collectAsStateValue(initial = ArticleListFeedIconPreference.default) + context.flowArticleListFeedIcon.collectAsStateValue(initial = FlowArticleListFeedIconPreference.default) val articleListFeedName = - context.articleListFeedName.collectAsStateValue(initial = ArticleListFeedNamePreference.default) + context.flowArticleListFeedName.collectAsStateValue(initial = FlowArticleListFeedNamePreference.default) val articleListImage = - context.articleListImage.collectAsStateValue(initial = ArticleListImagePreference.default) + context.flowArticleListImage.collectAsStateValue(initial = FlowArticleListImagePreference.default) val articleListDesc = - context.articleListDesc.collectAsStateValue(initial = ArticleListDescPreference.default) + context.flowArticleListDesc.collectAsStateValue(initial = FlowArticleListDescPreference.default) val articleListDate = - context.articleListDate.collectAsStateValue(initial = ArticleListDatePreference.default) + context.flowArticleListDate.collectAsStateValue(initial = FlowArticleListDatePreference.default) val articleListTonalElevation = - context.articleListTonalElevation.collectAsStateValue(initial = ArticleListTonalElevationPreference.default) + context.flowArticleListTonalElevation.collectAsStateValue(initial = FlowArticleListTonalElevationPreference.default) var filterBarStyleDialogVisible by remember { mutableStateOf(false) } var filterBarPaddingDialogVisible by remember { mutableStateOf(false) } var filterBarTonalElevationDialogVisible by remember { mutableStateOf(false) } + var topBarTonalElevationDialogVisible by remember { mutableStateOf(false) } var articleListTonalElevationDialogVisible by remember { mutableStateOf(false) } var filterBarPaddingValue: Int? by remember { mutableStateOf(filterBarPadding) } @@ -107,6 +115,8 @@ fun FlowPageStyle( item { DisplayText(text = stringResource(R.string.flow_page), desc = "") } + + // Preview item { Row( modifier = Modifier @@ -121,67 +131,49 @@ fun FlowPageStyle( horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { - FeedsPagePreview(articleListTonalElevation) + FlowPagePreview( + topBarTonalElevation = topBarTonalElevation, + articleListTonalElevation = articleListTonalElevation, + filterBarStyle = filterBarStyle.value, + filterBarFilled = filterBarFilled.value, + filterBarPadding = filterBarPadding.dp, + filterBarTonalElevation = filterBarTonalElevation.value.dp, + ) } Spacer(modifier = Modifier.height(24.dp)) } + + // Top Bar item { Subtitle( modifier = Modifier.padding(horizontal = 24.dp), - text = "过滤栏", + text = stringResource(R.string.top_bar) ) SettingItem( - title = "样式", - desc = filterBarStyle.getDesc(context), - onClick = { - filterBarStyleDialogVisible = true - }, - ) {} - SettingItem( - title = "填充已选中的图标", - onClick = { - (!filterBarFilled).put(context, scope) - }, - ) { - Switch(activated = filterBarFilled.value) { - (!filterBarFilled).put(context, scope) - } - } - SettingItem( - title = "两端边距", - desc = "${filterBarPadding}dp", - onClick = { - filterBarPaddingDialogVisible = true - }, - ) {} - SettingItem( - title = "色调海拔", - desc = "${filterBarTonalElevation.value}dp", - onClick = { - filterBarTonalElevationDialogVisible = true - }, - ) {} - Spacer(modifier = Modifier.height(24.dp)) - } - item { - Subtitle( - modifier = Modifier.padding(horizontal = 24.dp), - text = "标题栏" - ) - SettingItem( - title = "“标记为已读”按钮的位置", - desc = "顶部", + title = stringResource(R.string.mark_as_read_button_position), + desc = stringResource(R.string.top), + enable = false, onClick = {}, ) {} + SettingItem( + title = stringResource(R.string.tonal_elevation), + desc = "${topBarTonalElevation.value}dp", + onClick = { + topBarTonalElevationDialogVisible = true + }, + ) {} + Tips(text = stringResource(R.string.tips_top_bar_tonal_elevation)) Spacer(modifier = Modifier.height(24.dp)) } + + // Article List item { Subtitle( modifier = Modifier.padding(horizontal = 24.dp), - text = "文章列表" + text = stringResource(R.string.article_list) ) SettingItem( - title = "显示订阅源图标", + title = stringResource(R.string.display_feed_favicon), onClick = { (!articleListFeedIcon).put(context, scope) }, @@ -191,7 +183,7 @@ fun FlowPageStyle( } } SettingItem( - title = "显示订阅源名称", + title = stringResource(R.string.display_feed_name), onClick = { (!articleListFeedName).put(context, scope) }, @@ -201,13 +193,14 @@ fun FlowPageStyle( } } SettingItem( - title = "显示文章插图", + title = stringResource(R.string.display_article_image), + enable = false, onClick = {}, ) { Switch(activated = false, enable = false) } SettingItem( - title = "显示文章描述", + title = stringResource(R.string.display_article_desc), onClick = { (!articleListDesc).put(context, scope) }, @@ -217,7 +210,7 @@ fun FlowPageStyle( } } SettingItem( - title = "显示文章发布时间", + title = stringResource(R.string.display_article_date), onClick = { (!articleListDate).put(context, scope) }, @@ -227,12 +220,54 @@ fun FlowPageStyle( } } SettingItem( - title = "色调海拔", + title = stringResource(R.string.tonal_elevation), desc = "${articleListTonalElevation.value}dp", onClick = { articleListTonalElevationDialogVisible = true }, ) {} + Tips(text = stringResource(R.string.tips_article_list_tonal_elevation)) + Spacer(modifier = Modifier.height(24.dp)) + } + + // Filter Bar + item { + Subtitle( + modifier = Modifier.padding(horizontal = 24.dp), + text = stringResource(R.string.filter_bar), + ) + SettingItem( + title = stringResource(R.string.style), + desc = filterBarStyle.getDesc(context), + onClick = { + filterBarStyleDialogVisible = true + }, + ) {} + SettingItem( + title = stringResource(R.string.fill_selected_icon), + onClick = { + (!filterBarFilled).put(context, scope) + }, + ) { + Switch(activated = filterBarFilled.value) { + (!filterBarFilled).put(context, scope) + } + } + SettingItem( + title = stringResource(R.string.padding_on_both_ends), + desc = "${filterBarPadding}dp", + onClick = { + filterBarPaddingValue = filterBarPadding + filterBarPaddingDialogVisible = true + }, + ) {} + SettingItem( + title = stringResource(R.string.tonal_elevation), + desc = "${filterBarTonalElevation.value}dp", + onClick = { + filterBarTonalElevationDialogVisible = true + }, + ) {} Spacer(modifier = Modifier.height(24.dp)) } } @@ -241,8 +276,8 @@ fun FlowPageStyle( RadioDialog( visible = filterBarStyleDialogVisible, - title = stringResource(R.string.initial_filter), - options = FilterBarStylePreference.values.map { + title = stringResource(R.string.style), + options = FlowFilterBarStylePreference.values.map { RadioDialogOption( text = it.getDesc(context), selected = filterBarStyle == it, @@ -256,17 +291,17 @@ fun FlowPageStyle( TextFieldDialog( visible = filterBarPaddingDialogVisible, - title = "两端边距", + title = stringResource(R.string.padding_on_both_ends), value = (filterBarPaddingValue ?: "").toString(), - placeholder = stringResource(R.string.name), + placeholder = stringResource(R.string.value), onValueChange = { - filterBarPaddingValue = it.toIntOrNull() + filterBarPaddingValue = it.filter { it.isDigit() }.toIntOrNull() }, onDismissRequest = { filterBarPaddingDialogVisible = false }, onConfirm = { - FilterBarPaddingPreference.put(context, scope, filterBarPaddingValue ?: 0) + FlowFilterBarPaddingPreference.put(context, scope, filterBarPaddingValue ?: 0) filterBarPaddingDialogVisible = false } ) @@ -274,7 +309,7 @@ fun FlowPageStyle( RadioDialog( visible = filterBarTonalElevationDialogVisible, title = stringResource(R.string.tonal_elevation), - options = FilterBarTonalElevationPreference.values.map { + options = FlowFilterBarTonalElevationPreference.values.map { RadioDialogOption( text = it.getDesc(context), selected = filterBarTonalElevation == it, @@ -286,10 +321,25 @@ fun FlowPageStyle( filterBarTonalElevationDialogVisible = false } + RadioDialog( + visible = topBarTonalElevationDialogVisible, + title = stringResource(R.string.tonal_elevation), + options = FlowTopBarTonalElevationPreference.values.map { + RadioDialogOption( + text = it.getDesc(context), + selected = topBarTonalElevation == it, + ) { + it.put(context, scope) + } + } + ) { + topBarTonalElevationDialogVisible = false + } + RadioDialog( visible = articleListTonalElevationDialogVisible, title = stringResource(R.string.tonal_elevation), - options = ArticleListTonalElevationPreference.values.map { + options = FlowArticleListTonalElevationPreference.values.map { RadioDialogOption( text = it.getDesc(context), selected = articleListTonalElevation == it, @@ -303,43 +353,85 @@ fun FlowPageStyle( } @Composable -fun FeedsPagePreview( - articleListTonalElevation: ArticleListTonalElevationPreference, +fun FlowPagePreview( + topBarTonalElevation: FlowTopBarTonalElevationPreference, + articleListTonalElevation: FlowArticleListTonalElevationPreference, + filterBarStyle: Int, + filterBarFilled: Boolean, + filterBarPadding: Dp, + filterBarTonalElevation: Dp, ) { var filter by remember { mutableStateOf(Filter.Unread) } Column( modifier = Modifier .background( - color = MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp), + color = MaterialTheme.colorScheme.surfaceColorAtElevation( + articleListTonalElevation.value.dp + ) onDark MaterialTheme.colorScheme.surface, shape = RoundedCornerShape(24.dp) ) ) { + SmallTopAppBar( + title = {}, + colors = TopAppBarDefaults.smallTopAppBarColors( + containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( + topBarTonalElevation.value.dp + ), + ), + navigationIcon = { + FeedbackIconButton( + imageVector = Icons.Rounded.ArrowBack, + contentDescription = stringResource(R.string.back), + tint = MaterialTheme.colorScheme.onSurface + ) {} + }, + actions = { + FeedbackIconButton( + imageVector = Icons.Rounded.DoneAll, + contentDescription = stringResource(R.string.mark_all_as_read), + tint = MaterialTheme.colorScheme.onSurface, + ) {} + FeedbackIconButton( + imageVector = Icons.Rounded.Search, + contentDescription = stringResource(R.string.search), + tint = MaterialTheme.colorScheme.onSurface, + ) {} + } + ) Spacer(modifier = Modifier.height(12.dp)) ArticleItem( articleWithFeed = ArticleWithFeed( Article( id = "", - title = "《黎明之剑》撒花完结,白金远瞳的“希灵三部曲”值得你通宵阅读", - shortDescription = "昨日在找书的时候无意间发现,“远瞳”的《黎明之剑》突然冲上了起点热搜榜首位,去小说中查找原因,原来是这部六百多万字的作品已经完结了。四年的时间,这部小说始终占据科幻分类前三甲的位置,不得不说“远瞳”的实力的确不容小觑。", - rawDescription = "昨日在找书的时候无意间发现,“远瞳”的《黎明之剑》突然冲上了起点热搜榜首位,去小说中查找原因,原来是这部六百多万字的作品已经完结了。四年的时间,这部小说始终占据科幻分类前三甲的位置,不得不说“远瞳”的实力的确不容小觑。", + title = stringResource(R.string.preview_article_title), + shortDescription = stringResource(R.string.preview_article_desc), + rawDescription = stringResource(R.string.preview_article_desc), link = "", feedId = "", accountId = 0, date = Date(), + isStarred = true, ), feed = Feed( id = "", - name = "佛门射手", + name = stringResource(R.string.preview_feed_name), icon = "", accountId = 0, groupId = "", url = "", - ) + ), ) ) Spacer(modifier = Modifier.height(12.dp)) - FilterBar(modifier = Modifier.padding(horizontal = 12.dp), filter = filter) { + FilterBar( + modifier = Modifier.padding(horizontal = 12.dp), + filter = filter, + filterBarStyle = filterBarStyle, + filterBarFilled = filterBarFilled, + filterBarPadding = filterBarPadding, + filterBarTonalElevation = filterBarTonalElevation, + ) { filter = it } } diff --git a/app/src/main/java/me/ash/reader/ui/page/startup/StartupPage.kt b/app/src/main/java/me/ash/reader/ui/page/startup/StartupPage.kt index c302a91..cc30fbd 100644 --- a/app/src/main/java/me/ash/reader/ui/page/startup/StartupPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/startup/StartupPage.kt @@ -6,7 +6,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.layout.* import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.Info import androidx.compose.material.icons.rounded.CheckCircleOutline import androidx.compose.material3.* import androidx.compose.runtime.Composable @@ -21,6 +20,7 @@ import kotlinx.coroutines.launch import me.ash.reader.R import me.ash.reader.ui.component.DisplayText import me.ash.reader.ui.component.DynamicSVGImage +import me.ash.reader.ui.component.Tips import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put @@ -57,14 +57,12 @@ fun StartupPage( ) } item { - TipsItem( - modifier = Modifier - .padding(horizontal = 24.dp) - .padding(top = 40.dp) + Tips( + modifier = Modifier.padding(top = 40.dp), + text = stringResource(R.string.agree_terms), ) } item { - Spacer(modifier = Modifier.height(10.dp)) TextButton( modifier = Modifier.padding(horizontal = 12.dp), onClick = { @@ -119,26 +117,4 @@ fun StartupPage( ) } ) -} - -@Composable -private fun TipsItem( - modifier: Modifier = Modifier, -) { - Column( - modifier = modifier - .fillMaxWidth() - ) { - Icon( - imageVector = Icons.Outlined.Info, - contentDescription = stringResource(R.string.tips_and_support), - tint = MaterialTheme.colorScheme.onSurfaceVariant, - ) - Spacer(modifier = Modifier.height(22.dp)) - Text( - text = stringResource(R.string.agree_terms), - style = MaterialTheme.typography.titleSmall, - color = MaterialTheme.colorScheme.onSurfaceVariant, - ) - } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/ui/svg/SVGString.kt b/app/src/main/java/me/ash/reader/ui/svg/SVGString.kt index bbadd60..5bf1e59 100644 --- a/app/src/main/java/me/ash/reader/ui/svg/SVGString.kt +++ b/app/src/main/java/me/ash/reader/ui/svg/SVGString.kt @@ -10,6 +10,7 @@ object SVGString fun String.parseDynamicColor(tonalPalettes: TonalPalettes, isDarkTheme: Boolean): String = replace("fill=\"(.+?)\"".toRegex()) { val value = it.groupValues[1] + Log.i("RLog", "parseDynamicColor: $value") if (value.startsWith("#")) return@replace it.value try { val (scheme, tone) = value.split("(?<=\\d)(?=\\D)|(?=\\d)(?<=\\D)".toRegex()) @@ -24,6 +25,7 @@ fun String.parseDynamicColor(tonalPalettes: TonalPalettes, isDarkTheme: Boolean) }?.toArgb() ?: 0xFFFFFF "fill=\"${String.format("#%06X", 0xFFFFFF and argb)}\"" } catch (e: Exception) { + e.printStackTrace() Log.e("RLog", "parseDynamicColor: ${e.message}") it.value } diff --git a/app/src/main/java/me/ash/reader/ui/theme/Theme.kt b/app/src/main/java/me/ash/reader/ui/theme/Theme.kt index da76775..7354651 100644 --- a/app/src/main/java/me/ash/reader/ui/theme/Theme.kt +++ b/app/src/main/java/me/ash/reader/ui/theme/Theme.kt @@ -5,12 +5,29 @@ import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.compositionLocalOf import androidx.compose.ui.platform.LocalContext -import kotlinx.coroutines.flow.map -import me.ash.reader.ui.ext.DataStoreKeys -import me.ash.reader.ui.ext.dataStore +import me.ash.reader.data.preference.* +import me.ash.reader.data.preference.FeedsFilterBarFilledPreference.Companion.feedsFilterBarFilled +import me.ash.reader.data.preference.FeedsFilterBarPaddingPreference.feedsFilterBarPadding +import me.ash.reader.data.preference.FeedsFilterBarStylePreference.Companion.feedsFilterBarStyle +import me.ash.reader.data.preference.FeedsFilterBarTonalElevationPreference.Companion.feedsFilterBarTonalElevation +import me.ash.reader.data.preference.FeedsGroupListExpandPreference.Companion.feedsGroupListExpand +import me.ash.reader.data.preference.FeedsGroupListTonalElevationPreference.Companion.feedsGroupListTonalElevation +import me.ash.reader.data.preference.FeedsTopBarTonalElevationPreference.Companion.feedsTopBarTonalElevation +import me.ash.reader.data.preference.FlowArticleListDatePreference.Companion.flowArticleListDate +import me.ash.reader.data.preference.FlowArticleListDescPreference.Companion.flowArticleListDesc +import me.ash.reader.data.preference.FlowArticleListFeedIconPreference.Companion.flowArticleListFeedIcon +import me.ash.reader.data.preference.FlowArticleListFeedNamePreference.Companion.flowArticleListFeedName +import me.ash.reader.data.preference.FlowArticleListImagePreference.Companion.flowArticleListImage +import me.ash.reader.data.preference.FlowArticleListTonalElevationPreference.Companion.flowArticleListTonalElevation +import me.ash.reader.data.preference.FlowFilterBarFilledPreference.Companion.flowFilterBarFilled +import me.ash.reader.data.preference.FlowFilterBarPaddingPreference.flowFilterBarPadding +import me.ash.reader.data.preference.FlowFilterBarStylePreference.Companion.flowFilterBarStyle +import me.ash.reader.data.preference.FlowFilterBarTonalElevationPreference.Companion.flowFilterBarTonalElevation +import me.ash.reader.data.preference.FlowTopBarTonalElevationPreference.Companion.flowTopBarTonalElevation +import me.ash.reader.data.preference.ThemePreference.Theme +import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.theme.palette.LocalTonalPalettes import me.ash.reader.ui.theme.palette.TonalPalettes import me.ash.reader.ui.theme.palette.core.ProvideZcamViewingConditions @@ -19,6 +36,36 @@ import me.ash.reader.ui.theme.palette.dynamicDarkColorScheme import me.ash.reader.ui.theme.palette.dynamicLightColorScheme val LocalUseDarkTheme = compositionLocalOf { false } +val LocalTheme = compositionLocalOf { ThemePreference.default } + +val LocalFeedsFilterBarStyle = compositionLocalOf { FeedsFilterBarStylePreference.default.value } +val LocalFeedsFilterBarFilled = compositionLocalOf { FeedsFilterBarFilledPreference.default.value } +val LocalFeedsFilterBarPadding = compositionLocalOf { FeedsFilterBarPaddingPreference.default } +val LocalFeedsFilterBarTonalElevation = + compositionLocalOf { FeedsFilterBarTonalElevationPreference.default.value } +val LocalFeedsTopBarTonalElevation = + compositionLocalOf { FeedsTopBarTonalElevationPreference.default.value } +val LocalFeedsGroupListExpand = + compositionLocalOf { FeedsGroupListExpandPreference.default.value } +val LocalFeedsGroupListTonalElevation = + compositionLocalOf { FeedsGroupListTonalElevationPreference.default.value } + +val LocalFlowFilterBarStyle = compositionLocalOf { FlowFilterBarStylePreference.default.value } +val LocalFlowFilterBarFilled = compositionLocalOf { FlowFilterBarFilledPreference.default.value } +val LocalFlowFilterBarPadding = compositionLocalOf { FlowFilterBarPaddingPreference.default } +val LocalFlowFilterBarTonalElevation = + compositionLocalOf { FlowFilterBarTonalElevationPreference.default.value } +val LocalFlowTopBarTonalElevation = + compositionLocalOf { FlowTopBarTonalElevationPreference.default.value } +val LocalFlowArticleListFeedIcon = + compositionLocalOf { FlowArticleListFeedIconPreference.default.value } +val LocalFlowArticleListFeedName = + compositionLocalOf { FlowArticleListFeedNamePreference.default.value } +val LocalFlowArticleListImage = compositionLocalOf { FlowArticleListImagePreference.default.value } +val LocalFlowArticleListDesc = compositionLocalOf { FlowArticleListDescPreference.default.value } +val LocalFlowArticleListDate = compositionLocalOf { FlowArticleListDatePreference.default.value } +val LocalFlowArticleListTonalElevation = + compositionLocalOf { FlowArticleListTonalElevationPreference.default.value } @SuppressLint("FlowOperatorInvokedInComposition") @Composable @@ -28,26 +75,83 @@ fun AppTheme( content: @Composable () -> Unit ) { val context = LocalContext.current - val themeIndex = context.dataStore.data - .map { it[DataStoreKeys.ThemeIndex.key] ?: 5 } - .collectAsState(initial = 5).value + val theme = context.Theme.collectAsStateValue(initial = ThemePreference.default) val tonalPalettes = wallpaperPalettes[ - if (themeIndex >= wallpaperPalettes.size) { + if (theme >= wallpaperPalettes.size) { when { wallpaperPalettes.size == 5 -> 0 wallpaperPalettes.size > 5 -> 5 else -> 0 } } else { - themeIndex + theme } ] + val feedsFilterBarStyle = + context.feedsFilterBarStyle.collectAsStateValue(initial = FeedsFilterBarStylePreference.default) + val feedsFilterBarFilled = + context.feedsFilterBarFilled.collectAsStateValue(initial = FeedsFilterBarFilledPreference.default) + val feedsFilterBarPadding = + context.feedsFilterBarPadding.collectAsStateValue(initial = FeedsFilterBarPaddingPreference.default) + val feedsFilterBarTonalElevation = + context.feedsFilterBarTonalElevation.collectAsStateValue(initial = FeedsFilterBarTonalElevationPreference.default) + val feedsTopBarTonalElevation = + context.feedsTopBarTonalElevation.collectAsStateValue(initial = FeedsTopBarTonalElevationPreference.default) + val feedsGroupListExpand = + context.feedsGroupListExpand.collectAsStateValue(initial = FeedsGroupListExpandPreference.default) + val feedsGroupListTonalElevation = + context.feedsGroupListTonalElevation.collectAsStateValue(initial = FeedsGroupListTonalElevationPreference.default) + + val flowFilterBarStyle = + context.flowFilterBarStyle.collectAsStateValue(initial = FlowFilterBarStylePreference.default) + val flowFilterBarFilled = + context.flowFilterBarFilled.collectAsStateValue(initial = FlowFilterBarFilledPreference.default) + val flowFilterBarPadding = + context.flowFilterBarPadding.collectAsStateValue(initial = FlowFilterBarPaddingPreference.default) + val flowFilterBarTonalElevation = + context.flowFilterBarTonalElevation.collectAsStateValue(initial = FlowFilterBarTonalElevationPreference.default) + val flowTopBarTonalElevation = + context.flowTopBarTonalElevation.collectAsStateValue(initial = FlowTopBarTonalElevationPreference.default) + val flowArticleListFeedIcon = + context.flowArticleListFeedIcon.collectAsStateValue(initial = FlowArticleListFeedIconPreference.default) + val flowArticleListFeedName = + context.flowArticleListFeedName.collectAsStateValue(initial = FlowArticleListFeedNamePreference.default) + val flowArticleListImage = + context.flowArticleListImage.collectAsStateValue(initial = FlowArticleListImagePreference.default) + val flowArticleListDesc = + context.flowArticleListDesc.collectAsStateValue(initial = FlowArticleListDescPreference.default) + val flowArticleListDate = + context.flowArticleListDate.collectAsStateValue(initial = FlowArticleListDatePreference.default) + val flowArticleListTonalElevation = + context.flowArticleListTonalElevation.collectAsStateValue(initial = FlowArticleListTonalElevationPreference.default) + ProvideZcamViewingConditions { CompositionLocalProvider( LocalTonalPalettes provides tonalPalettes.also { it.Preheating() }, - LocalUseDarkTheme provides useDarkTheme + LocalUseDarkTheme provides useDarkTheme, + LocalTheme provides theme, + + LocalFeedsFilterBarStyle provides feedsFilterBarStyle.value, + LocalFeedsFilterBarFilled provides feedsFilterBarFilled.value, + LocalFeedsFilterBarPadding provides feedsFilterBarPadding, + LocalFeedsFilterBarTonalElevation provides feedsFilterBarTonalElevation.value, + LocalFeedsTopBarTonalElevation provides feedsTopBarTonalElevation.value, + LocalFeedsGroupListExpand provides feedsGroupListExpand.value, + LocalFeedsGroupListTonalElevation provides feedsGroupListTonalElevation.value, + + LocalFlowFilterBarStyle provides flowFilterBarStyle.value, + LocalFlowFilterBarFilled provides flowFilterBarFilled.value, + LocalFlowFilterBarPadding provides flowFilterBarPadding, + LocalFlowFilterBarTonalElevation provides flowFilterBarTonalElevation.value, + LocalFlowTopBarTonalElevation provides flowTopBarTonalElevation.value, + LocalFlowArticleListFeedIcon provides flowArticleListFeedIcon.value, + LocalFlowArticleListFeedName provides flowArticleListFeedName.value, + LocalFlowArticleListImage provides flowArticleListImage.value, + LocalFlowArticleListDesc provides flowArticleListDesc.value, + LocalFlowArticleListDate provides flowArticleListDate.value, + LocalFlowArticleListTonalElevation provides flowArticleListTonalElevation.value, ) { MaterialTheme( colorScheme = diff --git a/app/src/main/java/me/ash/reader/ui/theme/palette/DynamicTonalPalette.kt b/app/src/main/java/me/ash/reader/ui/theme/palette/DynamicTonalPalette.kt index 818d16c..3df4107 100644 --- a/app/src/main/java/me/ash/reader/ui/theme/palette/DynamicTonalPalette.kt +++ b/app/src/main/java/me/ash/reader/ui/theme/palette/DynamicTonalPalette.kt @@ -31,6 +31,7 @@ fun dynamicLightColorScheme(): ColorScheme { onSurface = palettes neutral 10, surfaceVariant = palettes neutralVariant 90, onSurfaceVariant = palettes neutralVariant 30, + surfaceTint = palettes primary 40, inverseSurface = palettes neutral 20, inverseOnSurface = palettes neutral 95, outline = palettes neutralVariant 50, @@ -60,6 +61,7 @@ fun dynamicDarkColorScheme(): ColorScheme { onSurface = palettes neutral 90, surfaceVariant = palettes neutralVariant 30, onSurfaceVariant = palettes neutralVariant 80, + surfaceTint = palettes primary 80, inverseSurface = palettes neutral 90, inverseOnSurface = palettes neutral 20, outline = palettes neutralVariant 60, diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 5920644..95f2e0d 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -99,7 +99,7 @@ 例如 #666666 或 666666 外观 样式 - 深色模式 + 深色主题 跟随系统设置 色调海拔 字体 @@ -124,4 +124,28 @@ 启动时 起始页面 起始过滤条件 + 呜呜呜,黎明之剑完结了 + 是宴席,就有结束的时候,但这本书真的陪了我好久啊,好舍不得,而且主线结束了坑却没填完,不知道啥时候才有番外啊 + 漩涡书院 + + 两端边距 + 显示文章发布时间 + 显示文章描述 + 显示文章插图 + 显示订阅源名称 + 显示订阅源图标 + 文章列表 + 分组列表 + 始终展开 + 顶部 + “标记为已读”按钮的位置 + 标题栏 + 填充已选中的图标 + 过滤栏 + 图标 + 图标和文字 + 图标和文字(仅选中时) + 标题栏的色调海拔仅在滚动时可用。 + 文章列表的色调海拔仅在亮色主题时可用。 + 分组列表的色调海拔仅在亮色主题时可用。 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 114011d..f72095b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -88,9 +88,9 @@ About, open source Welcome Before you can continue, you need to agree to Read You\'s Terms of Service and Privacy Policy. - View the <i><u>Terms of Service and Privacy Policy</u></i> + View the <i><u>Terms of Service & Privacy Policy</u></i> https://github.com/Ashinch/ReadYou/blob/main/TERMS_OF_SERVICE_AND_PRIVACY_POLICY.md - Agree and Continue + Agree Wallpaper Colors No Palettes Only Android 8.1+ @@ -116,7 +116,7 @@ Update Skip This Version Checking for updates… - This is the latest version + This is latest version Check failure Download failure The request rate is limited @@ -124,4 +124,28 @@ On Start Initial Page Initial Filter + The novel "Lord of the Mysteries" has finally come to an end + The Fool is the eighth and final volume of the Lord of the Mysteries series written by Cuttlefish That Loves Diving. + Reddit + value + Padding on Both Ends + Display Article Publish Time + Display Article Descriptions + Display Article Images + Display Feed Names + Display Feed Favicons + Article List + Group List + Always Expand + Top + \"Mark as Read\" Button Position + Top Bar + Fill The Selected Icon + Filter Bar + Icons + Icons & Labels + Icons & Label (Only Selected) + Tone elevation of the top bar is only available when scrolling. + Tone elevation of the article list is only available for light theme. + Tone elevation of the group list is only available for light theme. \ No newline at end of file From 1ba205343e0c7cd1b515d4b31a4b8bb1d53d680c Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 2 May 2022 19:02:20 +0800 Subject: [PATCH 5/6] Set default styles --- .../main/java/me/ash/reader/MainActivity.kt | 5 +- .../CustomPrimaryColorPreference.kt | 22 +++ .../FeedsFilterBarFilledPreference.kt | 18 +-- .../FeedsFilterBarPaddingPreference.kt | 18 +-- .../FeedsFilterBarStylePreference.kt | 20 +-- .../FeedsFilterBarTonalElevationPreference.kt | 26 ++-- .../FeedsGroupListExpandPreference.kt | 18 +-- .../FeedsGroupListTonalElevationPreference.kt | 26 ++-- .../FeedsTopBarTonalElevationPreference.kt | 26 ++-- .../FlowArticleListDatePreference.kt | 45 ------ .../FlowArticleListDescPreference.kt | 18 +-- .../FlowArticleListFeedIconPreference.kt | 18 +-- .../FlowArticleListFeedNamePreference.kt | 18 +-- .../FlowArticleListImagePreference.kt | 18 +-- .../FlowArticleListTimePreference.kt | 41 +++++ ...FlowArticleListTonalElevationPreference.kt | 26 ++-- .../FlowFilterBarFilledPreference.kt | 18 +-- .../FlowFilterBarPaddingPreference.kt | 18 +-- .../FlowFilterBarStylePreference.kt | 20 +-- .../FlowFilterBarTonalElevationPreference.kt | 26 ++-- .../FlowTopBarTonalElevationPreference.kt | 26 ++-- .../me/ash/reader/data/preference/Settings.kt | 147 ++++++++++++++++++ ...ePreference.kt => ThemeIndexPreference.kt} | 15 +- .../java/me/ash/reader/ui/ext/DataStoreExt.kt | 12 +- .../me/ash/reader/ui/page/common/HomeEntry.kt | 1 + .../reader/ui/page/home/feeds/FeedsPage.kt | 18 +-- .../reader/ui/page/home/flow/ArticleItem.kt | 20 +-- .../ash/reader/ui/page/home/flow/FlowPage.kt | 22 ++- .../ui/page/settings/color/ColorAndStyle.kt | 51 +++--- .../settings/color/feeds/FeedsPageStyle.kt | 38 ++--- .../page/settings/color/flow/FlowPageStyle.kt | 56 ++----- .../page/settings/interaction/Interaction.kt | 13 +- .../main/java/me/ash/reader/ui/theme/Theme.kt | 121 +------------- 33 files changed, 461 insertions(+), 524 deletions(-) create mode 100644 app/src/main/java/me/ash/reader/data/preference/CustomPrimaryColorPreference.kt delete mode 100644 app/src/main/java/me/ash/reader/data/preference/FlowArticleListDatePreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/FlowArticleListTimePreference.kt create mode 100644 app/src/main/java/me/ash/reader/data/preference/Settings.kt rename app/src/main/java/me/ash/reader/data/preference/{ThemePreference.kt => ThemeIndexPreference.kt} (63%) diff --git a/app/src/main/java/me/ash/reader/MainActivity.kt b/app/src/main/java/me/ash/reader/MainActivity.kt index d51c87c..1473493 100644 --- a/app/src/main/java/me/ash/reader/MainActivity.kt +++ b/app/src/main/java/me/ash/reader/MainActivity.kt @@ -18,6 +18,7 @@ import coil.memory.MemoryCache import coil.request.* import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.CompletableDeferred +import me.ash.reader.data.preference.SettingsProvider import me.ash.reader.ui.page.common.HomeEntry @AndroidEntryPoint @@ -28,7 +29,9 @@ class MainActivity : ComponentActivity(), ImageLoader { WindowCompat.setDecorFitsSystemWindows(window, false) Log.i("RLog", "onCreate: ${ProfileInstallerInitializer().create(this)}") setContent { - HomeEntry() + SettingsProvider { + HomeEntry() + } } } diff --git a/app/src/main/java/me/ash/reader/data/preference/CustomPrimaryColorPreference.kt b/app/src/main/java/me/ash/reader/data/preference/CustomPrimaryColorPreference.kt new file mode 100644 index 0000000..ad5d157 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/CustomPrimaryColorPreference.kt @@ -0,0 +1,22 @@ +package me.ash.reader.data.preference + +import android.content.Context +import androidx.datastore.preferences.core.Preferences +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +object CustomPrimaryColorPreference { + const val default = "" + + fun put(context: Context, scope: CoroutineScope, value: String) { + scope.launch { + context.dataStore.put(DataStoreKeys.CustomPrimaryColor, value) + } + } + + fun fromPreferences(preferences: Preferences) = + preferences[DataStoreKeys.CustomPrimaryColor.key] ?: default +} \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarFilledPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarFilledPreference.kt index 73dcf13..683d1c8 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarFilledPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarFilledPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -15,7 +13,7 @@ sealed class FeedsFilterBarFilledPreference(val value: Boolean) : Preference() { object OFF : FeedsFilterBarFilledPreference(false) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FeedsFilterBarFilled, value @@ -27,13 +25,11 @@ sealed class FeedsFilterBarFilledPreference(val value: Boolean) : Preference() { val default = OFF val values = listOf(ON, OFF) - val Context.feedsFilterBarFilled: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FeedsFilterBarFilled.key]) { - true -> ON - false -> OFF - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FeedsFilterBarFilled.key]) { + true -> ON + false -> OFF + else -> default } } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarPaddingPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarPaddingPreference.kt index 6f2bf15..b868411 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarPaddingPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarPaddingPreference.kt @@ -1,28 +1,22 @@ package me.ash.reader.data.preference import android.content.Context -import androidx.compose.runtime.Immutable +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put -@Immutable object FeedsFilterBarPaddingPreference { - const val default = 0 - - val Context.feedsFilterBarPadding: Flow - get() = this.dataStore.data.map { - it[DataStoreKeys.FeedsFilterBarPadding.key] ?: default - } + const val default = 60 fun put(context: Context, scope: CoroutineScope, value: Int) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put(DataStoreKeys.FeedsFilterBarPadding, value) } } + + fun fromPreferences(preferences: Preferences) = + preferences[DataStoreKeys.FeedsFilterBarPadding.key] ?: default } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarStylePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarStylePreference.kt index f7db9d3..c553834 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarStylePreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarStylePreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.R import me.ash.reader.ui.ext.DataStoreKeys @@ -17,7 +15,7 @@ sealed class FeedsFilterBarStylePreference(val value: Int) : Preference() { object IconLabelOnlySelected : FeedsFilterBarStylePreference(2) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FeedsFilterBarStyle, value @@ -36,14 +34,12 @@ sealed class FeedsFilterBarStylePreference(val value: Int) : Preference() { val default = Icon val values = listOf(Icon, IconLabel, IconLabelOnlySelected) - val Context.feedsFilterBarStyle: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FeedsFilterBarStyle.key]) { - 0 -> Icon - 1 -> IconLabel - 2 -> IconLabelOnlySelected - else -> default - } + fun fromPreferences(preferences: Preferences): FeedsFilterBarStylePreference = + when (preferences[DataStoreKeys.FeedsFilterBarStyle.key]) { + 0 -> Icon + 1 -> IconLabel + 2 -> IconLabelOnlySelected + else -> default } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt index 7afc42b..ba08eb3 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsFilterBarTonalElevationPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -19,7 +17,7 @@ sealed class FeedsFilterBarTonalElevationPreference(val value: Int) : Preference object Level5 : FeedsFilterBarTonalElevationPreference(12) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FeedsFilterBarTonalElevation, value @@ -41,17 +39,15 @@ sealed class FeedsFilterBarTonalElevationPreference(val value: Int) : Preference val default = Level0 val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) - val Context.feedsFilterBarTonalElevation: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FeedsFilterBarTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FeedsFilterBarTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListExpandPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListExpandPreference.kt index bad79bd..2056631 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListExpandPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListExpandPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -15,7 +13,7 @@ sealed class FeedsGroupListExpandPreference(val value: Boolean) : Preference() { object OFF : FeedsGroupListExpandPreference(false) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FeedsGroupListExpand, value @@ -27,13 +25,11 @@ sealed class FeedsGroupListExpandPreference(val value: Boolean) : Preference() { val default = ON val values = listOf(ON, OFF) - val Context.feedsGroupListExpand: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FeedsGroupListExpand.key]) { - true -> ON - false -> OFF - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FeedsGroupListExpand.key]) { + true -> ON + false -> OFF + else -> default } } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt index 03148e5..c65afe0 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsGroupListTonalElevationPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -19,7 +17,7 @@ sealed class FeedsGroupListTonalElevationPreference(val value: Int) : Preference object Level5 : FeedsGroupListTonalElevationPreference(12) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FeedsGroupListTonalElevation, value @@ -41,17 +39,15 @@ sealed class FeedsGroupListTonalElevationPreference(val value: Int) : Preference val default = Level0 val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) - val Context.feedsGroupListTonalElevation: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FeedsGroupListTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FeedsGroupListTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt index c1e9e4c..b541b4c 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FeedsTopBarTonalElevationPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -19,7 +17,7 @@ sealed class FeedsTopBarTonalElevationPreference(val value: Int) : Preference() object Level5 : FeedsTopBarTonalElevationPreference(12) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FeedsTopBarTonalElevation, value @@ -41,17 +39,15 @@ sealed class FeedsTopBarTonalElevationPreference(val value: Int) : Preference() val default = Level0 val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) - val Context.feedsTopBarTonalElevation: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FeedsTopBarTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FeedsTopBarTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDatePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDatePreference.kt deleted file mode 100644 index 119096c..0000000 --- a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDatePreference.kt +++ /dev/null @@ -1,45 +0,0 @@ -package me.ash.reader.data.preference - -import android.content.Context -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.launch -import me.ash.reader.ui.ext.DataStoreKeys -import me.ash.reader.ui.ext.dataStore -import me.ash.reader.ui.ext.put - -sealed class FlowArticleListDatePreference(val value: Boolean) : Preference() { - object ON : FlowArticleListDatePreference(true) - object OFF : FlowArticleListDatePreference(false) - - override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { - context.dataStore.put( - DataStoreKeys.FlowArticleListDate, - value - ) - } - } - - companion object { - val default = ON - val values = listOf(ON, OFF) - - val Context.flowArticleListDate: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FlowArticleListDate.key]) { - true -> ON - false -> OFF - else -> default - } - } - } -} - -operator fun FlowArticleListDatePreference.not(): FlowArticleListDatePreference = - when (value) { - true -> FlowArticleListDatePreference.OFF - false -> FlowArticleListDatePreference.ON - } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDescPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDescPreference.kt index a1f483f..8373917 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDescPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDescPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -15,7 +13,7 @@ sealed class FlowArticleListDescPreference(val value: Boolean) : Preference() { object OFF : FlowArticleListDescPreference(false) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FlowArticleListDesc, value @@ -27,13 +25,11 @@ sealed class FlowArticleListDescPreference(val value: Boolean) : Preference() { val default = ON val values = listOf(ON, OFF) - val Context.flowArticleListDesc: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FlowArticleListDesc.key]) { - true -> ON - false -> OFF - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowArticleListDesc.key]) { + true -> ON + false -> OFF + else -> default } } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedIconPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedIconPreference.kt index f00e873..f93708e 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedIconPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedIconPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -15,7 +13,7 @@ sealed class FlowArticleListFeedIconPreference(val value: Boolean) : Preference( object OFF : FlowArticleListFeedIconPreference(false) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FlowArticleListFeedIcon, value @@ -27,13 +25,11 @@ sealed class FlowArticleListFeedIconPreference(val value: Boolean) : Preference( val default = ON val values = listOf(ON, OFF) - val Context.flowArticleListFeedIcon: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FlowArticleListFeedIcon.key]) { - true -> ON - false -> OFF - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowArticleListFeedIcon.key]) { + true -> ON + false -> OFF + else -> default } } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedNamePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedNamePreference.kt index 4fae700..994289d 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedNamePreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListFeedNamePreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -15,7 +13,7 @@ sealed class FlowArticleListFeedNamePreference(val value: Boolean) : Preference( object OFF : FlowArticleListFeedNamePreference(false) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FlowArticleListFeedName, value @@ -27,13 +25,11 @@ sealed class FlowArticleListFeedNamePreference(val value: Boolean) : Preference( val default = ON val values = listOf(ON, OFF) - val Context.flowArticleListFeedName: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FlowArticleListFeedName.key]) { - true -> ON - false -> OFF - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowArticleListFeedName.key]) { + true -> ON + false -> OFF + else -> default } } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListImagePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListImagePreference.kt index ef7d776..ef56d37 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListImagePreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListImagePreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -15,7 +13,7 @@ sealed class FlowArticleListImagePreference(val value: Boolean) : Preference() { object OFF : FlowArticleListImagePreference(false) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FlowArticleListImage, value @@ -27,13 +25,11 @@ sealed class FlowArticleListImagePreference(val value: Boolean) : Preference() { val default = ON val values = listOf(ON, OFF) - val Context.flowArticleListImage: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FlowArticleListImage.key]) { - true -> ON - false -> OFF - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowArticleListImage.key]) { + true -> ON + false -> OFF + else -> default } } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTimePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTimePreference.kt new file mode 100644 index 0000000..cbad148 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTimePreference.kt @@ -0,0 +1,41 @@ +package me.ash.reader.data.preference + +import android.content.Context +import androidx.datastore.preferences.core.Preferences +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FlowArticleListTimePreference(val value: Boolean) : Preference() { + object ON : FlowArticleListTimePreference(true) + object OFF : FlowArticleListTimePreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch { + context.dataStore.put( + DataStoreKeys.FlowArticleListTime, + value + ) + } + } + + companion object { + val default = ON + val values = listOf(ON, OFF) + + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowArticleListTime.key]) { + true -> ON + false -> OFF + else -> default + } + } +} + +operator fun FlowArticleListTimePreference.not(): FlowArticleListTimePreference = + when (value) { + true -> FlowArticleListTimePreference.OFF + false -> FlowArticleListTimePreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt index e6febf7..2d3dd1b 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListTonalElevationPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -19,7 +17,7 @@ sealed class FlowArticleListTonalElevationPreference(val value: Int) : Preferenc object Level5 : FlowArticleListTonalElevationPreference(12) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FlowArticleListTonalElevation, value @@ -41,17 +39,15 @@ sealed class FlowArticleListTonalElevationPreference(val value: Int) : Preferenc val default = Level0 val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) - val Context.flowArticleListTonalElevation: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FlowArticleListTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowArticleListTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarFilledPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarFilledPreference.kt index 367507d..632d651 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarFilledPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarFilledPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -15,7 +13,7 @@ sealed class FlowFilterBarFilledPreference(val value: Boolean) : Preference() { object OFF : FlowFilterBarFilledPreference(false) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FlowFilterBarFilled, value @@ -27,13 +25,11 @@ sealed class FlowFilterBarFilledPreference(val value: Boolean) : Preference() { val default = OFF val values = listOf(ON, OFF) - val Context.flowFilterBarFilled: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FlowFilterBarFilled.key]) { - true -> ON - false -> OFF - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowFilterBarFilled.key]) { + true -> ON + false -> OFF + else -> default } } } diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarPaddingPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarPaddingPreference.kt index b564ff3..b9b08aa 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarPaddingPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarPaddingPreference.kt @@ -1,28 +1,22 @@ package me.ash.reader.data.preference import android.content.Context -import androidx.compose.runtime.Immutable +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put -@Immutable object FlowFilterBarPaddingPreference { - const val default = 0 - - val Context.flowFilterBarPadding: Flow - get() = this.dataStore.data.map { - it[DataStoreKeys.FlowFilterBarPadding.key] ?: default - } + const val default = 60 fun put(context: Context, scope: CoroutineScope, value: Int) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put(DataStoreKeys.FlowFilterBarPadding, value) } } + + fun fromPreferences(preferences: Preferences) = + preferences[DataStoreKeys.FlowFilterBarPadding.key] ?: default } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarStylePreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarStylePreference.kt index 10a5c9c..a25c9d2 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarStylePreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarStylePreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.R import me.ash.reader.ui.ext.DataStoreKeys @@ -17,7 +15,7 @@ sealed class FlowFilterBarStylePreference(val value: Int) : Preference() { object IconLabelOnlySelected : FlowFilterBarStylePreference(2) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FlowFilterBarStyle, value @@ -36,14 +34,12 @@ sealed class FlowFilterBarStylePreference(val value: Int) : Preference() { val default = Icon val values = listOf(Icon, IconLabel, IconLabelOnlySelected) - val Context.flowFilterBarStyle: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FlowFilterBarStyle.key]) { - 0 -> Icon - 1 -> IconLabel - 2 -> IconLabelOnlySelected - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowFilterBarStyle.key]) { + 0 -> Icon + 1 -> IconLabel + 2 -> IconLabelOnlySelected + else -> default } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt index 620b2f7..067d58c 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowFilterBarTonalElevationPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -19,7 +17,7 @@ sealed class FlowFilterBarTonalElevationPreference(val value: Int) : Preference( object Level5 : FlowFilterBarTonalElevationPreference(12) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FlowFilterBarTonalElevation, value @@ -41,17 +39,15 @@ sealed class FlowFilterBarTonalElevationPreference(val value: Int) : Preference( val default = Level0 val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) - val Context.flowFilterBarTonalElevation: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FlowFilterBarTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowFilterBarTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt index a01e263..90938dc 100644 --- a/app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/FlowTopBarTonalElevationPreference.kt @@ -1,10 +1,8 @@ package me.ash.reader.data.preference import android.content.Context +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore @@ -19,7 +17,7 @@ sealed class FlowTopBarTonalElevationPreference(val value: Int) : Preference() { object Level5 : FlowTopBarTonalElevationPreference(12) override fun put(context: Context, scope: CoroutineScope) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put( DataStoreKeys.FlowTopBarTonalElevation, value @@ -41,17 +39,15 @@ sealed class FlowTopBarTonalElevationPreference(val value: Int) : Preference() { val default = Level0 val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) - val Context.flowTopBarTonalElevation: Flow - get() = this.dataStore.data.map { - when (it[DataStoreKeys.FlowTopBarTonalElevation.key]) { - 0 -> Level0 - 1 -> Level1 - 3 -> Level2 - 6 -> Level3 - 8 -> Level4 - 12 -> Level5 - else -> default - } + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowTopBarTonalElevation.key]) { + 0 -> Level0 + 1 -> Level1 + 3 -> Level2 + 6 -> Level3 + 8 -> Level4 + 12 -> Level5 + else -> default } } } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/Settings.kt b/app/src/main/java/me/ash/reader/data/preference/Settings.kt new file mode 100644 index 0000000..651e838 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/Settings.kt @@ -0,0 +1,147 @@ +package me.ash.reader.data.preference + +import android.util.Log +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext +import androidx.datastore.preferences.core.Preferences +import kotlinx.coroutines.flow.map +import me.ash.reader.ui.ext.collectAsStateValue +import me.ash.reader.ui.ext.dataStore + +data class Settings( + val themeIndex: Int = ThemeIndexPreference.default, + val customPrimaryColor: String = CustomPrimaryColorPreference.default, + + val feedsFilterBarStyle: FeedsFilterBarStylePreference = FeedsFilterBarStylePreference.default, + val feedsFilterBarFilled: FeedsFilterBarFilledPreference = FeedsFilterBarFilledPreference.default, + val feedsFilterBarPadding: Int = FeedsFilterBarPaddingPreference.default, + val feedsFilterBarTonalElevation: FeedsFilterBarTonalElevationPreference = FeedsFilterBarTonalElevationPreference.default, + val feedsTopBarTonalElevation: FeedsTopBarTonalElevationPreference = FeedsTopBarTonalElevationPreference.default, + val feedsGroupListExpand: FeedsGroupListExpandPreference = FeedsGroupListExpandPreference.default, + val feedsGroupListTonalElevation: FeedsGroupListTonalElevationPreference = FeedsGroupListTonalElevationPreference.default, + + val flowFilterBarStyle: FlowFilterBarStylePreference = FlowFilterBarStylePreference.default, + val flowFilterBarFilled: FlowFilterBarFilledPreference = FlowFilterBarFilledPreference.default, + val flowFilterBarPadding: Int = FlowFilterBarPaddingPreference.default, + val flowFilterBarTonalElevation: FlowFilterBarTonalElevationPreference = FlowFilterBarTonalElevationPreference.default, + val flowTopBarTonalElevation: FlowTopBarTonalElevationPreference = FlowTopBarTonalElevationPreference.default, + val flowArticleListFeedIcon: FlowArticleListFeedIconPreference = FlowArticleListFeedIconPreference.default, + val flowArticleListFeedName: FlowArticleListFeedNamePreference = FlowArticleListFeedNamePreference.default, + val flowArticleListImage: FlowArticleListImagePreference = FlowArticleListImagePreference.default, + val flowArticleListDesc: FlowArticleListDescPreference = FlowArticleListDescPreference.default, + val flowArticleListTime: FlowArticleListTimePreference = FlowArticleListTimePreference.default, + val flowArticleListTonalElevation: FlowArticleListTonalElevationPreference = FlowArticleListTonalElevationPreference.default, +) + +fun Preferences.toSettings(): Settings { + return Settings( + themeIndex = ThemeIndexPreference.fromPreferences(this), + customPrimaryColor = CustomPrimaryColorPreference.fromPreferences(this), + + feedsFilterBarStyle = FeedsFilterBarStylePreference.fromPreferences(this), + feedsFilterBarFilled = FeedsFilterBarFilledPreference.fromPreferences(this), + feedsFilterBarPadding = FeedsFilterBarPaddingPreference.fromPreferences(this), + feedsFilterBarTonalElevation = FeedsFilterBarTonalElevationPreference.fromPreferences(this), + feedsTopBarTonalElevation = FeedsTopBarTonalElevationPreference.fromPreferences(this), + feedsGroupListExpand = FeedsGroupListExpandPreference.fromPreferences(this), + feedsGroupListTonalElevation = FeedsGroupListTonalElevationPreference.fromPreferences(this), + + flowFilterBarStyle = FlowFilterBarStylePreference.fromPreferences(this), + flowFilterBarFilled = FlowFilterBarFilledPreference.fromPreferences(this), + flowFilterBarPadding = FlowFilterBarPaddingPreference.fromPreferences(this), + flowFilterBarTonalElevation = FlowFilterBarTonalElevationPreference.fromPreferences(this), + flowTopBarTonalElevation = FlowTopBarTonalElevationPreference.fromPreferences(this), + flowArticleListFeedIcon = FlowArticleListFeedIconPreference.fromPreferences(this), + flowArticleListFeedName = FlowArticleListFeedNamePreference.fromPreferences(this), + flowArticleListImage = FlowArticleListImagePreference.fromPreferences(this), + flowArticleListDesc = FlowArticleListDescPreference.fromPreferences(this), + flowArticleListTime = FlowArticleListTimePreference.fromPreferences(this), + flowArticleListTonalElevation = FlowArticleListTonalElevationPreference.fromPreferences(this), + ) +} + +@Composable +fun SettingsProvider( + content: @Composable () -> Unit, +) { + val context = LocalContext.current + val settings = remember { + context.dataStore.data.map { + Log.i("RLog", "AppTheme: ${it}") + it.toSettings() + } + }.collectAsStateValue(initial = Settings()) + + CompositionLocalProvider( + LocalThemeIndex provides settings.themeIndex, + LocalCustomPrimaryColor provides settings.customPrimaryColor, + + LocalFeedsTopBarTonalElevation provides settings.feedsTopBarTonalElevation, + LocalFeedsGroupListExpand provides settings.feedsGroupListExpand, + LocalFeedsGroupListTonalElevation provides settings.feedsGroupListTonalElevation, + LocalFeedsFilterBarStyle provides settings.feedsFilterBarStyle, + LocalFeedsFilterBarFilled provides settings.feedsFilterBarFilled, + LocalFeedsFilterBarPadding provides settings.feedsFilterBarPadding, + LocalFeedsFilterBarTonalElevation provides settings.feedsFilterBarTonalElevation, + + LocalFlowTopBarTonalElevation provides settings.flowTopBarTonalElevation, + LocalFlowArticleListFeedIcon provides settings.flowArticleListFeedIcon, + LocalFlowArticleListFeedName provides settings.flowArticleListFeedName, + LocalFlowArticleListImage provides settings.flowArticleListImage, + LocalFlowArticleListDesc provides settings.flowArticleListDesc, + LocalFlowArticleListTime provides settings.flowArticleListTime, + LocalFlowArticleListTonalElevation provides settings.flowArticleListTonalElevation, + LocalFlowFilterBarStyle provides settings.flowFilterBarStyle, + LocalFlowFilterBarFilled provides settings.flowFilterBarFilled, + LocalFlowFilterBarPadding provides settings.flowFilterBarPadding, + LocalFlowFilterBarTonalElevation provides settings.flowFilterBarTonalElevation, + ) { + content() + } +} + +val LocalThemeIndex = + compositionLocalOf { ThemeIndexPreference.default } +val LocalCustomPrimaryColor = + compositionLocalOf { CustomPrimaryColorPreference.default } + +val LocalFeedsFilterBarStyle = + compositionLocalOf { FeedsFilterBarStylePreference.default } +val LocalFeedsFilterBarFilled = + compositionLocalOf { FeedsFilterBarFilledPreference.default } +val LocalFeedsFilterBarPadding = + compositionLocalOf { FeedsFilterBarPaddingPreference.default } +val LocalFeedsFilterBarTonalElevation = + compositionLocalOf { FeedsFilterBarTonalElevationPreference.default } +val LocalFeedsTopBarTonalElevation = + compositionLocalOf { FeedsTopBarTonalElevationPreference.default } +val LocalFeedsGroupListExpand = + compositionLocalOf { FeedsGroupListExpandPreference.default } +val LocalFeedsGroupListTonalElevation = + compositionLocalOf { FeedsGroupListTonalElevationPreference.default } + +val LocalFlowFilterBarStyle = + compositionLocalOf { FlowFilterBarStylePreference.default } +val LocalFlowFilterBarFilled = + compositionLocalOf { FlowFilterBarFilledPreference.default } +val LocalFlowFilterBarPadding = + compositionLocalOf { FlowFilterBarPaddingPreference.default } +val LocalFlowFilterBarTonalElevation = + compositionLocalOf { FlowFilterBarTonalElevationPreference.default } +val LocalFlowTopBarTonalElevation = + compositionLocalOf { FlowTopBarTonalElevationPreference.default } +val LocalFlowArticleListFeedIcon = + compositionLocalOf { FlowArticleListFeedIconPreference.default } +val LocalFlowArticleListFeedName = + compositionLocalOf { FlowArticleListFeedNamePreference.default } +val LocalFlowArticleListImage = + compositionLocalOf { FlowArticleListImagePreference.default } +val LocalFlowArticleListDesc = + compositionLocalOf { FlowArticleListDescPreference.default } +val LocalFlowArticleListTime = + compositionLocalOf { FlowArticleListTimePreference.default } +val LocalFlowArticleListTonalElevation = + compositionLocalOf { FlowArticleListTonalElevationPreference.default } diff --git a/app/src/main/java/me/ash/reader/data/preference/ThemePreference.kt b/app/src/main/java/me/ash/reader/data/preference/ThemeIndexPreference.kt similarity index 63% rename from app/src/main/java/me/ash/reader/data/preference/ThemePreference.kt rename to app/src/main/java/me/ash/reader/data/preference/ThemeIndexPreference.kt index 3f006a7..2c947e2 100644 --- a/app/src/main/java/me/ash/reader/data/preference/ThemePreference.kt +++ b/app/src/main/java/me/ash/reader/data/preference/ThemeIndexPreference.kt @@ -1,28 +1,23 @@ package me.ash.reader.data.preference import android.content.Context -import androidx.compose.runtime.Immutable +import androidx.datastore.preferences.core.Preferences import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.put -@Immutable -object ThemePreference { +object ThemeIndexPreference { const val default = 5 - val Context.Theme: Flow - get() = this.dataStore.data.map { - it[DataStoreKeys.ThemeIndex.key] ?: default - } - fun put(context: Context, scope: CoroutineScope, value: Int) { scope.launch(Dispatchers.IO) { context.dataStore.put(DataStoreKeys.ThemeIndex, value) } } + + fun fromPreferences(preferences: Preferences) = + preferences[DataStoreKeys.ThemeIndex.key] ?: default } \ No newline at end of file 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 687f4be..ff56e64 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 @@ -5,10 +5,12 @@ import android.util.Log import androidx.datastore.core.DataStore import androidx.datastore.preferences.core.* import androidx.datastore.preferences.preferencesDataStore +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.map import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withContext import java.io.IOException val Context.dataStore: DataStore by preferencesDataStore(name = "settings") @@ -32,8 +34,6 @@ val Context.currentAccountId: Int val Context.currentAccountType: Int get() = this.dataStore.get(DataStoreKeys.CurrentAccountType)!! -val Context.customPrimaryColor: String - get() = this.dataStore.get(DataStoreKeys.CustomPrimaryColor) ?: "" val Context.initialPage: Int get() = this.dataStore.get(DataStoreKeys.InitialPage) ?: 0 val Context.initialFilter: Int @@ -41,7 +41,9 @@ val Context.initialFilter: Int suspend fun DataStore.put(dataStoreKeys: DataStoreKeys, value: T) { this.edit { - it[dataStoreKeys.key] = value + withContext(Dispatchers.IO) { + it[dataStoreKeys.key] = value + } } } @@ -208,9 +210,9 @@ sealed class DataStoreKeys { get() = booleanPreferencesKey("flowArticleListDesc") } - object FlowArticleListDate : DataStoreKeys() { + object FlowArticleListTime : DataStoreKeys() { override val key: Preferences.Key - get() = booleanPreferencesKey("flowArticleListDate") + get() = booleanPreferencesKey("flowArticleListTime") } object FlowArticleListTonalElevation : DataStoreKeys() { diff --git a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt index 76453a5..4aed762 100644 --- a/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt +++ b/app/src/main/java/me/ash/reader/ui/page/common/HomeEntry.kt @@ -36,6 +36,7 @@ fun HomeEntry( homeViewModel: HomeViewModel = hiltViewModel(), ) { val context = LocalContext.current + val viewState = homeViewModel.viewState.collectAsStateValue() val filterState = homeViewModel.filterState.collectAsStateValue() val pagingItems = viewState.pagingData.collectAsLazyPagingItems() diff --git a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt index db5ac4c..336e5a0 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/feeds/FeedsPage.kt @@ -29,6 +29,7 @@ import androidx.navigation.NavHostController import kotlinx.coroutines.flow.map import me.ash.reader.R import me.ash.reader.data.entity.toVersion +import me.ash.reader.data.preference.* import me.ash.reader.data.repository.SyncWorker.Companion.getIsSyncing import me.ash.reader.ui.component.Banner import me.ash.reader.ui.component.DisplayText @@ -45,7 +46,6 @@ import me.ash.reader.ui.page.home.feeds.option.group.GroupOptionDrawer import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeDialog import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeViewAction import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeViewModel -import me.ash.reader.ui.theme.* import me.ash.reader.ui.theme.palette.onDark @SuppressLint("FlowOperatorInvokedInComposition") @@ -127,17 +127,17 @@ fun FeedsPage( Scaffold( modifier = Modifier - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(topBarTonalElevation.dp)) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(topBarTonalElevation.value.dp)) .statusBarsPadding() .navigationBarsPadding(), containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( - groupListTonalElevation.dp + groupListTonalElevation.value.dp ) onDark MaterialTheme.colorScheme.surface, topBar = { SmallTopAppBar( colors = TopAppBarDefaults.smallTopAppBarColors( containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( - topBarTonalElevation.dp + topBarTonalElevation.value.dp ), ), title = {}, @@ -222,8 +222,8 @@ fun FeedsPage( // Crossfade(targetState = groupWithFeed) { groupWithFeed -> Column { GroupItem( - isExpanded = groupListExpand, - tonalElevation = groupListTonalElevation.dp, + isExpanded = groupListExpand.value, + tonalElevation = groupListTonalElevation.value.dp, group = groupWithFeed.group, feeds = groupWithFeed.feeds, groupOnClick = { @@ -262,10 +262,10 @@ fun FeedsPage( bottomBar = { FilterBar( filter = filterState.filter, - filterBarStyle = filterBarStyle, - filterBarFilled = filterBarFilled, + filterBarStyle = filterBarStyle.value, + filterBarFilled = filterBarFilled.value, filterBarPadding = filterBarPadding.dp, - filterBarTonalElevation = filterBarTonalElevation.dp, + filterBarTonalElevation = filterBarTonalElevation.value.dp, ) { filterChange( navController = navController, 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 c4e30f2..ed74bf9 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 @@ -21,8 +21,8 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import me.ash.reader.R import me.ash.reader.data.entity.ArticleWithFeed +import me.ash.reader.data.preference.* import me.ash.reader.ui.ext.formatAsString -import me.ash.reader.ui.theme.* @Composable fun ArticleItem( @@ -35,7 +35,7 @@ fun ArticleItem( val articleListFeedName = LocalFlowArticleListFeedName.current val articleListImage = LocalFlowArticleListImage.current val articleListDesc = LocalFlowArticleListDesc.current - val articleListDate = LocalFlowArticleListDate.current + val articleListDate = LocalFlowArticleListTime.current Column( modifier = Modifier @@ -51,11 +51,11 @@ fun ArticleItem( verticalAlignment = Alignment.CenterVertically, ) { // Feed name - if (articleListFeedName) { + if (articleListFeedName.value) { Text( modifier = Modifier .weight(1f) - .padding(start = if (articleListFeedIcon) 30.dp else 0.dp), + .padding(start = if (articleListFeedIcon.value) 30.dp else 0.dp), text = articleWithFeed.feed.name, color = MaterialTheme.colorScheme.tertiary, style = MaterialTheme.typography.labelMedium, @@ -64,12 +64,12 @@ fun ArticleItem( ) } - if (articleListDate) { + if (articleListDate.value) { Row( verticalAlignment = Alignment.CenterVertically, ) { - if (!articleListFeedName) { - Spacer(Modifier.width(if (articleListFeedIcon) 30.dp else 0.dp)) + if (!articleListFeedName.value) { + Spacer(Modifier.width(if (articleListFeedIcon.value) 30.dp else 0.dp)) } // Starred if (articleWithFeed.article.isStarred) { @@ -99,7 +99,7 @@ fun ArticleItem( modifier = Modifier.fillMaxWidth(), ) { // Feed icon - if (articleListFeedIcon) { + if (articleListFeedIcon.value) { Row( modifier = Modifier .size(20.dp) @@ -117,11 +117,11 @@ fun ArticleItem( text = articleWithFeed.article.title, color = MaterialTheme.colorScheme.onSurface, style = MaterialTheme.typography.titleMedium, - maxLines = if (articleListDesc) 2 else 4, + maxLines = if (articleListDesc.value) 2 else 4, overflow = TextOverflow.Ellipsis, ) // Description - if (articleListDesc) { + if (articleListDesc.value) { Text( text = articleWithFeed.article.shortDescription, color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f), diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt index 8ed73cb..a72e3c6 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt @@ -15,7 +15,6 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester -import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.res.stringResource @@ -27,6 +26,7 @@ import androidx.paging.compose.LazyPagingItems import kotlinx.coroutines.delay import kotlinx.coroutines.launch import me.ash.reader.R +import me.ash.reader.data.preference.* import me.ash.reader.data.repository.SyncWorker.Companion.getIsSyncing import me.ash.reader.ui.component.DisplayText import me.ash.reader.ui.component.FeedbackIconButton @@ -39,7 +39,6 @@ import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.FilterState import me.ash.reader.ui.page.home.HomeViewAction import me.ash.reader.ui.page.home.HomeViewModel -import me.ash.reader.ui.theme.* import me.ash.reader.ui.theme.palette.onDark @OptIn( @@ -55,7 +54,6 @@ fun FlowPage( homeViewModel: HomeViewModel, pagingItems: LazyPagingItems, ) { - val context = LocalContext.current val keyboardController = LocalSoftwareKeyboardController.current val topBarTonalElevation = LocalFlowTopBarTonalElevation.current val articleListTonalElevation = LocalFlowArticleListTonalElevation.current @@ -109,18 +107,18 @@ fun FlowPage( Scaffold( modifier = Modifier - .background(MaterialTheme.colorScheme.surfaceColorAtElevation(topBarTonalElevation.dp)) + .background(MaterialTheme.colorScheme.surfaceColorAtElevation(topBarTonalElevation.value.dp)) .statusBarsPadding() .navigationBarsPadding(), containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( - articleListTonalElevation.dp + articleListTonalElevation.value.dp ) onDark MaterialTheme.colorScheme.surface, topBar = { SmallTopAppBar( title = {}, colors = TopAppBarDefaults.smallTopAppBarColors( containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( - topBarTonalElevation.dp + topBarTonalElevation.value.dp ), ), navigationIcon = { @@ -199,7 +197,7 @@ fun FlowPage( state = listState, ) { item { - DisplayTextHeader(filterState, isSyncing, articleListFeedIcon) + DisplayTextHeader(filterState, isSyncing, articleListFeedIcon.value) AnimatedVisibility( visible = markAsRead, enter = fadeIn() + expandVertically(), @@ -261,8 +259,8 @@ fun FlowPage( } ArticleList( pagingItems = pagingItems, - articleListFeedIcon = articleListFeedIcon, - articleListTonalElevation = articleListTonalElevation, + articleListFeedIcon = articleListFeedIcon.value, + articleListTonalElevation = articleListTonalElevation.value, ) { onSearch = false navController.navigate("${RouteName.READING}/${it.article.id}") { @@ -281,10 +279,10 @@ fun FlowPage( bottomBar = { FilterBar( filter = filterState.filter, - filterBarStyle = filterBarStyle, - filterBarFilled = filterBarFilled, + filterBarStyle = filterBarStyle.value, + filterBarFilled = filterBarFilled.value, filterBarPadding = filterBarPadding.dp, - filterBarTonalElevation = filterBarTonalElevation.dp, + filterBarTonalElevation = filterBarTonalElevation.value.dp, ) { flowViewModel.dispatch(FlowViewAction.ScrollToItem(0)) homeViewModel.dispatch(HomeViewAction.ChangeFilter(filterState.copy(filter = it))) diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt index b7c8db7..9a675ca 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/ColorAndStyle.kt @@ -1,6 +1,7 @@ package me.ash.reader.ui.page.settings.color import android.annotation.SuppressLint +import android.content.Context import android.os.Build import androidx.compose.animation.* import androidx.compose.foundation.background @@ -24,21 +25,16 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.launch import me.ash.reader.R -import me.ash.reader.data.preference.ThemePreference +import me.ash.reader.data.preference.CustomPrimaryColorPreference +import me.ash.reader.data.preference.LocalCustomPrimaryColor +import me.ash.reader.data.preference.LocalThemeIndex +import me.ash.reader.data.preference.ThemeIndexPreference import me.ash.reader.ui.component.* -import me.ash.reader.ui.ext.DataStoreKeys -import me.ash.reader.ui.ext.customPrimaryColor -import me.ash.reader.ui.ext.dataStore -import me.ash.reader.ui.ext.put import me.ash.reader.ui.page.common.RouteName import me.ash.reader.ui.page.settings.SettingItem import me.ash.reader.ui.svg.PALETTE import me.ash.reader.ui.svg.SVGString -import me.ash.reader.ui.theme.LocalTheme import me.ash.reader.ui.theme.LocalUseDarkTheme import me.ash.reader.ui.theme.palette.* import me.ash.reader.ui.theme.palette.TonalPalettes.Companion.toTonalPalettes @@ -52,9 +48,11 @@ fun ColorAndStyle( ) { val context = LocalContext.current val useDarkTheme = LocalUseDarkTheme.current - val theme = LocalTheme.current + val themeIndex = LocalThemeIndex.current + val customPrimaryColor = LocalCustomPrimaryColor.current + val wallpaperTonalPalettes = extractTonalPalettesFromUserWallpaper() - var radioButtonSelected by remember { mutableStateOf(if (theme > 4) 0 else 1) } + var radioButtonSelected by remember { mutableStateOf(if (themeIndex > 4) 0 else 1) } Scaffold( modifier = Modifier @@ -118,6 +116,7 @@ fun ColorAndStyle( onClick = {}, ) { Palettes( + context = context, palettes = wallpaperTonalPalettes.run { if (this.size > 5) { this.subList(5, wallpaperTonalPalettes.size) @@ -125,7 +124,9 @@ fun ColorAndStyle( emptyList() } }, + themeIndex = themeIndex, themeIndexPrefix = 5, + customPrimaryColor = customPrimaryColor, ) }, BlockRadioGroupButtonItem( @@ -133,7 +134,10 @@ fun ColorAndStyle( onClick = {}, ) { Palettes( - palettes = wallpaperTonalPalettes.subList(0, 5) + context = context, + themeIndex = themeIndex, + palettes = wallpaperTonalPalettes.subList(0, 5), + customPrimaryColor = customPrimaryColor, ) }, ), @@ -199,20 +203,16 @@ fun ColorAndStyle( @Composable fun Palettes( modifier: Modifier = Modifier, + context: Context, palettes: List, + themeIndex: Int = 0, themeIndexPrefix: Int = 0, + customPrimaryColor: String = "", ) { - val context = LocalContext.current val scope = rememberCoroutineScope() - val themeIndex = context.dataStore.data - .map { it[DataStoreKeys.ThemeIndex.key] ?: 5 } - .collectAsState(initial = 5).value - val customPrimaryColor = context.dataStore.data - .map { it[DataStoreKeys.CustomPrimaryColor.key] ?: "" } - .collectAsState(initial = "").value val tonalPalettes = customPrimaryColor.safeHexToColor().toTonalPalettes() var addDialogVisible by remember { mutableStateOf(false) } - var customColorValue by remember { mutableStateOf(context.customPrimaryColor) } + var customColorValue by remember { mutableStateOf(customPrimaryColor) } if (palettes.isEmpty()) { Row( @@ -252,9 +252,10 @@ fun Palettes( isCustom = isCustom, onClick = { if (isCustom) { + customColorValue = customPrimaryColor addDialogVisible = true } else { - ThemePreference.put(context, scope, themeIndexPrefix + index) + ThemeIndexPreference.put(context, scope, themeIndexPrefix + index) } }, palette = if (isCustom) tonalPalettes else palette @@ -274,16 +275,12 @@ fun Palettes( }, onDismissRequest = { addDialogVisible = false - customColorValue = context.customPrimaryColor }, onConfirm = { it.checkColorHex()?.let { - scope.launch(Dispatchers.IO) { - context.dataStore.put(DataStoreKeys.CustomPrimaryColor, it) - context.dataStore.put(DataStoreKeys.ThemeIndex, 4) - } + CustomPrimaryColorPreference.put(context, scope, it) + ThemeIndexPreference.put(context, scope, 4) addDialogVisible = false - customColorValue = it } } ) diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt index fdb19bc..02fafd7 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt @@ -24,15 +24,7 @@ import me.ash.reader.data.entity.Feed import me.ash.reader.data.entity.Filter import me.ash.reader.data.entity.Group import me.ash.reader.data.preference.* -import me.ash.reader.data.preference.FeedsFilterBarFilledPreference.Companion.feedsFilterBarFilled -import me.ash.reader.data.preference.FeedsFilterBarPaddingPreference.feedsFilterBarPadding -import me.ash.reader.data.preference.FeedsFilterBarStylePreference.Companion.feedsFilterBarStyle -import me.ash.reader.data.preference.FeedsFilterBarTonalElevationPreference.Companion.feedsFilterBarTonalElevation -import me.ash.reader.data.preference.FeedsGroupListExpandPreference.Companion.feedsGroupListExpand -import me.ash.reader.data.preference.FeedsGroupListTonalElevationPreference.Companion.feedsGroupListTonalElevation -import me.ash.reader.data.preference.FeedsTopBarTonalElevationPreference.Companion.feedsTopBarTonalElevation import me.ash.reader.ui.component.* -import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.surfaceColorAtElevation import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.feeds.GroupItem @@ -46,21 +38,15 @@ fun FeedsPageStyle( navController: NavHostController, ) { val context = LocalContext.current + val filterBarStyle = LocalFeedsFilterBarStyle.current + val filterBarFilled = LocalFeedsFilterBarFilled.current + val filterBarPadding = LocalFeedsFilterBarPadding.current + val filterBarTonalElevation = LocalFeedsFilterBarTonalElevation.current + val topBarTonalElevation = LocalFeedsTopBarTonalElevation.current + val groupListExpand = LocalFeedsGroupListExpand.current + val groupListTonalElevation = LocalFeedsGroupListTonalElevation.current + val scope = rememberCoroutineScope() - val filterBarStyle = - context.feedsFilterBarStyle.collectAsStateValue(initial = FeedsFilterBarStylePreference.default) - val filterBarFilled = - context.feedsFilterBarFilled.collectAsStateValue(initial = FeedsFilterBarFilledPreference.default) - val filterBarPadding = - context.feedsFilterBarPadding.collectAsStateValue(initial = FeedsFilterBarPaddingPreference.default) - val filterBarTonalElevation = - context.feedsFilterBarTonalElevation.collectAsStateValue(initial = FeedsFilterBarTonalElevationPreference.default) - val topBarTonalElevation = - context.feedsTopBarTonalElevation.collectAsStateValue(initial = FeedsTopBarTonalElevationPreference.default) - val groupListExpand = - context.feedsGroupListExpand.collectAsStateValue(initial = FeedsGroupListExpandPreference.default) - val groupListTonalElevation = - context.feedsGroupListTonalElevation.collectAsStateValue(initial = FeedsGroupListTonalElevationPreference.default) var filterBarStyleDialogVisible by remember { mutableStateOf(false) } var filterBarPaddingDialogVisible by remember { mutableStateOf(false) } @@ -141,7 +127,7 @@ fun FeedsPageStyle( topBarTonalElevationDialogVisible = true }, ) {} - Tips(text = stringResource(R.string.tips_top_bar_tonal_elevation)) +// Tips(text = stringResource(R.string.tips_top_bar_tonal_elevation)) Spacer(modifier = Modifier.height(24.dp)) } @@ -254,7 +240,7 @@ fun FeedsPageStyle( options = FeedsFilterBarTonalElevationPreference.values.map { RadioDialogOption( text = it.getDesc(context), - selected = filterBarTonalElevation == it, + selected = it == filterBarTonalElevation, ) { it.put(context, scope) } @@ -269,7 +255,7 @@ fun FeedsPageStyle( options = FeedsTopBarTonalElevationPreference.values.map { RadioDialogOption( text = it.getDesc(context), - selected = topBarTonalElevation == it, + selected = it == topBarTonalElevation, ) { it.put(context, scope) } @@ -284,7 +270,7 @@ fun FeedsPageStyle( options = FeedsGroupListTonalElevationPreference.values.map { RadioDialogOption( text = it.getDesc(context), - selected = groupListTonalElevation == it, + selected = it == groupListTonalElevation, ) { it.put(context, scope) } diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt index 046c939..31e1e6f 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt @@ -26,19 +26,7 @@ import me.ash.reader.data.entity.ArticleWithFeed import me.ash.reader.data.entity.Feed import me.ash.reader.data.entity.Filter import me.ash.reader.data.preference.* -import me.ash.reader.data.preference.FlowArticleListDatePreference.Companion.flowArticleListDate -import me.ash.reader.data.preference.FlowArticleListDescPreference.Companion.flowArticleListDesc -import me.ash.reader.data.preference.FlowArticleListFeedIconPreference.Companion.flowArticleListFeedIcon -import me.ash.reader.data.preference.FlowArticleListFeedNamePreference.Companion.flowArticleListFeedName -import me.ash.reader.data.preference.FlowArticleListImagePreference.Companion.flowArticleListImage -import me.ash.reader.data.preference.FlowArticleListTonalElevationPreference.Companion.flowArticleListTonalElevation -import me.ash.reader.data.preference.FlowFilterBarFilledPreference.Companion.flowFilterBarFilled -import me.ash.reader.data.preference.FlowFilterBarPaddingPreference.flowFilterBarPadding -import me.ash.reader.data.preference.FlowFilterBarStylePreference.Companion.flowFilterBarStyle -import me.ash.reader.data.preference.FlowFilterBarTonalElevationPreference.Companion.flowFilterBarTonalElevation -import me.ash.reader.data.preference.FlowTopBarTonalElevationPreference.Companion.flowTopBarTonalElevation import me.ash.reader.ui.component.* -import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.surfaceColorAtElevation import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.flow.ArticleItem @@ -54,29 +42,19 @@ fun FlowPageStyle( navController: NavHostController, ) { val context = LocalContext.current + val filterBarStyle = LocalFlowFilterBarStyle.current + val filterBarFilled = LocalFlowFilterBarFilled.current + val filterBarPadding = LocalFlowFilterBarPadding.current + val filterBarTonalElevation = LocalFlowFilterBarTonalElevation.current + val topBarTonalElevation = LocalFlowTopBarTonalElevation.current + val articleListFeedIcon = LocalFlowArticleListFeedIcon.current + val articleListFeedName = LocalFlowArticleListFeedName.current + val articleListImage = LocalFlowArticleListImage.current + val articleListDesc = LocalFlowArticleListDesc.current + val articleListDate = LocalFlowArticleListTime.current + val articleListTonalElevation = LocalFlowArticleListTonalElevation.current + val scope = rememberCoroutineScope() - val filterBarStyle = - context.flowFilterBarStyle.collectAsStateValue(initial = FlowFilterBarStylePreference.default) - val filterBarFilled = - context.flowFilterBarFilled.collectAsStateValue(initial = FlowFilterBarFilledPreference.default) - val filterBarPadding = - context.flowFilterBarPadding.collectAsStateValue(initial = FlowFilterBarPaddingPreference.default) - val filterBarTonalElevation = - context.flowFilterBarTonalElevation.collectAsStateValue(initial = FlowFilterBarTonalElevationPreference.default) - val topBarTonalElevation = - context.flowTopBarTonalElevation.collectAsStateValue(initial = FlowTopBarTonalElevationPreference.default) - val articleListFeedIcon = - context.flowArticleListFeedIcon.collectAsStateValue(initial = FlowArticleListFeedIconPreference.default) - val articleListFeedName = - context.flowArticleListFeedName.collectAsStateValue(initial = FlowArticleListFeedNamePreference.default) - val articleListImage = - context.flowArticleListImage.collectAsStateValue(initial = FlowArticleListImagePreference.default) - val articleListDesc = - context.flowArticleListDesc.collectAsStateValue(initial = FlowArticleListDescPreference.default) - val articleListDate = - context.flowArticleListDate.collectAsStateValue(initial = FlowArticleListDatePreference.default) - val articleListTonalElevation = - context.flowArticleListTonalElevation.collectAsStateValue(initial = FlowArticleListTonalElevationPreference.default) var filterBarStyleDialogVisible by remember { mutableStateOf(false) } var filterBarPaddingDialogVisible by remember { mutableStateOf(false) } @@ -162,7 +140,7 @@ fun FlowPageStyle( topBarTonalElevationDialogVisible = true }, ) {} - Tips(text = stringResource(R.string.tips_top_bar_tonal_elevation)) +// Tips(text = stringResource(R.string.tips_top_bar_tonal_elevation)) Spacer(modifier = Modifier.height(24.dp)) } @@ -280,7 +258,7 @@ fun FlowPageStyle( options = FlowFilterBarStylePreference.values.map { RadioDialogOption( text = it.getDesc(context), - selected = filterBarStyle == it, + selected = it == filterBarStyle, ) { it.put(context, scope) } @@ -312,7 +290,7 @@ fun FlowPageStyle( options = FlowFilterBarTonalElevationPreference.values.map { RadioDialogOption( text = it.getDesc(context), - selected = filterBarTonalElevation == it, + selected = it == filterBarTonalElevation, ) { it.put(context, scope) } @@ -327,7 +305,7 @@ fun FlowPageStyle( options = FlowTopBarTonalElevationPreference.values.map { RadioDialogOption( text = it.getDesc(context), - selected = topBarTonalElevation == it, + selected = it == topBarTonalElevation, ) { it.put(context, scope) } @@ -342,7 +320,7 @@ fun FlowPageStyle( options = FlowArticleListTonalElevationPreference.values.map { RadioDialogOption( text = it.getDesc(context), - selected = articleListTonalElevation == it, + selected = it == articleListTonalElevation, ) { it.put(context, scope) } diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/interaction/Interaction.kt b/app/src/main/java/me/ash/reader/ui/page/settings/interaction/Interaction.kt index 40ce721..ca362b6 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/interaction/Interaction.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/interaction/Interaction.kt @@ -10,11 +10,9 @@ import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.navigation.NavHostController -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import me.ash.reader.R @@ -32,7 +30,6 @@ fun Interaction( navController: NavHostController, ) { val context = LocalContext.current - val view = LocalView.current val scope = rememberCoroutineScope() var initialPageDialogVisible by remember { mutableStateOf(false) } var initialFilterDialogVisible by remember { mutableStateOf(false) } @@ -116,7 +113,7 @@ fun Interaction( text = stringResource(R.string.feeds_page), selected = initialPage == 0, ) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put(DataStoreKeys.InitialPage, 0) } }, @@ -124,7 +121,7 @@ fun Interaction( text = stringResource(R.string.flow_page), selected = initialPage == 1, ) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put(DataStoreKeys.InitialPage, 1) } }, @@ -141,7 +138,7 @@ fun Interaction( text = stringResource(R.string.starred), selected = initialFilter == 0, ) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put(DataStoreKeys.InitialFilter, 0) } }, @@ -149,7 +146,7 @@ fun Interaction( text = stringResource(R.string.unread), selected = initialFilter == 1, ) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put(DataStoreKeys.InitialFilter, 1) } }, @@ -157,7 +154,7 @@ fun Interaction( text = stringResource(R.string.all), selected = initialFilter == 2, ) { - scope.launch(Dispatchers.IO) { + scope.launch { context.dataStore.put(DataStoreKeys.InitialFilter, 2) } }, diff --git a/app/src/main/java/me/ash/reader/ui/theme/Theme.kt b/app/src/main/java/me/ash/reader/ui/theme/Theme.kt index 7354651..694093b 100644 --- a/app/src/main/java/me/ash/reader/ui/theme/Theme.kt +++ b/app/src/main/java/me/ash/reader/ui/theme/Theme.kt @@ -1,33 +1,11 @@ package me.ash.reader.ui.theme -import android.annotation.SuppressLint import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.compositionLocalOf -import androidx.compose.ui.platform.LocalContext -import me.ash.reader.data.preference.* -import me.ash.reader.data.preference.FeedsFilterBarFilledPreference.Companion.feedsFilterBarFilled -import me.ash.reader.data.preference.FeedsFilterBarPaddingPreference.feedsFilterBarPadding -import me.ash.reader.data.preference.FeedsFilterBarStylePreference.Companion.feedsFilterBarStyle -import me.ash.reader.data.preference.FeedsFilterBarTonalElevationPreference.Companion.feedsFilterBarTonalElevation -import me.ash.reader.data.preference.FeedsGroupListExpandPreference.Companion.feedsGroupListExpand -import me.ash.reader.data.preference.FeedsGroupListTonalElevationPreference.Companion.feedsGroupListTonalElevation -import me.ash.reader.data.preference.FeedsTopBarTonalElevationPreference.Companion.feedsTopBarTonalElevation -import me.ash.reader.data.preference.FlowArticleListDatePreference.Companion.flowArticleListDate -import me.ash.reader.data.preference.FlowArticleListDescPreference.Companion.flowArticleListDesc -import me.ash.reader.data.preference.FlowArticleListFeedIconPreference.Companion.flowArticleListFeedIcon -import me.ash.reader.data.preference.FlowArticleListFeedNamePreference.Companion.flowArticleListFeedName -import me.ash.reader.data.preference.FlowArticleListImagePreference.Companion.flowArticleListImage -import me.ash.reader.data.preference.FlowArticleListTonalElevationPreference.Companion.flowArticleListTonalElevation -import me.ash.reader.data.preference.FlowFilterBarFilledPreference.Companion.flowFilterBarFilled -import me.ash.reader.data.preference.FlowFilterBarPaddingPreference.flowFilterBarPadding -import me.ash.reader.data.preference.FlowFilterBarStylePreference.Companion.flowFilterBarStyle -import me.ash.reader.data.preference.FlowFilterBarTonalElevationPreference.Companion.flowFilterBarTonalElevation -import me.ash.reader.data.preference.FlowTopBarTonalElevationPreference.Companion.flowTopBarTonalElevation -import me.ash.reader.data.preference.ThemePreference.Theme -import me.ash.reader.ui.ext.collectAsStateValue +import me.ash.reader.data.preference.LocalThemeIndex import me.ash.reader.ui.theme.palette.LocalTonalPalettes import me.ash.reader.ui.theme.palette.TonalPalettes import me.ash.reader.ui.theme.palette.core.ProvideZcamViewingConditions @@ -36,122 +14,31 @@ import me.ash.reader.ui.theme.palette.dynamicDarkColorScheme import me.ash.reader.ui.theme.palette.dynamicLightColorScheme val LocalUseDarkTheme = compositionLocalOf { false } -val LocalTheme = compositionLocalOf { ThemePreference.default } -val LocalFeedsFilterBarStyle = compositionLocalOf { FeedsFilterBarStylePreference.default.value } -val LocalFeedsFilterBarFilled = compositionLocalOf { FeedsFilterBarFilledPreference.default.value } -val LocalFeedsFilterBarPadding = compositionLocalOf { FeedsFilterBarPaddingPreference.default } -val LocalFeedsFilterBarTonalElevation = - compositionLocalOf { FeedsFilterBarTonalElevationPreference.default.value } -val LocalFeedsTopBarTonalElevation = - compositionLocalOf { FeedsTopBarTonalElevationPreference.default.value } -val LocalFeedsGroupListExpand = - compositionLocalOf { FeedsGroupListExpandPreference.default.value } -val LocalFeedsGroupListTonalElevation = - compositionLocalOf { FeedsGroupListTonalElevationPreference.default.value } - -val LocalFlowFilterBarStyle = compositionLocalOf { FlowFilterBarStylePreference.default.value } -val LocalFlowFilterBarFilled = compositionLocalOf { FlowFilterBarFilledPreference.default.value } -val LocalFlowFilterBarPadding = compositionLocalOf { FlowFilterBarPaddingPreference.default } -val LocalFlowFilterBarTonalElevation = - compositionLocalOf { FlowFilterBarTonalElevationPreference.default.value } -val LocalFlowTopBarTonalElevation = - compositionLocalOf { FlowTopBarTonalElevationPreference.default.value } -val LocalFlowArticleListFeedIcon = - compositionLocalOf { FlowArticleListFeedIconPreference.default.value } -val LocalFlowArticleListFeedName = - compositionLocalOf { FlowArticleListFeedNamePreference.default.value } -val LocalFlowArticleListImage = compositionLocalOf { FlowArticleListImagePreference.default.value } -val LocalFlowArticleListDesc = compositionLocalOf { FlowArticleListDescPreference.default.value } -val LocalFlowArticleListDate = compositionLocalOf { FlowArticleListDatePreference.default.value } -val LocalFlowArticleListTonalElevation = - compositionLocalOf { FlowArticleListTonalElevationPreference.default.value } - -@SuppressLint("FlowOperatorInvokedInComposition") @Composable fun AppTheme( useDarkTheme: Boolean = isSystemInDarkTheme(), wallpaperPalettes: List = extractTonalPalettesFromUserWallpaper(), content: @Composable () -> Unit ) { - val context = LocalContext.current - val theme = context.Theme.collectAsStateValue(initial = ThemePreference.default) + val themeIndex = LocalThemeIndex.current val tonalPalettes = wallpaperPalettes[ - if (theme >= wallpaperPalettes.size) { + if (themeIndex >= wallpaperPalettes.size) { when { wallpaperPalettes.size == 5 -> 0 wallpaperPalettes.size > 5 -> 5 else -> 0 } } else { - theme + themeIndex } ] - val feedsFilterBarStyle = - context.feedsFilterBarStyle.collectAsStateValue(initial = FeedsFilterBarStylePreference.default) - val feedsFilterBarFilled = - context.feedsFilterBarFilled.collectAsStateValue(initial = FeedsFilterBarFilledPreference.default) - val feedsFilterBarPadding = - context.feedsFilterBarPadding.collectAsStateValue(initial = FeedsFilterBarPaddingPreference.default) - val feedsFilterBarTonalElevation = - context.feedsFilterBarTonalElevation.collectAsStateValue(initial = FeedsFilterBarTonalElevationPreference.default) - val feedsTopBarTonalElevation = - context.feedsTopBarTonalElevation.collectAsStateValue(initial = FeedsTopBarTonalElevationPreference.default) - val feedsGroupListExpand = - context.feedsGroupListExpand.collectAsStateValue(initial = FeedsGroupListExpandPreference.default) - val feedsGroupListTonalElevation = - context.feedsGroupListTonalElevation.collectAsStateValue(initial = FeedsGroupListTonalElevationPreference.default) - - val flowFilterBarStyle = - context.flowFilterBarStyle.collectAsStateValue(initial = FlowFilterBarStylePreference.default) - val flowFilterBarFilled = - context.flowFilterBarFilled.collectAsStateValue(initial = FlowFilterBarFilledPreference.default) - val flowFilterBarPadding = - context.flowFilterBarPadding.collectAsStateValue(initial = FlowFilterBarPaddingPreference.default) - val flowFilterBarTonalElevation = - context.flowFilterBarTonalElevation.collectAsStateValue(initial = FlowFilterBarTonalElevationPreference.default) - val flowTopBarTonalElevation = - context.flowTopBarTonalElevation.collectAsStateValue(initial = FlowTopBarTonalElevationPreference.default) - val flowArticleListFeedIcon = - context.flowArticleListFeedIcon.collectAsStateValue(initial = FlowArticleListFeedIconPreference.default) - val flowArticleListFeedName = - context.flowArticleListFeedName.collectAsStateValue(initial = FlowArticleListFeedNamePreference.default) - val flowArticleListImage = - context.flowArticleListImage.collectAsStateValue(initial = FlowArticleListImagePreference.default) - val flowArticleListDesc = - context.flowArticleListDesc.collectAsStateValue(initial = FlowArticleListDescPreference.default) - val flowArticleListDate = - context.flowArticleListDate.collectAsStateValue(initial = FlowArticleListDatePreference.default) - val flowArticleListTonalElevation = - context.flowArticleListTonalElevation.collectAsStateValue(initial = FlowArticleListTonalElevationPreference.default) - ProvideZcamViewingConditions { CompositionLocalProvider( LocalTonalPalettes provides tonalPalettes.also { it.Preheating() }, LocalUseDarkTheme provides useDarkTheme, - LocalTheme provides theme, - - LocalFeedsFilterBarStyle provides feedsFilterBarStyle.value, - LocalFeedsFilterBarFilled provides feedsFilterBarFilled.value, - LocalFeedsFilterBarPadding provides feedsFilterBarPadding, - LocalFeedsFilterBarTonalElevation provides feedsFilterBarTonalElevation.value, - LocalFeedsTopBarTonalElevation provides feedsTopBarTonalElevation.value, - LocalFeedsGroupListExpand provides feedsGroupListExpand.value, - LocalFeedsGroupListTonalElevation provides feedsGroupListTonalElevation.value, - - LocalFlowFilterBarStyle provides flowFilterBarStyle.value, - LocalFlowFilterBarFilled provides flowFilterBarFilled.value, - LocalFlowFilterBarPadding provides flowFilterBarPadding, - LocalFlowFilterBarTonalElevation provides flowFilterBarTonalElevation.value, - LocalFlowTopBarTonalElevation provides flowTopBarTonalElevation.value, - LocalFlowArticleListFeedIcon provides flowArticleListFeedIcon.value, - LocalFlowArticleListFeedName provides flowArticleListFeedName.value, - LocalFlowArticleListImage provides flowArticleListImage.value, - LocalFlowArticleListDesc provides flowArticleListDesc.value, - LocalFlowArticleListDate provides flowArticleListDate.value, - LocalFlowArticleListTonalElevation provides flowArticleListTonalElevation.value, ) { MaterialTheme( colorScheme = From 263c583f494b674f6142ff5741b4a454db4033c4 Mon Sep 17 00:00:00 2001 From: Ash Date: Mon, 2 May 2022 21:03:33 +0800 Subject: [PATCH 6/6] Add the StickyHeader switch for the article list --- ...owArticleListDateStickyHeaderPreference.kt | 41 +++++++++++++++++++ .../me/ash/reader/data/preference/Settings.kt | 5 +++ .../java/me/ash/reader/ui/component/Switch.kt | 6 +-- .../java/me/ash/reader/ui/ext/DataStoreExt.kt | 5 +++ .../reader/ui/page/home/flow/ArticleList.kt | 11 ++++- .../ash/reader/ui/page/home/flow/FlowPage.kt | 2 + .../settings/color/feeds/FeedsPageStyle.kt | 2 + .../page/settings/color/flow/FlowPageStyle.kt | 21 ++++++++-- app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 10 files changed, 86 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/me/ash/reader/data/preference/FlowArticleListDateStickyHeaderPreference.kt diff --git a/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDateStickyHeaderPreference.kt b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDateStickyHeaderPreference.kt new file mode 100644 index 0000000..cb7f6c7 --- /dev/null +++ b/app/src/main/java/me/ash/reader/data/preference/FlowArticleListDateStickyHeaderPreference.kt @@ -0,0 +1,41 @@ +package me.ash.reader.data.preference + +import android.content.Context +import androidx.datastore.preferences.core.Preferences +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.launch +import me.ash.reader.ui.ext.DataStoreKeys +import me.ash.reader.ui.ext.dataStore +import me.ash.reader.ui.ext.put + +sealed class FlowArticleListDateStickyHeaderPreference(val value: Boolean) : Preference() { + object ON : FlowArticleListDateStickyHeaderPreference(true) + object OFF : FlowArticleListDateStickyHeaderPreference(false) + + override fun put(context: Context, scope: CoroutineScope) { + scope.launch { + context.dataStore.put( + DataStoreKeys.FlowArticleListDateStickyHeader, + value + ) + } + } + + companion object { + val default = ON + val values = listOf(ON, OFF) + + fun fromPreferences(preferences: Preferences) = + when (preferences[DataStoreKeys.FlowArticleListDateStickyHeader.key]) { + true -> ON + false -> OFF + else -> default + } + } +} + +operator fun FlowArticleListDateStickyHeaderPreference.not(): FlowArticleListDateStickyHeaderPreference = + when (value) { + true -> FlowArticleListDateStickyHeaderPreference.OFF + false -> FlowArticleListDateStickyHeaderPreference.ON + } \ No newline at end of file diff --git a/app/src/main/java/me/ash/reader/data/preference/Settings.kt b/app/src/main/java/me/ash/reader/data/preference/Settings.kt index 651e838..b1d4022 100644 --- a/app/src/main/java/me/ash/reader/data/preference/Settings.kt +++ b/app/src/main/java/me/ash/reader/data/preference/Settings.kt @@ -33,6 +33,7 @@ data class Settings( val flowArticleListImage: FlowArticleListImagePreference = FlowArticleListImagePreference.default, val flowArticleListDesc: FlowArticleListDescPreference = FlowArticleListDescPreference.default, val flowArticleListTime: FlowArticleListTimePreference = FlowArticleListTimePreference.default, + val flowArticleListDateStickyHeader: FlowArticleListDateStickyHeaderPreference = FlowArticleListDateStickyHeaderPreference.default, val flowArticleListTonalElevation: FlowArticleListTonalElevationPreference = FlowArticleListTonalElevationPreference.default, ) @@ -59,6 +60,7 @@ fun Preferences.toSettings(): Settings { flowArticleListImage = FlowArticleListImagePreference.fromPreferences(this), flowArticleListDesc = FlowArticleListDescPreference.fromPreferences(this), flowArticleListTime = FlowArticleListTimePreference.fromPreferences(this), + flowArticleListDateStickyHeader = FlowArticleListDateStickyHeaderPreference.fromPreferences(this), flowArticleListTonalElevation = FlowArticleListTonalElevationPreference.fromPreferences(this), ) } @@ -93,6 +95,7 @@ fun SettingsProvider( LocalFlowArticleListImage provides settings.flowArticleListImage, LocalFlowArticleListDesc provides settings.flowArticleListDesc, LocalFlowArticleListTime provides settings.flowArticleListTime, + LocalFlowArticleListDateStickyHeader provides settings.flowArticleListDateStickyHeader, LocalFlowArticleListTonalElevation provides settings.flowArticleListTonalElevation, LocalFlowFilterBarStyle provides settings.flowFilterBarStyle, LocalFlowFilterBarFilled provides settings.flowFilterBarFilled, @@ -143,5 +146,7 @@ val LocalFlowArticleListDesc = compositionLocalOf { FlowArticleListDescPreference.default } val LocalFlowArticleListTime = compositionLocalOf { FlowArticleListTimePreference.default } +val LocalFlowArticleListDateStickyHeader = + compositionLocalOf { FlowArticleListDateStickyHeaderPreference.default } val LocalFlowArticleListTonalElevation = compositionLocalOf { FlowArticleListTonalElevationPreference.default } diff --git a/app/src/main/java/me/ash/reader/ui/component/Switch.kt b/app/src/main/java/me/ash/reader/ui/component/Switch.kt index ab00983..53b545c 100644 --- a/app/src/main/java/me/ash/reader/ui/component/Switch.kt +++ b/app/src/main/java/me/ash/reader/ui/component/Switch.kt @@ -45,8 +45,8 @@ fun Switch( .alpha(if (enable) 1f else 0.5f), shape = CircleShape, color = animateColorAsState( - if (activated) (tonalPalettes primary 40) onDark (tonalPalettes neutralVariant 50) - else (tonalPalettes neutralVariant 50) onDark (tonalPalettes neutral 60) + if (activated) (tonalPalettes primary 40) onDark (tonalPalettes secondary 50) + else (tonalPalettes neutralVariant 50) onDark (tonalPalettes neutral 30) ).value ) { Box( @@ -61,7 +61,7 @@ fun Switch( shape = CircleShape, color = animateColorAsState( if (activated) tonalPalettes primary 90 - else (tonalPalettes neutralVariant 70) onDark (tonalPalettes neutral 30) + else (tonalPalettes neutralVariant 70) onDark (tonalPalettes neutral 60) ).value ) {} } 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 ff56e64..79728c4 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 @@ -215,6 +215,11 @@ sealed class DataStoreKeys { get() = booleanPreferencesKey("flowArticleListTime") } + object FlowArticleListDateStickyHeader : DataStoreKeys() { + override val key: Preferences.Key + get() = booleanPreferencesKey("flowArticleListDateStickyHeader") + } + object FlowArticleListTonalElevation : DataStoreKeys() { override val key: Preferences.Key get() = intPreferencesKey("flowArticleListTonalElevation") diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt index 2d4f736..f05ad97 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/ArticleList.kt @@ -14,6 +14,7 @@ import me.ash.reader.data.entity.ArticleWithFeed fun LazyListScope.ArticleList( pagingItems: LazyPagingItems, articleListFeedIcon: Boolean, + articleListDateStickyHeader: Boolean, articleListTonalElevation: Int, onClick: (ArticleWithFeed) -> Unit = {}, ) { @@ -31,8 +32,14 @@ fun LazyListScope.ArticleList( is FlowItemView.Date -> { val separator = pagingItems[index] as FlowItemView.Date if (separator.showSpacer) item { Spacer(modifier = Modifier.height(40.dp)) } - stickyHeader { - StickyHeader(separator.date, articleListFeedIcon, articleListTonalElevation) + if (articleListDateStickyHeader) { + stickyHeader(key = separator.date) { + StickyHeader(separator.date, articleListFeedIcon, articleListTonalElevation) + } + } else { + item(key = separator.date) { + StickyHeader(separator.date, articleListFeedIcon, articleListTonalElevation) + } } } else -> {} diff --git a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt index a72e3c6..63360ed 100644 --- a/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt +++ b/app/src/main/java/me/ash/reader/ui/page/home/flow/FlowPage.kt @@ -58,6 +58,7 @@ fun FlowPage( val topBarTonalElevation = LocalFlowTopBarTonalElevation.current val articleListTonalElevation = LocalFlowArticleListTonalElevation.current val articleListFeedIcon = LocalFlowArticleListFeedIcon.current + val articleListDateStickyHeader = LocalFlowArticleListDateStickyHeader.current val filterBarStyle = LocalFlowFilterBarStyle.current val filterBarFilled = LocalFlowFilterBarFilled.current val filterBarPadding = LocalFlowFilterBarPadding.current @@ -260,6 +261,7 @@ fun FlowPage( ArticleList( pagingItems = pagingItems, articleListFeedIcon = articleListFeedIcon.value, + articleListDateStickyHeader = articleListDateStickyHeader.value, articleListTonalElevation = articleListTonalElevation.value, ) { onSearch = false diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt index 02fafd7..a7fce97 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/feeds/FeedsPageStyle.kt @@ -1,5 +1,6 @@ package me.ash.reader.ui.page.settings.color.feeds +import androidx.compose.animation.animateContentSize import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* @@ -294,6 +295,7 @@ fun FeedsPagePreview( Column( modifier = Modifier + .animateContentSize() .background( color = MaterialTheme.colorScheme.surfaceColorAtElevation( groupListTonalElevation.value.dp diff --git a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt index 31e1e6f..991762a 100644 --- a/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt +++ b/app/src/main/java/me/ash/reader/ui/page/settings/color/flow/FlowPageStyle.kt @@ -1,6 +1,7 @@ package me.ash.reader.ui.page.settings.color.flow import android.annotation.SuppressLint +import androidx.compose.animation.animateContentSize import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* @@ -51,7 +52,8 @@ fun FlowPageStyle( val articleListFeedName = LocalFlowArticleListFeedName.current val articleListImage = LocalFlowArticleListImage.current val articleListDesc = LocalFlowArticleListDesc.current - val articleListDate = LocalFlowArticleListTime.current + val articleListTime = LocalFlowArticleListTime.current + val articleListStickyDate = LocalFlowArticleListDateStickyHeader.current val articleListTonalElevation = LocalFlowArticleListTonalElevation.current val scope = rememberCoroutineScope() @@ -190,11 +192,21 @@ fun FlowPageStyle( SettingItem( title = stringResource(R.string.display_article_date), onClick = { - (!articleListDate).put(context, scope) + (!articleListTime).put(context, scope) }, ) { - Switch(activated = articleListDate.value) { - (!articleListDate).put(context, scope) + Switch(activated = articleListTime.value) { + (!articleListTime).put(context, scope) + } + } + SettingItem( + title = stringResource(R.string.article_date_sticky_header), + onClick = { + (!articleListStickyDate).put(context, scope) + }, + ) { + Switch(activated = articleListStickyDate.value) { + (!articleListStickyDate).put(context, scope) } } SettingItem( @@ -343,6 +355,7 @@ fun FlowPagePreview( Column( modifier = Modifier + .animateContentSize() .background( color = MaterialTheme.colorScheme.surfaceColorAtElevation( articleListTonalElevation.value.dp diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 95f2e0d..bea1e53 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -134,6 +134,7 @@ 显示文章插图 显示订阅源名称 显示订阅源图标 + 文章发布日期粘性标签(实验性) 文章列表 分组列表 始终展开 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f72095b..6e0a66d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -134,6 +134,7 @@ Display Article Images Display Feed Names Display Feed Favicons + Article Publish Date Sticky Header (Experimental) Article List Group List Always Expand