Add FeedsPage style settings
This commit is contained in:
parent
9bea2e8e8b
commit
fa3c5e3601
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
app/src/main/java/me/ash/reader/ui/component/Tips.kt
Normal file
38
app/src/main/java/me/ash/reader/ui/component/Tips.kt
Normal 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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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>() {
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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(),
|
||||||
|
|
|
@ -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(
|
||||||
|
@ -91,4 +95,3 @@ fun FeedItem(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
},
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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)
|
||||||
},
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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>
|
|
@ -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 <i><u>Terms of Service and Privacy Policy</u></i></string>
|
<string name="view_terms">View the <i><u>Terms of Service & Privacy Policy</u></i></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 & Labels</string>
|
||||||
|
<string name="icons_and_label_only_selected">Icons & 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>
|
Loading…
Reference in New Issue
Block a user