Add FlowPage style settings
This commit is contained in:
parent
0cfd63c571
commit
9bea2e8e8b
|
@ -2,13 +2,16 @@ package me.ash.reader.data.entity
|
||||||
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.FiberManualRecord
|
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.StarOutline
|
||||||
import androidx.compose.material.icons.rounded.Subject
|
import androidx.compose.material.icons.rounded.Subject
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
|
|
||||||
class Filter(
|
class Filter(
|
||||||
var index: Int,
|
val index: Int,
|
||||||
var icon: ImageVector,
|
val iconOutline: ImageVector,
|
||||||
|
val iconFilled: ImageVector,
|
||||||
) {
|
) {
|
||||||
fun isStarred(): Boolean = this == Starred
|
fun isStarred(): Boolean = this == Starred
|
||||||
fun isUnread(): Boolean = this == Unread
|
fun isUnread(): Boolean = this == Unread
|
||||||
|
@ -17,15 +20,18 @@ class Filter(
|
||||||
companion object {
|
companion object {
|
||||||
val Starred = Filter(
|
val Starred = Filter(
|
||||||
index = 0,
|
index = 0,
|
||||||
icon = Icons.Rounded.StarOutline,
|
iconOutline = Icons.Rounded.StarOutline,
|
||||||
|
iconFilled = Icons.Rounded.Star,
|
||||||
)
|
)
|
||||||
val Unread = Filter(
|
val Unread = Filter(
|
||||||
index = 1,
|
index = 1,
|
||||||
icon = Icons.Outlined.FiberManualRecord,
|
iconOutline = Icons.Outlined.FiberManualRecord,
|
||||||
|
iconFilled = Icons.Rounded.FiberManualRecord,
|
||||||
)
|
)
|
||||||
val All = Filter(
|
val All = Filter(
|
||||||
index = 2,
|
index = 2,
|
||||||
icon = Icons.Rounded.Subject,
|
iconOutline = Icons.Rounded.Subject,
|
||||||
|
iconFilled = Icons.Rounded.Subject,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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<ArticleListDatePreference>
|
||||||
|
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
|
||||||
|
}
|
|
@ -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<ArticleListDescPreference>
|
||||||
|
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
|
||||||
|
}
|
|
@ -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<ArticleListFeedIconPreference>
|
||||||
|
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
|
||||||
|
}
|
|
@ -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<ArticleListFeedNamePreference>
|
||||||
|
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
|
||||||
|
}
|
|
@ -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<ArticleListImagePreference>
|
||||||
|
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
|
||||||
|
}
|
|
@ -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<ArticleListTonalElevationPreference>
|
||||||
|
get() = this.dataStore.data.map {
|
||||||
|
when (it[DataStoreKeys.ArticleListTonalElevation.key]) {
|
||||||
|
0 -> Level0
|
||||||
|
1 -> Level1
|
||||||
|
3 -> Level2
|
||||||
|
6 -> Level3
|
||||||
|
8 -> Level4
|
||||||
|
12 -> Level5
|
||||||
|
else -> default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<FilterBarFilledPreference>
|
||||||
|
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
|
||||||
|
}
|
|
@ -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<Int>
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<FilterBarStylePreference>
|
||||||
|
get() = this.dataStore.data.map {
|
||||||
|
when (it[DataStoreKeys.FilterBarStyle.key]) {
|
||||||
|
0 -> Icon
|
||||||
|
1 -> IconLabel
|
||||||
|
2 -> IconLabelOnlySelected
|
||||||
|
else -> default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<FilterBarTonalElevationPreference>
|
||||||
|
get() = this.dataStore.data.map {
|
||||||
|
when (it[DataStoreKeys.FilterBarTonalElevation.key]) {
|
||||||
|
0 -> Level0
|
||||||
|
1 -> Level1
|
||||||
|
3 -> Level2
|
||||||
|
6 -> Level3
|
||||||
|
8 -> Level4
|
||||||
|
12 -> Level5
|
||||||
|
else -> default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
|
@ -33,6 +33,7 @@ val Context.currentAccountType: Int
|
||||||
get() = this.dataStore.get(DataStoreKeys.CurrentAccountType)!!
|
get() = this.dataStore.get(DataStoreKeys.CurrentAccountType)!!
|
||||||
val Context.themeIndex: Int
|
val Context.themeIndex: Int
|
||||||
get() = this.dataStore.get(DataStoreKeys.ThemeIndex) ?: 5
|
get() = this.dataStore.get(DataStoreKeys.ThemeIndex) ?: 5
|
||||||
|
|
||||||
val Context.customPrimaryColor: String
|
val Context.customPrimaryColor: String
|
||||||
get() = this.dataStore.get(DataStoreKeys.CustomPrimaryColor) ?: ""
|
get() = this.dataStore.get(DataStoreKeys.CustomPrimaryColor) ?: ""
|
||||||
val Context.initialPage: Int
|
val Context.initialPage: Int
|
||||||
|
@ -129,6 +130,56 @@ sealed class DataStoreKeys<T> {
|
||||||
get() = stringPreferencesKey("customPrimaryColor")
|
get() = stringPreferencesKey("customPrimaryColor")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object FilterBarStyle : DataStoreKeys<Int>() {
|
||||||
|
override val key: Preferences.Key<Int>
|
||||||
|
get() = intPreferencesKey("filterBarStyle")
|
||||||
|
}
|
||||||
|
|
||||||
|
object FilterBarFilled : DataStoreKeys<Boolean>() {
|
||||||
|
override val key: Preferences.Key<Boolean>
|
||||||
|
get() = booleanPreferencesKey("filterBarFilled")
|
||||||
|
}
|
||||||
|
|
||||||
|
object FilterBarPadding : DataStoreKeys<Int>() {
|
||||||
|
override val key: Preferences.Key<Int>
|
||||||
|
get() = intPreferencesKey("filterBarPadding")
|
||||||
|
}
|
||||||
|
|
||||||
|
object FilterBarTonalElevation : DataStoreKeys<Int>() {
|
||||||
|
override val key: Preferences.Key<Int>
|
||||||
|
get() = intPreferencesKey("filterBarTonalElevation")
|
||||||
|
}
|
||||||
|
|
||||||
|
object ArticleListFeedIcon : DataStoreKeys<Boolean>() {
|
||||||
|
override val key: Preferences.Key<Boolean>
|
||||||
|
get() = booleanPreferencesKey("articleListFeedIcon")
|
||||||
|
}
|
||||||
|
|
||||||
|
object ArticleListFeedName : DataStoreKeys<Boolean>() {
|
||||||
|
override val key: Preferences.Key<Boolean>
|
||||||
|
get() = booleanPreferencesKey("articleListFeedName")
|
||||||
|
}
|
||||||
|
|
||||||
|
object ArticleListImage : DataStoreKeys<Boolean>() {
|
||||||
|
override val key: Preferences.Key<Boolean>
|
||||||
|
get() = booleanPreferencesKey("articleListImage")
|
||||||
|
}
|
||||||
|
|
||||||
|
object ArticleListDesc : DataStoreKeys<Boolean>() {
|
||||||
|
override val key: Preferences.Key<Boolean>
|
||||||
|
get() = booleanPreferencesKey("articleListDesc")
|
||||||
|
}
|
||||||
|
|
||||||
|
object ArticleListDate : DataStoreKeys<Boolean>() {
|
||||||
|
override val key: Preferences.Key<Boolean>
|
||||||
|
get() = booleanPreferencesKey("articleListDate")
|
||||||
|
}
|
||||||
|
|
||||||
|
object ArticleListTonalElevation : DataStoreKeys<Int>() {
|
||||||
|
override val key: Preferences.Key<Int>
|
||||||
|
get() = intPreferencesKey("articleListTonalElevation")
|
||||||
|
}
|
||||||
|
|
||||||
object InitialPage : DataStoreKeys<Int>() {
|
object InitialPage : DataStoreKeys<Int>() {
|
||||||
override val key: Preferences.Key<Int>
|
override val key: Preferences.Key<Int>
|
||||||
get() = intPreferencesKey("initialPage")
|
get() = intPreferencesKey("initialPage")
|
||||||
|
|
|
@ -3,6 +3,7 @@ package me.ash.reader.ui.ext
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
@ -10,3 +11,9 @@ import kotlin.coroutines.CoroutineContext
|
||||||
fun <T> StateFlow<T>.collectAsStateValue(
|
fun <T> StateFlow<T>.collectAsStateValue(
|
||||||
context: CoroutineContext = Dispatchers.Default
|
context: CoroutineContext = Dispatchers.Default
|
||||||
): T = collectAsState(context).value
|
): T = collectAsState(context).value
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun <T : R, R> Flow<T>.collectAsStateValue(
|
||||||
|
initial: R,
|
||||||
|
context: CoroutineContext = Dispatchers.Default
|
||||||
|
): R = collectAsState(initial, context).value
|
|
@ -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.home.read.ReadPage
|
||||||
import me.ash.reader.ui.page.settings.SettingsPage
|
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.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.interaction.Interaction
|
||||||
import me.ash.reader.ui.page.settings.tips.TipsAndSupport
|
import me.ash.reader.ui.page.settings.tips.TipsAndSupport
|
||||||
import me.ash.reader.ui.page.startup.StartupPage
|
import me.ash.reader.ui.page.startup.StartupPage
|
||||||
|
@ -97,9 +98,12 @@ fun HomeEntry(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
startDestination = if (context.isFirstLaunch) RouteName.STARTUP else RouteName.FEEDS,
|
startDestination = if (context.isFirstLaunch) RouteName.STARTUP else RouteName.FEEDS,
|
||||||
) {
|
) {
|
||||||
|
// Startup
|
||||||
animatedComposable(route = RouteName.STARTUP) {
|
animatedComposable(route = RouteName.STARTUP) {
|
||||||
StartupPage(navController)
|
StartupPage(navController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Home
|
||||||
animatedComposable(route = RouteName.FEEDS) {
|
animatedComposable(route = RouteName.FEEDS) {
|
||||||
FeedsPage(navController = navController, homeViewModel = homeViewModel)
|
FeedsPage(navController = navController, homeViewModel = homeViewModel)
|
||||||
}
|
}
|
||||||
|
@ -113,15 +117,26 @@ fun HomeEntry(
|
||||||
animatedComposable(route = "${RouteName.READING}/{articleId}") {
|
animatedComposable(route = "${RouteName.READING}/{articleId}") {
|
||||||
ReadPage(navController = navController)
|
ReadPage(navController = navController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Settings
|
||||||
animatedComposable(route = RouteName.SETTINGS) {
|
animatedComposable(route = RouteName.SETTINGS) {
|
||||||
SettingsPage(navController)
|
SettingsPage(navController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Color & Style
|
||||||
animatedComposable(route = RouteName.COLOR_AND_STYLE) {
|
animatedComposable(route = RouteName.COLOR_AND_STYLE) {
|
||||||
ColorAndStyle(navController)
|
ColorAndStyle(navController)
|
||||||
}
|
}
|
||||||
|
animatedComposable(route = RouteName.FLOW_PAGE_STYLE) {
|
||||||
|
FlowPageStyle(navController)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interaction
|
||||||
animatedComposable(route = RouteName.INTERACTION) {
|
animatedComposable(route = RouteName.INTERACTION) {
|
||||||
Interaction(navController)
|
Interaction(navController)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tips & Support
|
||||||
animatedComposable(route = RouteName.TIPS_AND_SUPPORT) {
|
animatedComposable(route = RouteName.TIPS_AND_SUPPORT) {
|
||||||
TipsAndSupport(navController)
|
TipsAndSupport(navController)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,24 @@
|
||||||
package me.ash.reader.ui.page.common
|
package me.ash.reader.ui.page.common
|
||||||
|
|
||||||
object RouteName {
|
object RouteName {
|
||||||
|
// Startup
|
||||||
const val STARTUP = "startup"
|
const val STARTUP = "startup"
|
||||||
|
|
||||||
|
// Home
|
||||||
const val FEEDS = "feeds"
|
const val FEEDS = "feeds"
|
||||||
const val FLOW = "flow"
|
const val FLOW = "flow"
|
||||||
const val READING = "reading"
|
const val READING = "reading"
|
||||||
|
|
||||||
|
// Settings
|
||||||
const val SETTINGS = "settings"
|
const val SETTINGS = "settings"
|
||||||
|
|
||||||
|
// Color & Style
|
||||||
const val COLOR_AND_STYLE = "color_and_style"
|
const val COLOR_AND_STYLE = "color_and_style"
|
||||||
|
const val FLOW_PAGE_STYLE = "flow_page_style"
|
||||||
|
|
||||||
|
// Interaction
|
||||||
const val INTERACTION = "interaction"
|
const val INTERACTION = "interaction"
|
||||||
|
|
||||||
|
// Tips & Support
|
||||||
const val TIPS_AND_SUPPORT = "tips_and_support"
|
const val TIPS_AND_SUPPORT = "tips_and_support"
|
||||||
}
|
}
|
|
@ -1,16 +1,27 @@
|
||||||
package me.ash.reader.ui.page.home
|
package me.ash.reader.ui.page.home
|
||||||
|
|
||||||
import android.view.SoundEffectConstants
|
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.material3.*
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalView
|
import androidx.compose.ui.platform.LocalView
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.zIndex
|
|
||||||
import com.google.accompanist.pager.ExperimentalPagerApi
|
import com.google.accompanist.pager.ExperimentalPagerApi
|
||||||
import me.ash.reader.data.entity.Filter
|
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.ext.getName
|
||||||
|
import me.ash.reader.ui.theme.palette.onDark
|
||||||
|
|
||||||
@OptIn(ExperimentalPagerApi::class)
|
@OptIn(ExperimentalPagerApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -20,51 +31,67 @@ fun FilterBar(
|
||||||
filterOnClick: (Filter) -> Unit = {},
|
filterOnClick: (Filter) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val view = LocalView.current
|
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(
|
NavigationBar(
|
||||||
// modifier = Modifier.height(60.dp)
|
tonalElevation = filterBarTonalElevation.value.dp,
|
||||||
) {
|
) {
|
||||||
Divider(
|
Spacer(modifier = Modifier.width(filterBarPadding.dp))
|
||||||
modifier = Modifier
|
listOf(
|
||||||
.fillMaxWidth()
|
Filter.Starred,
|
||||||
.height(1.dp)
|
Filter.Unread,
|
||||||
.zIndex(1f),
|
Filter.All,
|
||||||
color = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.24f)
|
).forEach { item ->
|
||||||
)
|
NavigationBarItem(
|
||||||
NavigationBar(
|
// modifier = Modifier.height(60.dp),
|
||||||
// modifier = Modifier.fillMaxSize(),
|
alwaysShowLabel = when (filterBarStyle) {
|
||||||
// tonalElevation = 0.dp,
|
is FilterBarStylePreference.Icon -> false
|
||||||
) {
|
is FilterBarStylePreference.IconLabel -> true
|
||||||
Spacer(modifier = Modifier.width(60.dp))
|
is FilterBarStylePreference.IconLabelOnlySelected -> false
|
||||||
listOf(
|
},
|
||||||
Filter.Starred,
|
icon = {
|
||||||
Filter.Unread,
|
Icon(
|
||||||
Filter.All,
|
imageVector = if (filter == item && filterBarFilled.value) {
|
||||||
).forEach { item ->
|
item.iconFilled
|
||||||
NavigationBarItem(
|
} else {
|
||||||
icon = {
|
item.iconOutline
|
||||||
Icon(
|
},
|
||||||
imageVector = item.icon,
|
contentDescription = item.getName()
|
||||||
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,
|
selected = filter == item,
|
||||||
onClick = {
|
onClick = {
|
||||||
// view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
|
// view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
|
||||||
view.playSoundEffect(SoundEffectConstants.CLICK)
|
view.playSoundEffect(SoundEffectConstants.CLICK)
|
||||||
filterOnClick(item)
|
filterOnClick(item)
|
||||||
},
|
},
|
||||||
colors = NavigationBarItemDefaults.colors(
|
colors = NavigationBarItemDefaults.colors(
|
||||||
// selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer alwaysLight true,
|
// selectedIconColor = MaterialTheme.colorScheme.onSecondaryContainer alwaysLight true,
|
||||||
// unselectedIconColor = MaterialTheme.colorScheme.outline,
|
// unselectedIconColor = MaterialTheme.colorScheme.outline,
|
||||||
// selectedTextColor = MaterialTheme.colorScheme.onSurface alwaysLight true,
|
// selectedTextColor = MaterialTheme.colorScheme.onSurface alwaysLight true,
|
||||||
// unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
// 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))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -174,7 +174,7 @@ fun FeedsPage(
|
||||||
Banner(
|
Banner(
|
||||||
title = filterState.filter.getName(),
|
title = filterState.filter.getName(),
|
||||||
desc = feedsViewState.importantCount,
|
desc = feedsViewState.importantCount,
|
||||||
icon = filterState.filter.icon,
|
icon = filterState.filter.iconOutline,
|
||||||
action = {
|
action = {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Outlined.KeyboardArrowRight,
|
imageVector = Icons.Outlined.KeyboardArrowRight,
|
||||||
|
@ -241,9 +241,6 @@ fun FeedsPage(
|
||||||
},
|
},
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
FilterBar(
|
FilterBar(
|
||||||
modifier = Modifier
|
|
||||||
.height(60.dp)
|
|
||||||
.fillMaxWidth(),
|
|
||||||
filter = filterState.filter,
|
filter = filterState.filter,
|
||||||
filterOnClick = {
|
filterOnClick = {
|
||||||
filterChange(
|
filterChange(
|
||||||
|
|
|
@ -21,6 +21,13 @@ import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import me.ash.reader.R
|
import me.ash.reader.R
|
||||||
import me.ash.reader.data.entity.ArticleWithFeed
|
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.ext.formatAsString
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
@ -30,6 +37,16 @@ fun ArticleItem(
|
||||||
onClick: (ArticleWithFeed) -> Unit = {},
|
onClick: (ArticleWithFeed) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
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(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -44,67 +61,84 @@ fun ArticleItem(
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(
|
// Feed name
|
||||||
modifier = Modifier
|
if (articleListFeedName.value) {
|
||||||
.weight(1f)
|
Text(
|
||||||
.padding(start = 30.dp),
|
modifier = Modifier
|
||||||
text = articleWithFeed.feed.name,
|
.weight(1f)
|
||||||
color = MaterialTheme.colorScheme.tertiary,
|
.padding(start = if (articleListFeedIcon.value) 30.dp else 0.dp),
|
||||||
style = MaterialTheme.typography.labelMedium,
|
text = articleWithFeed.feed.name,
|
||||||
maxLines = 1,
|
color = MaterialTheme.colorScheme.tertiary,
|
||||||
overflow = TextOverflow.Ellipsis,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
)
|
maxLines = 1,
|
||||||
Row(
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier.padding(start = 6.dp),
|
)
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
}
|
||||||
) {
|
|
||||||
if (articleWithFeed.article.isStarred) {
|
if (articleListDate.value) {
|
||||||
Icon(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier.padding(start = 6.dp),
|
||||||
.size(14.dp)
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
.padding(end = 2.dp),
|
) {
|
||||||
imageVector = Icons.Rounded.Star,
|
// Starred
|
||||||
contentDescription = stringResource(R.string.starred),
|
if (articleWithFeed.article.isStarred) {
|
||||||
tint = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f),
|
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(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
Row(
|
// Feed icon
|
||||||
modifier = Modifier
|
if (articleListFeedIcon.value) {
|
||||||
.size(20.dp)
|
Row(
|
||||||
.clip(CircleShape)
|
modifier = Modifier
|
||||||
.background(MaterialTheme.colorScheme.outline.copy(alpha = 0.2f))
|
.size(20.dp)
|
||||||
) {}
|
.clip(CircleShape)
|
||||||
Spacer(modifier = Modifier.width(10.dp))
|
.background(MaterialTheme.colorScheme.outline.copy(alpha = 0.2f))
|
||||||
|
) {}
|
||||||
|
Spacer(modifier = Modifier.width(10.dp))
|
||||||
|
}
|
||||||
|
// Article
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
) {
|
) {
|
||||||
|
// Title
|
||||||
Text(
|
Text(
|
||||||
text = articleWithFeed.article.title,
|
text = articleWithFeed.article.title,
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
style = MaterialTheme.typography.titleMedium,
|
style = MaterialTheme.typography.titleMedium,
|
||||||
maxLines = 2,
|
maxLines = if (articleListDesc.value) 2 else 4,
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = articleWithFeed.article.shortDescription,
|
|
||||||
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f),
|
|
||||||
style = MaterialTheme.typography.bodySmall,
|
|
||||||
maxLines = 2,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
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,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import me.ash.reader.data.entity.ArticleWithFeed
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
fun LazyListScope.ArticleList(
|
fun LazyListScope.ArticleList(
|
||||||
pagingItems: LazyPagingItems<FlowItemView>,
|
pagingItems: LazyPagingItems<FlowItemView>,
|
||||||
|
articleListFeedIcon: Boolean,
|
||||||
|
articleListTonalElevation: Int,
|
||||||
onClick: (ArticleWithFeed) -> Unit = {},
|
onClick: (ArticleWithFeed) -> Unit = {},
|
||||||
) {
|
) {
|
||||||
for (index in 0 until pagingItems.itemCount) {
|
for (index in 0 until pagingItems.itemCount) {
|
||||||
|
@ -30,7 +32,7 @@ fun LazyListScope.ArticleList(
|
||||||
val separator = pagingItems[index] as FlowItemView.Date
|
val separator = pagingItems[index] as FlowItemView.Date
|
||||||
if (separator.showSpacer) item { Spacer(modifier = Modifier.height(40.dp)) }
|
if (separator.showSpacer) item { Spacer(modifier = Modifier.height(40.dp)) }
|
||||||
stickyHeader {
|
stickyHeader {
|
||||||
StickyHeader(separator.date)
|
StickyHeader(separator.date, articleListFeedIcon, articleListTonalElevation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {}
|
||||||
|
|
|
@ -15,6 +15,7 @@ import androidx.compose.material3.*
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalLifecycleOwner
|
import androidx.compose.ui.platform.LocalLifecycleOwner
|
||||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
@ -26,6 +27,10 @@ import androidx.paging.compose.LazyPagingItems
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import me.ash.reader.R
|
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.data.repository.SyncWorker.Companion.getIsSyncing
|
||||||
import me.ash.reader.ui.component.DisplayText
|
import me.ash.reader.ui.component.DisplayText
|
||||||
import me.ash.reader.ui.component.FeedbackIconButton
|
import me.ash.reader.ui.component.FeedbackIconButton
|
||||||
|
@ -52,6 +57,7 @@ fun FlowPage(
|
||||||
homeViewModel: HomeViewModel,
|
homeViewModel: HomeViewModel,
|
||||||
pagingItems: LazyPagingItems<FlowItemView>,
|
pagingItems: LazyPagingItems<FlowItemView>,
|
||||||
) {
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
@ -64,6 +70,11 @@ fun FlowPage(
|
||||||
val homeViewState = homeViewModel.viewState.collectAsStateValue()
|
val homeViewState = homeViewModel.viewState.collectAsStateValue()
|
||||||
val listState = if (pagingItems.itemCount > 0) viewState.listState else rememberLazyListState()
|
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
|
val owner = LocalLifecycleOwner.current
|
||||||
var isSyncing by remember { mutableStateOf(false) }
|
var isSyncing by remember { mutableStateOf(false) }
|
||||||
homeViewModel.syncWorkLiveData.observe(owner) {
|
homeViewModel.syncWorkLiveData.observe(owner) {
|
||||||
|
@ -98,15 +109,17 @@ fun FlowPage(
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp))
|
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp))
|
||||||
.statusBarsPadding()
|
.statusBarsPadding()
|
||||||
.navigationBarsPadding(),
|
.navigationBarsPadding(),
|
||||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp),
|
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp),
|
||||||
topBar = {
|
topBar = {
|
||||||
SmallTopAppBar(
|
SmallTopAppBar(
|
||||||
title = {},
|
title = {},
|
||||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp),
|
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||||
|
articleListTonalElevation.value.dp
|
||||||
|
),
|
||||||
),
|
),
|
||||||
navigationIcon = {
|
navigationIcon = {
|
||||||
FeedbackIconButton(
|
FeedbackIconButton(
|
||||||
|
@ -115,7 +128,7 @@ fun FlowPage(
|
||||||
tint = MaterialTheme.colorScheme.onSurface
|
tint = MaterialTheme.colorScheme.onSurface
|
||||||
) {
|
) {
|
||||||
onSearch = false
|
onSearch = false
|
||||||
if(navController.previousBackStackEntry == null) {
|
if (navController.previousBackStackEntry == null) {
|
||||||
navController.navigate(RouteName.FEEDS) {
|
navController.navigate(RouteName.FEEDS) {
|
||||||
launchSingleTop = true
|
launchSingleTop = true
|
||||||
}
|
}
|
||||||
|
@ -184,7 +197,7 @@ fun FlowPage(
|
||||||
state = listState,
|
state = listState,
|
||||||
) {
|
) {
|
||||||
item {
|
item {
|
||||||
DisplayTextHeader(filterState, isSyncing)
|
DisplayTextHeader(filterState, isSyncing, articleListFeedIcon.value)
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = markAsRead,
|
visible = markAsRead,
|
||||||
enter = fadeIn() + expandVertically(),
|
enter = fadeIn() + expandVertically(),
|
||||||
|
@ -246,6 +259,8 @@ fun FlowPage(
|
||||||
}
|
}
|
||||||
ArticleList(
|
ArticleList(
|
||||||
pagingItems = pagingItems,
|
pagingItems = pagingItems,
|
||||||
|
articleListFeedIcon = articleListFeedIcon.value,
|
||||||
|
articleListTonalElevation = articleListTonalElevation.value,
|
||||||
) {
|
) {
|
||||||
onSearch = false
|
onSearch = false
|
||||||
navController.navigate("${RouteName.READING}/${it.article.id}") {
|
navController.navigate("${RouteName.READING}/${it.article.id}") {
|
||||||
|
@ -263,9 +278,6 @@ fun FlowPage(
|
||||||
},
|
},
|
||||||
bottomBar = {
|
bottomBar = {
|
||||||
FilterBar(
|
FilterBar(
|
||||||
modifier = Modifier
|
|
||||||
.height(60.dp)
|
|
||||||
.fillMaxWidth(),
|
|
||||||
filter = filterState.filter,
|
filter = filterState.filter,
|
||||||
filterOnClick = {
|
filterOnClick = {
|
||||||
flowViewModel.dispatch(FlowViewAction.ScrollToItem(0))
|
flowViewModel.dispatch(FlowViewAction.ScrollToItem(0))
|
||||||
|
@ -280,10 +292,11 @@ fun FlowPage(
|
||||||
@Composable
|
@Composable
|
||||||
private fun DisplayTextHeader(
|
private fun DisplayTextHeader(
|
||||||
filterState: FilterState,
|
filterState: FilterState,
|
||||||
isSyncing: Boolean
|
isSyncing: Boolean,
|
||||||
|
articleListFeedIcon: Boolean,
|
||||||
) {
|
) {
|
||||||
DisplayText(
|
DisplayText(
|
||||||
modifier = Modifier.padding(start = 30.dp),
|
modifier = Modifier.padding(start = if (articleListFeedIcon) 30.dp else 0.dp),
|
||||||
text = when {
|
text = when {
|
||||||
filterState.group != null -> filterState.group.name
|
filterState.group != null -> filterState.group.name
|
||||||
filterState.feed != null -> filterState.feed.name
|
filterState.feed != null -> filterState.feed.name
|
||||||
|
|
|
@ -13,16 +13,20 @@ import androidx.compose.ui.unit.dp
|
||||||
import me.ash.reader.ui.ext.surfaceColorAtElevation
|
import me.ash.reader.ui.ext.surfaceColorAtElevation
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun StickyHeader(currentItemDay: String) {
|
fun StickyHeader(
|
||||||
|
currentItemDay: String,
|
||||||
|
articleListFeedIcon: Boolean,
|
||||||
|
articleListTonalElevation: Int,
|
||||||
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)),
|
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.dp)),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier
|
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,
|
text = currentItemDay,
|
||||||
color = MaterialTheme.colorScheme.primary,
|
color = MaterialTheme.colorScheme.primary,
|
||||||
style = MaterialTheme.typography.labelLarge,
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
|
|
@ -30,6 +30,7 @@ import kotlinx.coroutines.launch
|
||||||
import me.ash.reader.R
|
import me.ash.reader.R
|
||||||
import me.ash.reader.ui.component.*
|
import me.ash.reader.ui.component.*
|
||||||
import me.ash.reader.ui.ext.*
|
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.page.settings.SettingItem
|
||||||
import me.ash.reader.ui.svg.PALETTE
|
import me.ash.reader.ui.svg.PALETTE
|
||||||
import me.ash.reader.ui.svg.SVGString
|
import me.ash.reader.ui.svg.SVGString
|
||||||
|
@ -167,8 +168,11 @@ fun ColorAndStyle(
|
||||||
) {}
|
) {}
|
||||||
SettingItem(
|
SettingItem(
|
||||||
title = stringResource(R.string.flow_page),
|
title = stringResource(R.string.flow_page),
|
||||||
enable = false,
|
onClick = {
|
||||||
onClick = {},
|
navController.navigate(RouteName.FLOW_PAGE_STYLE) {
|
||||||
|
launchSingleTop = true
|
||||||
|
}
|
||||||
|
},
|
||||||
) {}
|
) {}
|
||||||
SettingItem(
|
SettingItem(
|
||||||
title = stringResource(R.string.reading_page),
|
title = stringResource(R.string.reading_page),
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -79,7 +79,7 @@
|
||||||
<string name="accounts">账户</string>
|
<string name="accounts">账户</string>
|
||||||
<string name="accounts_desc">本地、FreshRSS</string>
|
<string name="accounts_desc">本地、FreshRSS</string>
|
||||||
<string name="color_and_style">颜色和样式</string>
|
<string name="color_and_style">颜色和样式</string>
|
||||||
<string name="color_and_style_desc">主题、色彩系统、字体大小</string>
|
<string name="color_and_style_desc">主题、色调样式、字体大小</string>
|
||||||
<string name="interaction">交互</string>
|
<string name="interaction">交互</string>
|
||||||
<string name="interaction_desc">启动时、触感反馈</string>
|
<string name="interaction_desc">启动时、触感反馈</string>
|
||||||
<string name="languages">语言</string>
|
<string name="languages">语言</string>
|
||||||
|
|
|
@ -79,7 +79,7 @@
|
||||||
<string name="accounts">Accounts</string>
|
<string name="accounts">Accounts</string>
|
||||||
<string name="accounts_desc">Local, FreshRSS</string>
|
<string name="accounts_desc">Local, FreshRSS</string>
|
||||||
<string name="color_and_style">Color & style</string>
|
<string name="color_and_style">Color & style</string>
|
||||||
<string name="color_and_style_desc">Theme, color system, font size</string>
|
<string name="color_and_style_desc">Theme, color style, font size</string>
|
||||||
<string name="interaction">Interaction</string>
|
<string name="interaction">Interaction</string>
|
||||||
<string name="interaction_desc">On start, haptic feedback</string>
|
<string name="interaction_desc">On start, haptic feedback</string>
|
||||||
<string name="languages">Languages</string>
|
<string name="languages">Languages</string>
|
||||||
|
|
Loading…
Reference in New Issue
Block a user