Add FeedsPage style settings

This commit is contained in:
Ash 2022-05-02 13:52:08 +08:00
parent 9bea2e8e8b
commit fa3c5e3601
42 changed files with 1550 additions and 406 deletions

View File

@ -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<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
}

View File

@ -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<FeedsFilterBarFilledPreference>
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
}

View File

@ -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<Int>
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)
}
}
}

View File

@ -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<FeedsFilterBarStylePreference>
get() = this.dataStore.data.map {
when (it[DataStoreKeys.FeedsFilterBarStyle.key]) {
0 -> Icon
1 -> IconLabel
2 -> IconLabelOnlySelected
else -> default
}
}
}
}

View File

@ -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<FeedsFilterBarTonalElevationPreference>
get() = this.dataStore.data.map {
when (it[DataStoreKeys.FeedsFilterBarTonalElevation.key]) {
0 -> Level0
1 -> Level1
3 -> Level2
6 -> Level3
8 -> Level4
12 -> Level5
else -> default
}
}
}
}

View File

@ -10,14 +10,14 @@ import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put import me.ash.reader.ui.ext.put
sealed class ArticleListDatePreference(val value: Boolean) : Preference() { sealed class FeedsGroupListExpandPreference(val value: Boolean) : Preference() {
object ON : ArticleListDatePreference(true) object ON : FeedsGroupListExpandPreference(true)
object OFF : ArticleListDatePreference(false) object OFF : FeedsGroupListExpandPreference(false)
override fun put(context: Context, scope: CoroutineScope) { override fun put(context: Context, scope: CoroutineScope) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
context.dataStore.put( context.dataStore.put(
DataStoreKeys.ArticleListDate, DataStoreKeys.FeedsGroupListExpand,
value value
) )
} }
@ -27,9 +27,9 @@ sealed class ArticleListDatePreference(val value: Boolean) : Preference() {
val default = ON val default = ON
val values = listOf(ON, OFF) val values = listOf(ON, OFF)
val Context.articleListDate: Flow<ArticleListDatePreference> val Context.feedsGroupListExpand: Flow<FeedsGroupListExpandPreference>
get() = this.dataStore.data.map { get() = this.dataStore.data.map {
when (it[DataStoreKeys.ArticleListDate.key]) { when (it[DataStoreKeys.FeedsGroupListExpand.key]) {
true -> ON true -> ON
false -> OFF false -> OFF
else -> default 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) { when (value) {
true -> ArticleListDatePreference.OFF true -> FeedsGroupListExpandPreference.OFF
false -> ArticleListDatePreference.ON false -> FeedsGroupListExpandPreference.ON
} }

View File

@ -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<FeedsGroupListTonalElevationPreference>
get() = this.dataStore.data.map {
when (it[DataStoreKeys.FeedsGroupListTonalElevation.key]) {
0 -> Level0
1 -> Level1
3 -> Level2
6 -> Level3
8 -> Level4
12 -> Level5
else -> default
}
}
}
}

View File

@ -10,18 +10,18 @@ import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put import me.ash.reader.ui.ext.put
sealed class ArticleListTonalElevationPreference(val value: Int) : Preference() { sealed class FeedsTopBarTonalElevationPreference(val value: Int) : Preference() {
object Level0 : ArticleListTonalElevationPreference(0) object Level0 : FeedsTopBarTonalElevationPreference(0)
object Level1 : ArticleListTonalElevationPreference(1) object Level1 : FeedsTopBarTonalElevationPreference(1)
object Level2 : ArticleListTonalElevationPreference(3) object Level2 : FeedsTopBarTonalElevationPreference(3)
object Level3 : ArticleListTonalElevationPreference(6) object Level3 : FeedsTopBarTonalElevationPreference(6)
object Level4 : ArticleListTonalElevationPreference(8) object Level4 : FeedsTopBarTonalElevationPreference(8)
object Level5 : ArticleListTonalElevationPreference(12) object Level5 : FeedsTopBarTonalElevationPreference(12)
override fun put(context: Context, scope: CoroutineScope) { override fun put(context: Context, scope: CoroutineScope) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
context.dataStore.put( context.dataStore.put(
DataStoreKeys.ArticleListTonalElevation, DataStoreKeys.FeedsTopBarTonalElevation,
value value
) )
} }
@ -41,9 +41,9 @@ sealed class ArticleListTonalElevationPreference(val value: Int) : Preference()
val default = Level0 val default = Level0
val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5)
val Context.articleListTonalElevation: Flow<ArticleListTonalElevationPreference> val Context.feedsTopBarTonalElevation: Flow<FeedsTopBarTonalElevationPreference>
get() = this.dataStore.data.map { get() = this.dataStore.data.map {
when (it[DataStoreKeys.ArticleListTonalElevation.key]) { when (it[DataStoreKeys.FeedsTopBarTonalElevation.key]) {
0 -> Level0 0 -> Level0
1 -> Level1 1 -> Level1
3 -> Level2 3 -> Level2

View File

@ -10,14 +10,14 @@ import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put import me.ash.reader.ui.ext.put
sealed class ArticleListFeedNamePreference(val value: Boolean) : Preference() { sealed class FlowArticleListDatePreference(val value: Boolean) : Preference() {
object ON : ArticleListFeedNamePreference(true) object ON : FlowArticleListDatePreference(true)
object OFF : ArticleListFeedNamePreference(false) object OFF : FlowArticleListDatePreference(false)
override fun put(context: Context, scope: CoroutineScope) { override fun put(context: Context, scope: CoroutineScope) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
context.dataStore.put( context.dataStore.put(
DataStoreKeys.ArticleListFeedName, DataStoreKeys.FlowArticleListDate,
value value
) )
} }
@ -27,9 +27,9 @@ sealed class ArticleListFeedNamePreference(val value: Boolean) : Preference() {
val default = ON val default = ON
val values = listOf(ON, OFF) val values = listOf(ON, OFF)
val Context.articleListFeedName: Flow<ArticleListFeedNamePreference> val Context.flowArticleListDate: Flow<FlowArticleListDatePreference>
get() = this.dataStore.data.map { get() = this.dataStore.data.map {
when (it[DataStoreKeys.ArticleListFeedName.key]) { when (it[DataStoreKeys.FlowArticleListDate.key]) {
true -> ON true -> ON
false -> OFF false -> OFF
else -> default 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) { when (value) {
true -> ArticleListFeedNamePreference.OFF true -> FlowArticleListDatePreference.OFF
false -> ArticleListFeedNamePreference.ON false -> FlowArticleListDatePreference.ON
} }

View File

@ -10,14 +10,14 @@ import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put import me.ash.reader.ui.ext.put
sealed class ArticleListFeedIconPreference(val value: Boolean) : Preference() { sealed class FlowArticleListDescPreference(val value: Boolean) : Preference() {
object ON : ArticleListFeedIconPreference(true) object ON : FlowArticleListDescPreference(true)
object OFF : ArticleListFeedIconPreference(false) object OFF : FlowArticleListDescPreference(false)
override fun put(context: Context, scope: CoroutineScope) { override fun put(context: Context, scope: CoroutineScope) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
context.dataStore.put( context.dataStore.put(
DataStoreKeys.ArticleListFeedIcon, DataStoreKeys.FlowArticleListDesc,
value value
) )
} }
@ -27,9 +27,9 @@ sealed class ArticleListFeedIconPreference(val value: Boolean) : Preference() {
val default = ON val default = ON
val values = listOf(ON, OFF) val values = listOf(ON, OFF)
val Context.articleListFeedIcon: Flow<ArticleListFeedIconPreference> val Context.flowArticleListDesc: Flow<FlowArticleListDescPreference>
get() = this.dataStore.data.map { get() = this.dataStore.data.map {
when (it[DataStoreKeys.ArticleListFeedIcon.key]) { when (it[DataStoreKeys.FlowArticleListDesc.key]) {
true -> ON true -> ON
false -> OFF false -> OFF
else -> default 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) { when (value) {
true -> ArticleListFeedIconPreference.OFF true -> FlowArticleListDescPreference.OFF
false -> ArticleListFeedIconPreference.ON false -> FlowArticleListDescPreference.ON
} }

View File

@ -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<FlowArticleListFeedIconPreference>
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
}

View File

@ -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<FlowArticleListFeedNamePreference>
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
}

View File

@ -10,14 +10,14 @@ import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put import me.ash.reader.ui.ext.put
sealed class ArticleListDescPreference(val value: Boolean) : Preference() { sealed class FlowArticleListImagePreference(val value: Boolean) : Preference() {
object ON : ArticleListDescPreference(true) object ON : FlowArticleListImagePreference(true)
object OFF : ArticleListDescPreference(false) object OFF : FlowArticleListImagePreference(false)
override fun put(context: Context, scope: CoroutineScope) { override fun put(context: Context, scope: CoroutineScope) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
context.dataStore.put( context.dataStore.put(
DataStoreKeys.ArticleListDesc, DataStoreKeys.FlowArticleListImage,
value value
) )
} }
@ -27,9 +27,9 @@ sealed class ArticleListDescPreference(val value: Boolean) : Preference() {
val default = ON val default = ON
val values = listOf(ON, OFF) val values = listOf(ON, OFF)
val Context.articleListDesc: Flow<ArticleListDescPreference> val Context.flowArticleListImage: Flow<FlowArticleListImagePreference>
get() = this.dataStore.data.map { get() = this.dataStore.data.map {
when (it[DataStoreKeys.ArticleListDesc.key]) { when (it[DataStoreKeys.FlowArticleListImage.key]) {
true -> ON true -> ON
false -> OFF false -> OFF
else -> default 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) { when (value) {
true -> ArticleListDescPreference.OFF true -> FlowArticleListImagePreference.OFF
false -> ArticleListDescPreference.ON false -> FlowArticleListImagePreference.ON
} }

View File

@ -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<FlowArticleListTonalElevationPreference>
get() = this.dataStore.data.map {
when (it[DataStoreKeys.FlowArticleListTonalElevation.key]) {
0 -> Level0
1 -> Level1
3 -> Level2
6 -> Level3
8 -> Level4
12 -> Level5
else -> default
}
}
}
}

View File

@ -10,14 +10,14 @@ import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put import me.ash.reader.ui.ext.put
sealed class FilterBarFilledPreference(val value: Boolean) : Preference() { sealed class FlowFilterBarFilledPreference(val value: Boolean) : Preference() {
object ON : FilterBarFilledPreference(true) object ON : FlowFilterBarFilledPreference(true)
object OFF : FilterBarFilledPreference(false) object OFF : FlowFilterBarFilledPreference(false)
override fun put(context: Context, scope: CoroutineScope) { override fun put(context: Context, scope: CoroutineScope) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
context.dataStore.put( context.dataStore.put(
DataStoreKeys.FilterBarFilled, DataStoreKeys.FlowFilterBarFilled,
value value
) )
} }
@ -27,9 +27,9 @@ sealed class FilterBarFilledPreference(val value: Boolean) : Preference() {
val default = OFF val default = OFF
val values = listOf(ON, OFF) val values = listOf(ON, OFF)
val Context.filterBarFilled: Flow<FilterBarFilledPreference> val Context.flowFilterBarFilled: Flow<FlowFilterBarFilledPreference>
get() = this.dataStore.data.map { get() = this.dataStore.data.map {
when (it[DataStoreKeys.FilterBarFilled.key]) { when (it[DataStoreKeys.FlowFilterBarFilled.key]) {
true -> ON true -> ON
false -> OFF false -> OFF
else -> default 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) { when (value) {
true -> FilterBarFilledPreference.OFF true -> FlowFilterBarFilledPreference.OFF
false -> FilterBarFilledPreference.ON false -> FlowFilterBarFilledPreference.ON
} }

View File

@ -1,7 +1,6 @@
package me.ash.reader.data.preference package me.ash.reader.data.preference
import android.content.Context import android.content.Context
import android.util.Log
import androidx.compose.runtime.Immutable import androidx.compose.runtime.Immutable
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -13,17 +12,17 @@ import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put import me.ash.reader.ui.ext.put
@Immutable @Immutable
object FilterBarPaddingPreference { object FlowFilterBarPaddingPreference {
const val default = 0 const val default = 0
val Context.filterBarPadding: Flow<Int> val Context.flowFilterBarPadding: Flow<Int>
get() = this.dataStore.data.map { get() = this.dataStore.data.map {
it[DataStoreKeys.FilterBarPadding.key] ?: 0 it[DataStoreKeys.FlowFilterBarPadding.key] ?: default
} }
fun put(context: Context, scope: CoroutineScope, value: Int) { fun put(context: Context, scope: CoroutineScope, value: Int) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
context.dataStore.put(DataStoreKeys.FilterBarPadding, value) context.dataStore.put(DataStoreKeys.FlowFilterBarPadding, value)
} }
} }
} }

View File

@ -6,19 +6,20 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.ash.reader.R
import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put import me.ash.reader.ui.ext.put
sealed class FilterBarStylePreference(val value: Int) : Preference() { sealed class FlowFilterBarStylePreference(val value: Int) : Preference() {
object Icon : FilterBarStylePreference(0) object Icon : FlowFilterBarStylePreference(0)
object IconLabel : FilterBarStylePreference(1) object IconLabel : FlowFilterBarStylePreference(1)
object IconLabelOnlySelected : FilterBarStylePreference(2) object IconLabelOnlySelected : FlowFilterBarStylePreference(2)
override fun put(context: Context, scope: CoroutineScope) { override fun put(context: Context, scope: CoroutineScope) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
context.dataStore.put( context.dataStore.put(
DataStoreKeys.FilterBarStyle, DataStoreKeys.FlowFilterBarStyle,
value value
) )
} }
@ -26,18 +27,18 @@ sealed class FilterBarStylePreference(val value: Int) : Preference() {
fun getDesc(context: Context): String = fun getDesc(context: Context): String =
when (this) { when (this) {
Icon -> "图标" Icon -> context.getString(R.string.icons)
IconLabel -> "图标 + 标签" IconLabel -> context.getString(R.string.icons_and_labels)
IconLabelOnlySelected -> "图标 + 标签(仅选中时)" IconLabelOnlySelected -> context.getString(R.string.icons_and_label_only_selected)
} }
companion object { companion object {
val default = Icon val default = Icon
val values = listOf(Icon, IconLabel, IconLabelOnlySelected) val values = listOf(Icon, IconLabel, IconLabelOnlySelected)
val Context.filterBarStyle: Flow<FilterBarStylePreference> val Context.flowFilterBarStyle: Flow<FlowFilterBarStylePreference>
get() = this.dataStore.data.map { get() = this.dataStore.data.map {
when (it[DataStoreKeys.FilterBarStyle.key]) { when (it[DataStoreKeys.FlowFilterBarStyle.key]) {
0 -> Icon 0 -> Icon
1 -> IconLabel 1 -> IconLabel
2 -> IconLabelOnlySelected 2 -> IconLabelOnlySelected

View File

@ -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<FlowFilterBarTonalElevationPreference>
get() = this.dataStore.data.map {
when (it[DataStoreKeys.FlowFilterBarTonalElevation.key]) {
0 -> Level0
1 -> Level1
3 -> Level2
6 -> Level3
8 -> Level4
12 -> Level5
else -> default
}
}
}
}

View File

@ -10,18 +10,18 @@ import me.ash.reader.ui.ext.DataStoreKeys
import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put import me.ash.reader.ui.ext.put
sealed class FilterBarTonalElevationPreference(val value: Int) : Preference() { sealed class FlowTopBarTonalElevationPreference(val value: Int) : Preference() {
object Level0 : FilterBarTonalElevationPreference(0) object Level0 : FlowTopBarTonalElevationPreference(0)
object Level1 : FilterBarTonalElevationPreference(1) object Level1 : FlowTopBarTonalElevationPreference(1)
object Level2 : FilterBarTonalElevationPreference(3) object Level2 : FlowTopBarTonalElevationPreference(3)
object Level3 : FilterBarTonalElevationPreference(6) object Level3 : FlowTopBarTonalElevationPreference(6)
object Level4 : FilterBarTonalElevationPreference(8) object Level4 : FlowTopBarTonalElevationPreference(8)
object Level5 : FilterBarTonalElevationPreference(12) object Level5 : FlowTopBarTonalElevationPreference(12)
override fun put(context: Context, scope: CoroutineScope) { override fun put(context: Context, scope: CoroutineScope) {
scope.launch(Dispatchers.IO) { scope.launch(Dispatchers.IO) {
context.dataStore.put( context.dataStore.put(
DataStoreKeys.FilterBarTonalElevation, DataStoreKeys.FlowTopBarTonalElevation,
value value
) )
} }
@ -41,9 +41,9 @@ sealed class FilterBarTonalElevationPreference(val value: Int) : Preference() {
val default = Level0 val default = Level0
val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5) val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5)
val Context.filterBarTonalElevation: Flow<FilterBarTonalElevationPreference> val Context.flowTopBarTonalElevation: Flow<FlowTopBarTonalElevationPreference>
get() = this.dataStore.data.map { get() = this.dataStore.data.map {
when (it[DataStoreKeys.FilterBarTonalElevation.key]) { when (it[DataStoreKeys.FlowTopBarTonalElevation.key]) {
0 -> Level0 0 -> Level0
1 -> Level1 1 -> Level1
3 -> Level2 3 -> Level2

View File

@ -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<Int>
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)
}
}
}

View File

@ -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,
)
}
}

View File

@ -9,8 +9,16 @@ import kotlin.math.ln
fun ColorScheme.surfaceColorAtElevation( fun ColorScheme.surfaceColorAtElevation(
elevation: Dp, elevation: Dp,
color: Color = surface,
): Color = color.atElevation(surfaceTint, elevation)
fun Color.atElevation(
sourceColor: Color,
elevation: Dp,
): Color { ): Color {
if (elevation == 0.dp) return surface if (elevation == 0.dp) return this
val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f return sourceColor.copy(alpha = elevation.alphaLN(constant = 4.5f)).compositeOver(this)
return primary.copy(alpha = alpha).compositeOver(surface)
} }
fun Dp.alphaLN(constant: Float = 1f, weight: Float = 0f): Float =
((constant * ln(value + 1) + weight) + 2f) / 100f

View File

@ -31,8 +31,6 @@ val Context.currentAccountId: Int
get() = this.dataStore.get(DataStoreKeys.CurrentAccountId)!! get() = this.dataStore.get(DataStoreKeys.CurrentAccountId)!!
val Context.currentAccountType: Int val Context.currentAccountType: Int
get() = this.dataStore.get(DataStoreKeys.CurrentAccountType)!! get() = this.dataStore.get(DataStoreKeys.CurrentAccountType)!!
val Context.themeIndex: Int
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) ?: ""
@ -130,54 +128,94 @@ sealed class DataStoreKeys<T> {
get() = stringPreferencesKey("customPrimaryColor") get() = stringPreferencesKey("customPrimaryColor")
} }
object FilterBarStyle : DataStoreKeys<Int>() { object FeedsFilterBarStyle : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int> override val key: Preferences.Key<Int>
get() = intPreferencesKey("filterBarStyle") get() = intPreferencesKey("feedsFilterBarStyle")
} }
object FilterBarFilled : DataStoreKeys<Boolean>() { object FeedsFilterBarFilled : DataStoreKeys<Boolean>() {
override val key: Preferences.Key<Boolean> override val key: Preferences.Key<Boolean>
get() = booleanPreferencesKey("filterBarFilled") get() = booleanPreferencesKey("feedsFilterBarFilled")
} }
object FilterBarPadding : DataStoreKeys<Int>() { object FeedsFilterBarPadding : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int> override val key: Preferences.Key<Int>
get() = intPreferencesKey("filterBarPadding") get() = intPreferencesKey("feedsFilterBarPadding")
} }
object FilterBarTonalElevation : DataStoreKeys<Int>() { object FeedsFilterBarTonalElevation : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int> override val key: Preferences.Key<Int>
get() = intPreferencesKey("filterBarTonalElevation") get() = intPreferencesKey("feedsFilterBarTonalElevation")
} }
object ArticleListFeedIcon : DataStoreKeys<Boolean>() { object FeedsTopBarTonalElevation : DataStoreKeys<Int>() {
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> override val key: Preferences.Key<Int>
get() = intPreferencesKey("articleListTonalElevation") get() = intPreferencesKey("feedsTopBarTonalElevation")
}
object FeedsGroupListExpand : DataStoreKeys<Boolean>() {
override val key: Preferences.Key<Boolean>
get() = booleanPreferencesKey("feedsGroupListExpand")
}
object FeedsGroupListTonalElevation : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int>
get() = intPreferencesKey("feedsGroupListTonalElevation")
}
object FlowFilterBarStyle : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int>
get() = intPreferencesKey("flowFilterBarStyle")
}
object FlowFilterBarFilled : DataStoreKeys<Boolean>() {
override val key: Preferences.Key<Boolean>
get() = booleanPreferencesKey("flowFilterBarFilled")
}
object FlowFilterBarPadding : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int>
get() = intPreferencesKey("flowFilterBarPadding")
}
object FlowFilterBarTonalElevation : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int>
get() = intPreferencesKey("flowFilterBarTonalElevation")
}
object FlowTopBarTonalElevation : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int>
get() = intPreferencesKey("flowTopBarTonalElevation")
}
object FlowArticleListFeedIcon : DataStoreKeys<Boolean>() {
override val key: Preferences.Key<Boolean>
get() = booleanPreferencesKey("flowArticleListFeedIcon")
}
object FlowArticleListFeedName : DataStoreKeys<Boolean>() {
override val key: Preferences.Key<Boolean>
get() = booleanPreferencesKey("flowArticleListFeedName")
}
object FlowArticleListImage : DataStoreKeys<Boolean>() {
override val key: Preferences.Key<Boolean>
get() = booleanPreferencesKey("flowArticleListImage")
}
object FlowArticleListDesc : DataStoreKeys<Boolean>() {
override val key: Preferences.Key<Boolean>
get() = booleanPreferencesKey("flowArticleListDesc")
}
object FlowArticleListDate : DataStoreKeys<Boolean>() {
override val key: Preferences.Key<Boolean>
get() = booleanPreferencesKey("flowArticleListDate")
}
object FlowArticleListTonalElevation : DataStoreKeys<Int>() {
override val key: Preferences.Key<Int>
get() = intPreferencesKey("flowArticleListTonalElevation")
} }
object InitialPage : DataStoreKeys<Int>() { object InitialPage : DataStoreKeys<Int>() {

View File

@ -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.feeds.FeedsPageStyle
import me.ash.reader.ui.page.settings.color.flow.FlowPageStyle 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
@ -127,6 +128,9 @@ fun HomeEntry(
animatedComposable(route = RouteName.COLOR_AND_STYLE) { animatedComposable(route = RouteName.COLOR_AND_STYLE) {
ColorAndStyle(navController) ColorAndStyle(navController)
} }
animatedComposable(route = RouteName.FEEDS_PAGE_STYLE) {
FeedsPageStyle(navController)
}
animatedComposable(route = RouteName.FLOW_PAGE_STYLE) { animatedComposable(route = RouteName.FLOW_PAGE_STYLE) {
FlowPageStyle(navController) FlowPageStyle(navController)
} }

View File

@ -14,6 +14,7 @@ object RouteName {
// Color & Style // Color & Style
const val COLOR_AND_STYLE = "color_and_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" const val FLOW_PAGE_STYLE = "flow_page_style"
// Interaction // Interaction

View File

@ -6,20 +6,11 @@ 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 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.FlowFilterBarStylePreference
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 import me.ash.reader.ui.theme.palette.onDark
@ -28,23 +19,18 @@ import me.ash.reader.ui.theme.palette.onDark
fun FilterBar( fun FilterBar(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
filter: Filter, filter: Filter,
filterBarStyle: Int,
filterBarFilled: Boolean,
filterBarPadding: Dp,
filterBarTonalElevation: Dp,
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)
NavigationBar( NavigationBar(
tonalElevation = filterBarTonalElevation.value.dp, tonalElevation = filterBarTonalElevation,
) { ) {
Spacer(modifier = Modifier.width(filterBarPadding.dp)) Spacer(modifier = Modifier.width(filterBarPadding))
listOf( listOf(
Filter.Starred, Filter.Starred,
Filter.Unread, Filter.Unread,
@ -53,13 +39,14 @@ fun FilterBar(
NavigationBarItem( NavigationBarItem(
// modifier = Modifier.height(60.dp), // modifier = Modifier.height(60.dp),
alwaysShowLabel = when (filterBarStyle) { alwaysShowLabel = when (filterBarStyle) {
is FilterBarStylePreference.Icon -> false FlowFilterBarStylePreference.Icon.value -> false
is FilterBarStylePreference.IconLabel -> true FlowFilterBarStylePreference.IconLabel.value -> true
is FilterBarStylePreference.IconLabelOnlySelected -> false FlowFilterBarStylePreference.IconLabelOnlySelected.value -> false
else -> false
}, },
icon = { icon = {
Icon( Icon(
imageVector = if (filter == item && filterBarFilled.value) { imageVector = if (filter == item && filterBarFilled) {
item.iconFilled item.iconFilled
} else { } else {
item.iconOutline item.iconOutline
@ -67,7 +54,7 @@ fun FilterBar(
contentDescription = item.getName() contentDescription = item.getName()
) )
}, },
label = if (filterBarStyle is FilterBarStylePreference.Icon) { label = if (filterBarStyle == FlowFilterBarStylePreference.Icon.value) {
null null
} else { } else {
{ {
@ -92,6 +79,6 @@ fun FilterBar(
) )
) )
} }
Spacer(modifier = Modifier.width(filterBarPadding.dp)) Spacer(modifier = Modifier.width(filterBarPadding))
} }
} }

View File

@ -62,7 +62,7 @@ class HomeViewModel @Inject constructor(
private fun fetchArticles() { private fun fetchArticles() {
_viewState.update { _viewState.update {
it.copy( it.copy(
pagingData = Pager(PagingConfig(pageSize = 10)) { pagingData = Pager(PagingConfig(pageSize = 15)) {
if (_viewState.value.searchContent.isNotBlank()) { if (_viewState.value.searchContent.isNotBlank()) {
rssRepository.get().searchArticles( rssRepository.get().searchArticles(
content = _viewState.value.searchContent.trim(), content = _viewState.value.searchContent.trim(),

View File

@ -16,11 +16,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import me.ash.reader.data.entity.Feed 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.FeedOptionViewAction
import me.ash.reader.ui.page.home.feeds.option.feed.FeedOptionViewModel import me.ash.reader.ui.page.home.feeds.option.feed.FeedOptionViewModel
import kotlin.math.ln
@OptIn( @OptIn(
androidx.compose.foundation.ExperimentalFoundationApi::class, androidx.compose.foundation.ExperimentalFoundationApi::class,
@ -31,6 +33,7 @@ fun FeedItem(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
feed: Feed, feed: Feed,
feedOptionViewModel: FeedOptionViewModel = hiltViewModel(), feedOptionViewModel: FeedOptionViewModel = hiltViewModel(),
tonalElevation: Dp,
onClick: () -> Unit = {}, onClick: () -> Unit = {},
) { ) {
val view = LocalView.current val view = LocalView.current
@ -76,9 +79,10 @@ fun FeedItem(
) )
} }
if (feed.important ?: 0 != 0) { if (feed.important ?: 0 != 0) {
Row() {
Badge( Badge(
containerColor = MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.24f), containerColor = MaterialTheme.colorScheme.surfaceTint.copy(
alpha = (ln(tonalElevation.value + 1.4f) + 2f) / 100f
),
contentColor = MaterialTheme.colorScheme.outline, contentColor = MaterialTheme.colorScheme.outline,
content = { content = {
Text( Text(
@ -90,5 +94,4 @@ fun FeedItem(
} }
} }
} }
}
} }

View File

@ -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.SubscribeDialog
import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeViewAction 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.page.home.feeds.subscribe.SubscribeViewModel
import me.ash.reader.ui.theme.*
import me.ash.reader.ui.theme.palette.onDark
@SuppressLint("FlowOperatorInvokedInComposition") @SuppressLint("FlowOperatorInvokedInComposition")
@OptIn( @OptIn(
@ -59,6 +61,14 @@ fun FeedsPage(
homeViewModel: HomeViewModel, homeViewModel: HomeViewModel,
) { ) {
val context = LocalContext.current 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 feedsViewState = feedsViewModel.viewState.collectAsStateValue()
val filterState = homeViewModel.filterState.collectAsStateValue() val filterState = homeViewModel.filterState.collectAsStateValue()
@ -117,11 +127,19 @@ fun FeedsPage(
Scaffold( Scaffold(
modifier = Modifier modifier = Modifier
.background(MaterialTheme.colorScheme.surface) .background(MaterialTheme.colorScheme.surfaceColorAtElevation(topBarTonalElevation.dp))
.statusBarsPadding() .statusBarsPadding()
.navigationBarsPadding(), .navigationBarsPadding(),
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
groupListTonalElevation.dp
) onDark MaterialTheme.colorScheme.surface,
topBar = { topBar = {
SmallTopAppBar( SmallTopAppBar(
colors = TopAppBarDefaults.smallTopAppBarColors(
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
topBarTonalElevation.dp
),
),
title = {}, title = {},
navigationIcon = { navigationIcon = {
FeedbackIconButton( FeedbackIconButton(
@ -204,6 +222,8 @@ fun FeedsPage(
// Crossfade(targetState = groupWithFeed) { groupWithFeed -> // Crossfade(targetState = groupWithFeed) { groupWithFeed ->
Column { Column {
GroupItem( GroupItem(
isExpanded = groupListExpand,
tonalElevation = groupListTonalElevation.dp,
group = groupWithFeed.group, group = groupWithFeed.group,
feeds = groupWithFeed.feeds, feeds = groupWithFeed.feeds,
groupOnClick = { groupOnClick = {
@ -242,15 +262,18 @@ fun FeedsPage(
bottomBar = { bottomBar = {
FilterBar( FilterBar(
filter = filterState.filter, filter = filterState.filter,
filterOnClick = { filterBarStyle = filterBarStyle,
filterBarFilled = filterBarFilled,
filterBarPadding = filterBarPadding.dp,
filterBarTonalElevation = filterBarTonalElevation.dp,
) {
filterChange( filterChange(
navController = navController, navController = navController,
homeViewModel = homeViewModel, homeViewModel = homeViewModel,
filterState = filterState.copy(filter = it), filterState = filterState.copy(filter = it),
isNavigate = false, isNavigate = false,
) )
}, }
)
} }
) )

View File

@ -22,11 +22,13 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.data.entity.Feed import me.ash.reader.data.entity.Feed
import me.ash.reader.data.entity.Group 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.GroupOptionViewAction
import me.ash.reader.ui.page.home.feeds.option.group.GroupOptionViewModel 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 @Composable
fun GroupItem( fun GroupItem(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
tonalElevation: Dp,
group: Group, group: Group,
feeds: List<Feed>, feeds: List<Feed>,
isExpanded: Boolean = true, isExpanded: Boolean = true,
@ -50,7 +53,9 @@ fun GroupItem(
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
.clip(RoundedCornerShape(32.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( .combinedClickable(
onClick = { onClick = {
groupOnClick() groupOnClick()
@ -82,7 +87,11 @@ fun GroupItem(
.padding(end = 20.dp) .padding(end = 20.dp)
.size(24.dp) .size(24.dp)
.clip(CircleShape) .clip(CircleShape)
.background(MaterialTheme.colorScheme.secondaryContainer.copy(alpha = 0.24f)) .background(
MaterialTheme.colorScheme.surfaceTint.copy(
alpha = tonalElevation.alphaLN(weight = 1.4f)
)
)
.clickable { .clickable {
expanded = !expanded expanded = !expanded
}, },
@ -107,6 +116,7 @@ fun GroupItem(
FeedItem( FeedItem(
modifier = Modifier.padding(horizontal = 20.dp), modifier = Modifier.padding(horizontal = 20.dp),
feed = feed, feed = feed,
tonalElevation = tonalElevation,
) { ) {
feedOnClick(feed) feedOnClick(feed)
} }

View File

@ -21,14 +21,8 @@ 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
import me.ash.reader.ui.theme.*
@Composable @Composable
fun ArticleItem( fun ArticleItem(
@ -37,16 +31,11 @@ fun ArticleItem(
onClick: (ArticleWithFeed) -> Unit = {}, onClick: (ArticleWithFeed) -> Unit = {},
) { ) {
val context = LocalContext.current val context = LocalContext.current
val articleListFeedIcon = val articleListFeedIcon = LocalFlowArticleListFeedIcon.current
context.articleListFeedIcon.collectAsStateValue(initial = ArticleListFeedIconPreference.default) val articleListFeedName = LocalFlowArticleListFeedName.current
val articleListFeedName = val articleListImage = LocalFlowArticleListImage.current
context.articleListFeedName.collectAsStateValue(initial = ArticleListFeedNamePreference.default) val articleListDesc = LocalFlowArticleListDesc.current
val articleListImage = val articleListDate = LocalFlowArticleListDate.current
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
@ -62,11 +51,11 @@ fun ArticleItem(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
// Feed name // Feed name
if (articleListFeedName.value) { if (articleListFeedName) {
Text( Text(
modifier = Modifier modifier = Modifier
.weight(1f) .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, text = articleWithFeed.feed.name,
color = MaterialTheme.colorScheme.tertiary, color = MaterialTheme.colorScheme.tertiary,
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium,
@ -75,11 +64,13 @@ fun ArticleItem(
) )
} }
if (articleListDate.value) { if (articleListDate) {
Row( Row(
modifier = Modifier.padding(start = 6.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
if (!articleListFeedName) {
Spacer(Modifier.width(if (articleListFeedIcon) 30.dp else 0.dp))
}
// Starred // Starred
if (articleWithFeed.article.isStarred) { if (articleWithFeed.article.isStarred) {
Icon( Icon(
@ -108,7 +99,7 @@ fun ArticleItem(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) { ) {
// Feed icon // Feed icon
if (articleListFeedIcon.value) { if (articleListFeedIcon) {
Row( Row(
modifier = Modifier modifier = Modifier
.size(20.dp) .size(20.dp)
@ -126,11 +117,11 @@ fun ArticleItem(
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 = if (articleListDesc.value) 2 else 4, maxLines = if (articleListDesc) 2 else 4,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
) )
// Description // Description
if (articleListDesc.value) { if (articleListDesc) {
Text( Text(
text = articleWithFeed.article.shortDescription, text = articleWithFeed.article.shortDescription,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f), color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.7f),

View File

@ -27,10 +27,6 @@ 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
@ -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.FilterState
import me.ash.reader.ui.page.home.HomeViewAction import me.ash.reader.ui.page.home.HomeViewAction
import me.ash.reader.ui.page.home.HomeViewModel import me.ash.reader.ui.page.home.HomeViewModel
import me.ash.reader.ui.theme.*
import me.ash.reader.ui.theme.palette.onDark
@OptIn( @OptIn(
ExperimentalMaterial3Api::class, ExperimentalMaterial3Api::class,
@ -59,6 +57,13 @@ fun FlowPage(
) { ) {
val context = LocalContext.current val context = LocalContext.current
val keyboardController = LocalSoftwareKeyboardController.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 scope = rememberCoroutineScope()
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
@ -70,11 +75,6 @@ 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) {
@ -109,16 +109,18 @@ fun FlowPage(
Scaffold( Scaffold(
modifier = Modifier modifier = Modifier
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp)) .background(MaterialTheme.colorScheme.surfaceColorAtElevation(topBarTonalElevation.dp))
.statusBarsPadding() .statusBarsPadding()
.navigationBarsPadding(), .navigationBarsPadding(),
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp), containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
articleListTonalElevation.dp
) onDark MaterialTheme.colorScheme.surface,
topBar = { topBar = {
SmallTopAppBar( SmallTopAppBar(
title = {}, title = {},
colors = TopAppBarDefaults.smallTopAppBarColors( colors = TopAppBarDefaults.smallTopAppBarColors(
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation( containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
articleListTonalElevation.value.dp topBarTonalElevation.dp
), ),
), ),
navigationIcon = { navigationIcon = {
@ -197,7 +199,7 @@ fun FlowPage(
state = listState, state = listState,
) { ) {
item { item {
DisplayTextHeader(filterState, isSyncing, articleListFeedIcon.value) DisplayTextHeader(filterState, isSyncing, articleListFeedIcon)
AnimatedVisibility( AnimatedVisibility(
visible = markAsRead, visible = markAsRead,
enter = fadeIn() + expandVertically(), enter = fadeIn() + expandVertically(),
@ -259,8 +261,8 @@ fun FlowPage(
} }
ArticleList( ArticleList(
pagingItems = pagingItems, pagingItems = pagingItems,
articleListFeedIcon = articleListFeedIcon.value, articleListFeedIcon = articleListFeedIcon,
articleListTonalElevation = articleListTonalElevation.value, articleListTonalElevation = articleListTonalElevation,
) { ) {
onSearch = false onSearch = false
navController.navigate("${RouteName.READING}/${it.article.id}") { navController.navigate("${RouteName.READING}/${it.article.id}") {
@ -279,12 +281,15 @@ fun FlowPage(
bottomBar = { bottomBar = {
FilterBar( FilterBar(
filter = filterState.filter, filter = filterState.filter,
filterOnClick = { filterBarStyle = filterBarStyle,
filterBarFilled = filterBarFilled,
filterBarPadding = filterBarPadding.dp,
filterBarTonalElevation = filterBarTonalElevation.dp,
) {
flowViewModel.dispatch(FlowViewAction.ScrollToItem(0)) flowViewModel.dispatch(FlowViewAction.ScrollToItem(0))
homeViewModel.dispatch(HomeViewAction.ChangeFilter(filterState.copy(filter = it))) homeViewModel.dispatch(HomeViewAction.ChangeFilter(filterState.copy(filter = it)))
homeViewModel.dispatch(HomeViewAction.FetchArticles) homeViewModel.dispatch(HomeViewAction.FetchArticles)
}, }
)
} }
) )
} }

View File

@ -11,6 +11,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import me.ash.reader.ui.ext.surfaceColorAtElevation import me.ash.reader.ui.ext.surfaceColorAtElevation
import me.ash.reader.ui.theme.palette.onDark
@Composable @Composable
fun StickyHeader( fun StickyHeader(
@ -21,12 +22,17 @@ fun StickyHeader(
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.dp)), .background(
MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.dp)
onDark MaterialTheme.colorScheme.surface
),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
Text( Text(
modifier = Modifier modifier = Modifier.padding(
.padding(start = if (articleListFeedIcon) 54.dp else 24.dp, bottom = 4.dp), 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,

View File

@ -28,12 +28,17 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.data.preference.ThemePreference
import me.ash.reader.ui.component.* 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.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
import me.ash.reader.ui.theme.LocalTheme
import me.ash.reader.ui.theme.LocalUseDarkTheme import me.ash.reader.ui.theme.LocalUseDarkTheme
import me.ash.reader.ui.theme.palette.* import me.ash.reader.ui.theme.palette.*
import me.ash.reader.ui.theme.palette.TonalPalettes.Companion.toTonalPalettes import me.ash.reader.ui.theme.palette.TonalPalettes.Companion.toTonalPalettes
@ -47,8 +52,9 @@ fun ColorAndStyle(
) { ) {
val context = LocalContext.current val context = LocalContext.current
val useDarkTheme = LocalUseDarkTheme.current val useDarkTheme = LocalUseDarkTheme.current
val theme = LocalTheme.current
val wallpaperTonalPalettes = extractTonalPalettesFromUserWallpaper() 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( Scaffold(
modifier = Modifier modifier = Modifier
@ -163,8 +169,11 @@ fun ColorAndStyle(
) )
SettingItem( SettingItem(
title = stringResource(R.string.feeds_page), title = stringResource(R.string.feeds_page),
enable = false, onClick = {
onClick = {}, navController.navigate(RouteName.FEEDS_PAGE_STYLE) {
launchSingleTop = true
}
},
) {} ) {}
SettingItem( SettingItem(
title = stringResource(R.string.flow_page), title = stringResource(R.string.flow_page),
@ -245,12 +254,7 @@ fun Palettes(
if (isCustom) { if (isCustom) {
addDialogVisible = true addDialogVisible = true
} else { } else {
scope.launch(Dispatchers.IO) { ThemePreference.put(context, scope, themeIndexPrefix + index)
context.dataStore.put(
DataStoreKeys.ThemeIndex,
themeIndexPrefix + index
)
}
} }
}, },
palette = if (isCustom) tonalPalettes else palette palette = if (isCustom) tonalPalettes else palette

View File

@ -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
}
}
}

View File

@ -8,6 +8,8 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowBack 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.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -15,6 +17,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import me.ash.reader.R 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.Feed
import me.ash.reader.data.entity.Filter import me.ash.reader.data.entity.Filter
import me.ash.reader.data.preference.* import me.ash.reader.data.preference.*
import me.ash.reader.data.preference.ArticleListDatePreference.Companion.articleListDate import me.ash.reader.data.preference.FlowArticleListDatePreference.Companion.flowArticleListDate
import me.ash.reader.data.preference.ArticleListDescPreference.Companion.articleListDesc import me.ash.reader.data.preference.FlowArticleListDescPreference.Companion.flowArticleListDesc
import me.ash.reader.data.preference.ArticleListFeedIconPreference.Companion.articleListFeedIcon import me.ash.reader.data.preference.FlowArticleListFeedIconPreference.Companion.flowArticleListFeedIcon
import me.ash.reader.data.preference.ArticleListFeedNamePreference.Companion.articleListFeedName import me.ash.reader.data.preference.FlowArticleListFeedNamePreference.Companion.flowArticleListFeedName
import me.ash.reader.data.preference.ArticleListImagePreference.Companion.articleListImage import me.ash.reader.data.preference.FlowArticleListImagePreference.Companion.flowArticleListImage
import me.ash.reader.data.preference.ArticleListTonalElevationPreference.Companion.articleListTonalElevation import me.ash.reader.data.preference.FlowArticleListTonalElevationPreference.Companion.flowArticleListTonalElevation
import me.ash.reader.data.preference.FilterBarFilledPreference.Companion.filterBarFilled import me.ash.reader.data.preference.FlowFilterBarFilledPreference.Companion.flowFilterBarFilled
import me.ash.reader.data.preference.FilterBarPaddingPreference.filterBarPadding import me.ash.reader.data.preference.FlowFilterBarPaddingPreference.flowFilterBarPadding
import me.ash.reader.data.preference.FilterBarStylePreference.Companion.filterBarStyle import me.ash.reader.data.preference.FlowFilterBarStylePreference.Companion.flowFilterBarStyle
import me.ash.reader.data.preference.FilterBarTonalElevationPreference.Companion.filterBarTonalElevation 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.component.*
import me.ash.reader.ui.ext.collectAsStateValue import me.ash.reader.ui.ext.collectAsStateValue
import me.ash.reader.ui.ext.surfaceColorAtElevation import me.ash.reader.ui.ext.surfaceColorAtElevation
import me.ash.reader.ui.page.home.FilterBar import me.ash.reader.ui.page.home.FilterBar
import me.ash.reader.ui.page.home.flow.ArticleItem import me.ash.reader.ui.page.home.flow.ArticleItem
import me.ash.reader.ui.page.settings.SettingItem 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 me.ash.reader.ui.theme.palette.onLight
import java.util.* import java.util.*
@ -51,29 +56,32 @@ fun FlowPageStyle(
val context = LocalContext.current val context = LocalContext.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val filterBarStyle = val filterBarStyle =
context.filterBarStyle.collectAsStateValue(initial = FilterBarStylePreference.default) context.flowFilterBarStyle.collectAsStateValue(initial = FlowFilterBarStylePreference.default)
val filterBarFilled = val filterBarFilled =
context.filterBarFilled.collectAsStateValue(initial = FilterBarFilledPreference.default) context.flowFilterBarFilled.collectAsStateValue(initial = FlowFilterBarFilledPreference.default)
val filterBarPadding = val filterBarPadding =
context.filterBarPadding.collectAsStateValue(initial = FilterBarPaddingPreference.default) context.flowFilterBarPadding.collectAsStateValue(initial = FlowFilterBarPaddingPreference.default)
val filterBarTonalElevation = val filterBarTonalElevation =
context.filterBarTonalElevation.collectAsStateValue(initial = FilterBarTonalElevationPreference.default) context.flowFilterBarTonalElevation.collectAsStateValue(initial = FlowFilterBarTonalElevationPreference.default)
val topBarTonalElevation =
context.flowTopBarTonalElevation.collectAsStateValue(initial = FlowTopBarTonalElevationPreference.default)
val articleListFeedIcon = val articleListFeedIcon =
context.articleListFeedIcon.collectAsStateValue(initial = ArticleListFeedIconPreference.default) context.flowArticleListFeedIcon.collectAsStateValue(initial = FlowArticleListFeedIconPreference.default)
val articleListFeedName = val articleListFeedName =
context.articleListFeedName.collectAsStateValue(initial = ArticleListFeedNamePreference.default) context.flowArticleListFeedName.collectAsStateValue(initial = FlowArticleListFeedNamePreference.default)
val articleListImage = val articleListImage =
context.articleListImage.collectAsStateValue(initial = ArticleListImagePreference.default) context.flowArticleListImage.collectAsStateValue(initial = FlowArticleListImagePreference.default)
val articleListDesc = val articleListDesc =
context.articleListDesc.collectAsStateValue(initial = ArticleListDescPreference.default) context.flowArticleListDesc.collectAsStateValue(initial = FlowArticleListDescPreference.default)
val articleListDate = val articleListDate =
context.articleListDate.collectAsStateValue(initial = ArticleListDatePreference.default) context.flowArticleListDate.collectAsStateValue(initial = FlowArticleListDatePreference.default)
val articleListTonalElevation = val articleListTonalElevation =
context.articleListTonalElevation.collectAsStateValue(initial = ArticleListTonalElevationPreference.default) context.flowArticleListTonalElevation.collectAsStateValue(initial = FlowArticleListTonalElevationPreference.default)
var filterBarStyleDialogVisible by remember { mutableStateOf(false) } var filterBarStyleDialogVisible by remember { mutableStateOf(false) }
var filterBarPaddingDialogVisible by remember { mutableStateOf(false) } var filterBarPaddingDialogVisible by remember { mutableStateOf(false) }
var filterBarTonalElevationDialogVisible by remember { mutableStateOf(false) } var filterBarTonalElevationDialogVisible by remember { mutableStateOf(false) }
var topBarTonalElevationDialogVisible by remember { mutableStateOf(false) }
var articleListTonalElevationDialogVisible by remember { mutableStateOf(false) } var articleListTonalElevationDialogVisible by remember { mutableStateOf(false) }
var filterBarPaddingValue: Int? by remember { mutableStateOf(filterBarPadding) } var filterBarPaddingValue: Int? by remember { mutableStateOf(filterBarPadding) }
@ -107,6 +115,8 @@ fun FlowPageStyle(
item { item {
DisplayText(text = stringResource(R.string.flow_page), desc = "") DisplayText(text = stringResource(R.string.flow_page), desc = "")
} }
// Preview
item { item {
Row( Row(
modifier = Modifier modifier = Modifier
@ -121,67 +131,49 @@ fun FlowPageStyle(
horizontalArrangement = Arrangement.Center, horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically 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)) Spacer(modifier = Modifier.height(24.dp))
} }
// Top Bar
item { item {
Subtitle( Subtitle(
modifier = Modifier.padding(horizontal = 24.dp), modifier = Modifier.padding(horizontal = 24.dp),
text = "过滤栏", text = stringResource(R.string.top_bar)
) )
SettingItem( SettingItem(
title = "样式", title = stringResource(R.string.mark_as_read_button_position),
desc = filterBarStyle.getDesc(context), desc = stringResource(R.string.top),
onClick = { enable = false,
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 = {}, 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)) Spacer(modifier = Modifier.height(24.dp))
} }
// Article List
item { item {
Subtitle( Subtitle(
modifier = Modifier.padding(horizontal = 24.dp), modifier = Modifier.padding(horizontal = 24.dp),
text = "文章列表" text = stringResource(R.string.article_list)
) )
SettingItem( SettingItem(
title = "显示订阅源图标", title = stringResource(R.string.display_feed_favicon),
onClick = { onClick = {
(!articleListFeedIcon).put(context, scope) (!articleListFeedIcon).put(context, scope)
}, },
@ -191,7 +183,7 @@ fun FlowPageStyle(
} }
} }
SettingItem( SettingItem(
title = "显示订阅源名称", title = stringResource(R.string.display_feed_name),
onClick = { onClick = {
(!articleListFeedName).put(context, scope) (!articleListFeedName).put(context, scope)
}, },
@ -201,13 +193,14 @@ fun FlowPageStyle(
} }
} }
SettingItem( SettingItem(
title = "显示文章插图", title = stringResource(R.string.display_article_image),
enable = false,
onClick = {}, onClick = {},
) { ) {
Switch(activated = false, enable = false) Switch(activated = false, enable = false)
} }
SettingItem( SettingItem(
title = "显示文章描述", title = stringResource(R.string.display_article_desc),
onClick = { onClick = {
(!articleListDesc).put(context, scope) (!articleListDesc).put(context, scope)
}, },
@ -217,7 +210,7 @@ fun FlowPageStyle(
} }
} }
SettingItem( SettingItem(
title = "显示文章发布时间", title = stringResource(R.string.display_article_date),
onClick = { onClick = {
(!articleListDate).put(context, scope) (!articleListDate).put(context, scope)
}, },
@ -227,12 +220,54 @@ fun FlowPageStyle(
} }
} }
SettingItem( SettingItem(
title = "色调海拔", title = stringResource(R.string.tonal_elevation),
desc = "${articleListTonalElevation.value}dp", desc = "${articleListTonalElevation.value}dp",
onClick = { onClick = {
articleListTonalElevationDialogVisible = true 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)) Spacer(modifier = Modifier.height(24.dp))
} }
} }
@ -241,8 +276,8 @@ fun FlowPageStyle(
RadioDialog( RadioDialog(
visible = filterBarStyleDialogVisible, visible = filterBarStyleDialogVisible,
title = stringResource(R.string.initial_filter), title = stringResource(R.string.style),
options = FilterBarStylePreference.values.map { options = FlowFilterBarStylePreference.values.map {
RadioDialogOption( RadioDialogOption(
text = it.getDesc(context), text = it.getDesc(context),
selected = filterBarStyle == it, selected = filterBarStyle == it,
@ -256,17 +291,17 @@ fun FlowPageStyle(
TextFieldDialog( TextFieldDialog(
visible = filterBarPaddingDialogVisible, visible = filterBarPaddingDialogVisible,
title = "两端边距", title = stringResource(R.string.padding_on_both_ends),
value = (filterBarPaddingValue ?: "").toString(), value = (filterBarPaddingValue ?: "").toString(),
placeholder = stringResource(R.string.name), placeholder = stringResource(R.string.value),
onValueChange = { onValueChange = {
filterBarPaddingValue = it.toIntOrNull() filterBarPaddingValue = it.filter { it.isDigit() }.toIntOrNull()
}, },
onDismissRequest = { onDismissRequest = {
filterBarPaddingDialogVisible = false filterBarPaddingDialogVisible = false
}, },
onConfirm = { onConfirm = {
FilterBarPaddingPreference.put(context, scope, filterBarPaddingValue ?: 0) FlowFilterBarPaddingPreference.put(context, scope, filterBarPaddingValue ?: 0)
filterBarPaddingDialogVisible = false filterBarPaddingDialogVisible = false
} }
) )
@ -274,7 +309,7 @@ fun FlowPageStyle(
RadioDialog( RadioDialog(
visible = filterBarTonalElevationDialogVisible, visible = filterBarTonalElevationDialogVisible,
title = stringResource(R.string.tonal_elevation), title = stringResource(R.string.tonal_elevation),
options = FilterBarTonalElevationPreference.values.map { options = FlowFilterBarTonalElevationPreference.values.map {
RadioDialogOption( RadioDialogOption(
text = it.getDesc(context), text = it.getDesc(context),
selected = filterBarTonalElevation == it, selected = filterBarTonalElevation == it,
@ -286,10 +321,25 @@ fun FlowPageStyle(
filterBarTonalElevationDialogVisible = false 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( RadioDialog(
visible = articleListTonalElevationDialogVisible, visible = articleListTonalElevationDialogVisible,
title = stringResource(R.string.tonal_elevation), title = stringResource(R.string.tonal_elevation),
options = ArticleListTonalElevationPreference.values.map { options = FlowArticleListTonalElevationPreference.values.map {
RadioDialogOption( RadioDialogOption(
text = it.getDesc(context), text = it.getDesc(context),
selected = articleListTonalElevation == it, selected = articleListTonalElevation == it,
@ -303,43 +353,85 @@ fun FlowPageStyle(
} }
@Composable @Composable
fun FeedsPagePreview( fun FlowPagePreview(
articleListTonalElevation: ArticleListTonalElevationPreference, topBarTonalElevation: FlowTopBarTonalElevationPreference,
articleListTonalElevation: FlowArticleListTonalElevationPreference,
filterBarStyle: Int,
filterBarFilled: Boolean,
filterBarPadding: Dp,
filterBarTonalElevation: Dp,
) { ) {
var filter by remember { mutableStateOf(Filter.Unread) } var filter by remember { mutableStateOf(Filter.Unread) }
Column( Column(
modifier = Modifier modifier = Modifier
.background( .background(
color = MaterialTheme.colorScheme.surfaceColorAtElevation(articleListTonalElevation.value.dp), color = MaterialTheme.colorScheme.surfaceColorAtElevation(
articleListTonalElevation.value.dp
) onDark MaterialTheme.colorScheme.surface,
shape = RoundedCornerShape(24.dp) 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)) Spacer(modifier = Modifier.height(12.dp))
ArticleItem( ArticleItem(
articleWithFeed = ArticleWithFeed( articleWithFeed = ArticleWithFeed(
Article( Article(
id = "", id = "",
title = "《黎明之剑》撒花完结,白金远瞳的“希灵三部曲”值得你通宵阅读", title = stringResource(R.string.preview_article_title),
shortDescription = "昨日在找书的时候无意间发现,“远瞳”的《黎明之剑》突然冲上了起点热搜榜首位,去小说中查找原因,原来是这部六百多万字的作品已经完结了。四年的时间,这部小说始终占据科幻分类前三甲的位置,不得不说“远瞳”的实力的确不容小觑。", shortDescription = stringResource(R.string.preview_article_desc),
rawDescription = "昨日在找书的时候无意间发现,“远瞳”的《黎明之剑》突然冲上了起点热搜榜首位,去小说中查找原因,原来是这部六百多万字的作品已经完结了。四年的时间,这部小说始终占据科幻分类前三甲的位置,不得不说“远瞳”的实力的确不容小觑。", rawDescription = stringResource(R.string.preview_article_desc),
link = "", link = "",
feedId = "", feedId = "",
accountId = 0, accountId = 0,
date = Date(), date = Date(),
isStarred = true,
), ),
feed = Feed( feed = Feed(
id = "", id = "",
name = "佛门射手", name = stringResource(R.string.preview_feed_name),
icon = "", icon = "",
accountId = 0, accountId = 0,
groupId = "", groupId = "",
url = "", url = "",
) ),
) )
) )
Spacer(modifier = Modifier.height(12.dp)) 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 filter = it
} }
} }

View File

@ -6,7 +6,6 @@ import androidx.compose.foundation.background
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.rounded.CheckCircleOutline import androidx.compose.material.icons.rounded.CheckCircleOutline
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -21,6 +20,7 @@ import kotlinx.coroutines.launch
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.ui.component.DisplayText import me.ash.reader.ui.component.DisplayText
import me.ash.reader.ui.component.DynamicSVGImage 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.DataStoreKeys
import me.ash.reader.ui.ext.dataStore import me.ash.reader.ui.ext.dataStore
import me.ash.reader.ui.ext.put import me.ash.reader.ui.ext.put
@ -57,14 +57,12 @@ fun StartupPage(
) )
} }
item { item {
TipsItem( Tips(
modifier = Modifier modifier = Modifier.padding(top = 40.dp),
.padding(horizontal = 24.dp) text = stringResource(R.string.agree_terms),
.padding(top = 40.dp)
) )
} }
item { item {
Spacer(modifier = Modifier.height(10.dp))
TextButton( TextButton(
modifier = Modifier.padding(horizontal = 12.dp), modifier = Modifier.padding(horizontal = 12.dp),
onClick = { onClick = {
@ -120,25 +118,3 @@ 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,
)
}
}

View File

@ -10,6 +10,7 @@ object SVGString
fun String.parseDynamicColor(tonalPalettes: TonalPalettes, isDarkTheme: Boolean): String = fun String.parseDynamicColor(tonalPalettes: TonalPalettes, isDarkTheme: Boolean): String =
replace("fill=\"(.+?)\"".toRegex()) { replace("fill=\"(.+?)\"".toRegex()) {
val value = it.groupValues[1] val value = it.groupValues[1]
Log.i("RLog", "parseDynamicColor: $value")
if (value.startsWith("#")) return@replace it.value if (value.startsWith("#")) return@replace it.value
try { try {
val (scheme, tone) = value.split("(?<=\\d)(?=\\D)|(?=\\d)(?<=\\D)".toRegex()) val (scheme, tone) = value.split("(?<=\\d)(?=\\D)|(?=\\d)(?<=\\D)".toRegex())
@ -24,6 +25,7 @@ fun String.parseDynamicColor(tonalPalettes: TonalPalettes, isDarkTheme: Boolean)
}?.toArgb() ?: 0xFFFFFF }?.toArgb() ?: 0xFFFFFF
"fill=\"${String.format("#%06X", 0xFFFFFF and argb)}\"" "fill=\"${String.format("#%06X", 0xFFFFFF and argb)}\""
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace()
Log.e("RLog", "parseDynamicColor: ${e.message}") Log.e("RLog", "parseDynamicColor: ${e.message}")
it.value it.value
} }

View File

@ -5,12 +5,29 @@ import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.compositionLocalOf
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import kotlinx.coroutines.flow.map import me.ash.reader.data.preference.*
import me.ash.reader.ui.ext.DataStoreKeys import me.ash.reader.data.preference.FeedsFilterBarFilledPreference.Companion.feedsFilterBarFilled
import me.ash.reader.ui.ext.dataStore 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.LocalTonalPalettes
import me.ash.reader.ui.theme.palette.TonalPalettes import me.ash.reader.ui.theme.palette.TonalPalettes
import me.ash.reader.ui.theme.palette.core.ProvideZcamViewingConditions 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 import me.ash.reader.ui.theme.palette.dynamicLightColorScheme
val LocalUseDarkTheme = compositionLocalOf { false } 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") @SuppressLint("FlowOperatorInvokedInComposition")
@Composable @Composable
@ -28,26 +75,83 @@ fun AppTheme(
content: @Composable () -> Unit content: @Composable () -> Unit
) { ) {
val context = LocalContext.current val context = LocalContext.current
val themeIndex = context.dataStore.data val theme = context.Theme.collectAsStateValue(initial = ThemePreference.default)
.map { it[DataStoreKeys.ThemeIndex.key] ?: 5 }
.collectAsState(initial = 5).value
val tonalPalettes = wallpaperPalettes[ val tonalPalettes = wallpaperPalettes[
if (themeIndex >= wallpaperPalettes.size) { if (theme >= wallpaperPalettes.size) {
when { when {
wallpaperPalettes.size == 5 -> 0 wallpaperPalettes.size == 5 -> 0
wallpaperPalettes.size > 5 -> 5 wallpaperPalettes.size > 5 -> 5
else -> 0 else -> 0
} }
} else { } 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 { ProvideZcamViewingConditions {
CompositionLocalProvider( CompositionLocalProvider(
LocalTonalPalettes provides tonalPalettes.also { it.Preheating() }, 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( MaterialTheme(
colorScheme = colorScheme =

View File

@ -31,6 +31,7 @@ fun dynamicLightColorScheme(): ColorScheme {
onSurface = palettes neutral 10, onSurface = palettes neutral 10,
surfaceVariant = palettes neutralVariant 90, surfaceVariant = palettes neutralVariant 90,
onSurfaceVariant = palettes neutralVariant 30, onSurfaceVariant = palettes neutralVariant 30,
surfaceTint = palettes primary 40,
inverseSurface = palettes neutral 20, inverseSurface = palettes neutral 20,
inverseOnSurface = palettes neutral 95, inverseOnSurface = palettes neutral 95,
outline = palettes neutralVariant 50, outline = palettes neutralVariant 50,
@ -60,6 +61,7 @@ fun dynamicDarkColorScheme(): ColorScheme {
onSurface = palettes neutral 90, onSurface = palettes neutral 90,
surfaceVariant = palettes neutralVariant 30, surfaceVariant = palettes neutralVariant 30,
onSurfaceVariant = palettes neutralVariant 80, onSurfaceVariant = palettes neutralVariant 80,
surfaceTint = palettes primary 80,
inverseSurface = palettes neutral 90, inverseSurface = palettes neutral 90,
inverseOnSurface = palettes neutral 20, inverseOnSurface = palettes neutral 20,
outline = palettes neutralVariant 60, outline = palettes neutralVariant 60,

View File

@ -99,7 +99,7 @@
<string name="primary_color_hint">例如 #666666 或 666666</string> <string name="primary_color_hint">例如 #666666 或 666666</string>
<string name="appearance">外观</string> <string name="appearance">外观</string>
<string name="style">样式</string> <string name="style">样式</string>
<string name="dark_theme">深色模式</string> <string name="dark_theme">深色主题</string>
<string name="use_device_theme">跟随系统设置</string> <string name="use_device_theme">跟随系统设置</string>
<string name="tonal_elevation">色调海拔</string> <string name="tonal_elevation">色调海拔</string>
<string name="fonts">字体</string> <string name="fonts">字体</string>
@ -124,4 +124,28 @@
<string name="on_start">启动时</string> <string name="on_start">启动时</string>
<string name="initial_page">起始页面</string> <string name="initial_page">起始页面</string>
<string name="initial_filter">起始过滤条件</string> <string name="initial_filter">起始过滤条件</string>
<string name="preview_article_title">呜呜呜,黎明之剑完结了</string>
<string name="preview_article_desc">是宴席,就有结束的时候,但这本书真的陪了我好久啊,好舍不得,而且主线结束了坑却没填完,不知道啥时候才有番外啊</string>
<string name="preview_feed_name">漩涡书院</string>
<string name="value"></string>
<string name="padding_on_both_ends">两端边距</string>
<string name="display_article_date">显示文章发布时间</string>
<string name="display_article_desc">显示文章描述</string>
<string name="display_article_image">显示文章插图</string>
<string name="display_feed_name">显示订阅源名称</string>
<string name="display_feed_favicon">显示订阅源图标</string>
<string name="article_list">文章列表</string>
<string name="group_list">分组列表</string>
<string name="always_expand">始终展开</string>
<string name="top">顶部</string>
<string name="mark_as_read_button_position">“标记为已读”按钮的位置</string>
<string name="top_bar">标题栏</string>
<string name="fill_selected_icon">填充已选中的图标</string>
<string name="filter_bar">过滤栏</string>
<string name="icons">图标</string>
<string name="icons_and_labels">图标和文字</string>
<string name="icons_and_label_only_selected">图标和文字(仅选中时)</string>
<string name="tips_top_bar_tonal_elevation">标题栏的色调海拔仅在滚动时可用。</string>
<string name="tips_article_list_tonal_elevation">文章列表的色调海拔仅在亮色主题时可用。</string>
<string name="tips_group_list_tonal_elevation">分组列表的色调海拔仅在亮色主题时可用。</string>
</resources> </resources>

View File

@ -88,9 +88,9 @@
<string name="tips_and_support_desc">About, open source</string> <string name="tips_and_support_desc">About, open source</string>
<string name="welcome">Welcome</string> <string name="welcome">Welcome</string>
<string name="agree_terms">Before you can continue, you need to agree to Read You\'s Terms of Service and Privacy Policy.</string> <string name="agree_terms">Before you can continue, you need to agree to Read You\'s Terms of Service and Privacy Policy.</string>
<string name="view_terms">View the &lt;i&gt;&lt;u&gt;Terms of Service and Privacy Policy&lt;/u&gt;&lt;/i&gt;</string> <string name="view_terms">View the &lt;i&gt;&lt;u&gt;Terms of Service &amp; Privacy Policy&lt;/u&gt;&lt;/i&gt;</string>
<string name="terms_link">https://github.com/Ashinch/ReadYou/blob/main/TERMS_OF_SERVICE_AND_PRIVACY_POLICY.md</string> <string name="terms_link">https://github.com/Ashinch/ReadYou/blob/main/TERMS_OF_SERVICE_AND_PRIVACY_POLICY.md</string>
<string name="agree_and_continue">Agree and Continue</string> <string name="agree_and_continue">Agree</string>
<string name="wallpaper_colors">Wallpaper Colors</string> <string name="wallpaper_colors">Wallpaper Colors</string>
<string name="no_palettes">No Palettes</string> <string name="no_palettes">No Palettes</string>
<string name="only_android_8.1_plus">Only Android 8.1+</string> <string name="only_android_8.1_plus">Only Android 8.1+</string>
@ -116,7 +116,7 @@
<string name="update">Update</string> <string name="update">Update</string>
<string name="skip_this_version">Skip This Version</string> <string name="skip_this_version">Skip This Version</string>
<string name="checking_updates">Checking for updates…</string> <string name="checking_updates">Checking for updates…</string>
<string name="is_latest_version">This is the latest version</string> <string name="is_latest_version">This is latest version</string>
<string name="check_failure">Check failure</string> <string name="check_failure">Check failure</string>
<string name="download_failure">Download failure</string> <string name="download_failure">Download failure</string>
<string name="rate_limit">The request rate is limited</string> <string name="rate_limit">The request rate is limited</string>
@ -124,4 +124,28 @@
<string name="on_start">On Start</string> <string name="on_start">On Start</string>
<string name="initial_page">Initial Page</string> <string name="initial_page">Initial Page</string>
<string name="initial_filter">Initial Filter</string> <string name="initial_filter">Initial Filter</string>
<string name="preview_article_title">The novel "Lord of the Mysteries" has finally come to an end</string>
<string name="preview_article_desc">The Fool is the eighth and final volume of the Lord of the Mysteries series written by Cuttlefish That Loves Diving.</string>
<string name="preview_feed_name">Reddit</string>
<string name="value">value</string>
<string name="padding_on_both_ends">Padding on Both Ends</string>
<string name="display_article_date">Display Article Publish Time</string>
<string name="display_article_desc">Display Article Descriptions</string>
<string name="display_article_image">Display Article Images</string>
<string name="display_feed_name">Display Feed Names</string>
<string name="display_feed_favicon">Display Feed Favicons</string>
<string name="article_list">Article List</string>
<string name="group_list">Group List</string>
<string name="always_expand">Always Expand</string>
<string name="top">Top</string>
<string name="mark_as_read_button_position">\"Mark as Read\" Button Position</string>
<string name="top_bar">Top Bar</string>
<string name="fill_selected_icon">Fill The Selected Icon</string>
<string name="filter_bar">Filter Bar</string>
<string name="icons">Icons</string>
<string name="icons_and_labels">Icons &amp; Labels</string>
<string name="icons_and_label_only_selected">Icons &amp; Label (Only Selected)</string>
<string name="tips_top_bar_tonal_elevation">Tone elevation of the top bar is only available when scrolling.</string>
<string name="tips_article_list_tonal_elevation">Tone elevation of the article list is only available for light theme.</string>
<string name="tips_group_list_tonal_elevation">Tone elevation of the group list is only available for light theme.</string>
</resources> </resources>