Add reading page style settings (#132)
* Add reading page style settings * improved german language (#134) * Add Hindi translation Thanks augurer * Add auto hide toolbar and image maximize setting * Add tonal elevation setting in reading page * Add reading dark theme and previews * Add dynamic custom reading theme preview Co-authored-by: helloworldtest123 <36381315+helloworldtest123@users.noreply.github.com>
This commit is contained in:
parent
e32c0fbfd3
commit
f21a0c9fd8
|
@ -66,6 +66,14 @@ Nachfolgend sind die bisher erzielten Fortschritte und die Ziele aufgeführt, an
|
|||
|
||||
> Bei den oben genannten Funktionen handelt es sich nur um vorläufige Implementierungen, und es können noch unbekannte Probleme auftreten.
|
||||
|
||||
## Herunterladen
|
||||
|
||||
[<img src="https://fdroid.gitlab.io/artwork/badge/get-it-on-de.png"
|
||||
alt="Jetzt bei F-Droid"
|
||||
height="80">](https://f-droid.org/packages/me.ash.reader/)
|
||||
|
||||
oder hole die APK aus dem [GitHub Releasebereich](https://github.com/Ashinch/ReadYou/releases).
|
||||
|
||||
## Build
|
||||
|
||||
> Wenn Sie eine Vorschau der Read You App wollen, können Sie die **Vorschau-Version** der APK-Datei in [Telegram] (https://t.me/ReadYouApp) herunterladen.
|
||||
|
|
|
@ -20,6 +20,8 @@ sealed class LanguagesPreference(val value: Int) : Preference() {
|
|||
object Czech : LanguagesPreference(5)
|
||||
object Italian : LanguagesPreference(6)
|
||||
|
||||
object Hindi : LanguagesPreference(7)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(
|
||||
|
@ -39,6 +41,7 @@ sealed class LanguagesPreference(val value: Int) : Preference() {
|
|||
French -> context.getString(R.string.french)
|
||||
Czech -> context.getString(R.string.czech)
|
||||
Italian -> context.getString(R.string.italian)
|
||||
Hindi -> context.getString(R.string.hindi)
|
||||
}
|
||||
|
||||
fun getLocale(): Locale =
|
||||
|
@ -50,6 +53,7 @@ sealed class LanguagesPreference(val value: Int) : Preference() {
|
|||
French -> Locale("fr", "FR")
|
||||
Czech -> Locale("cs", "CZ")
|
||||
Italian -> Locale("it", "IT")
|
||||
Hindi -> Locale("hi", "IN")
|
||||
}
|
||||
|
||||
fun setLocale(context: Context) {
|
||||
|
@ -74,7 +78,7 @@ sealed class LanguagesPreference(val value: Int) : Preference() {
|
|||
companion object {
|
||||
|
||||
val default = UseDeviceLanguages
|
||||
val values = listOf(UseDeviceLanguages, English, ChineseSimplified, German, French, Czech, Italian)
|
||||
val values = listOf(UseDeviceLanguages, English, ChineseSimplified, German, French, Czech, Italian, Hindi)
|
||||
|
||||
fun fromPreferences(preferences: Preferences): LanguagesPreference =
|
||||
when (preferences[DataStoreKeys.Languages.key]) {
|
||||
|
@ -85,6 +89,7 @@ sealed class LanguagesPreference(val value: Int) : Preference() {
|
|||
4 -> French
|
||||
5 -> Czech
|
||||
6 -> Italian
|
||||
7 -> Hindi
|
||||
else -> default
|
||||
}
|
||||
|
||||
|
@ -97,6 +102,7 @@ sealed class LanguagesPreference(val value: Int) : Preference() {
|
|||
4 -> French
|
||||
5 -> Czech
|
||||
6 -> Italian
|
||||
7 -> Hindi
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ sealed class Preference {
|
|||
|
||||
fun Preferences.toSettings(): Settings {
|
||||
return Settings(
|
||||
// Version
|
||||
newVersionNumber = NewVersionNumberPreference.fromPreferences(this),
|
||||
skipVersionNumber = SkipVersionNumberPreference.fromPreferences(this),
|
||||
newVersionPublishDate = NewVersionPublishDatePreference.fromPreferences(this),
|
||||
|
@ -18,11 +19,13 @@ fun Preferences.toSettings(): Settings {
|
|||
newVersionSize = NewVersionSizePreference.fromPreferences(this),
|
||||
newVersionDownloadUrl = NewVersionDownloadUrlPreference.fromPreferences(this),
|
||||
|
||||
// Theme
|
||||
themeIndex = ThemeIndexPreference.fromPreferences(this),
|
||||
customPrimaryColor = CustomPrimaryColorPreference.fromPreferences(this),
|
||||
darkTheme = DarkThemePreference.fromPreferences(this),
|
||||
amoledDarkTheme = AmoledDarkThemePreference.fromPreferences(this),
|
||||
|
||||
// Feeds page
|
||||
feedsFilterBarStyle = FeedsFilterBarStylePreference.fromPreferences(this),
|
||||
feedsFilterBarFilled = FeedsFilterBarFilledPreference.fromPreferences(this),
|
||||
feedsFilterBarPadding = FeedsFilterBarPaddingPreference.fromPreferences(this),
|
||||
|
@ -31,6 +34,7 @@ fun Preferences.toSettings(): Settings {
|
|||
feedsGroupListExpand = FeedsGroupListExpandPreference.fromPreferences(this),
|
||||
feedsGroupListTonalElevation = FeedsGroupListTonalElevationPreference.fromPreferences(this),
|
||||
|
||||
// Flow page
|
||||
flowFilterBarStyle = FlowFilterBarStylePreference.fromPreferences(this),
|
||||
flowFilterBarFilled = FlowFilterBarFilledPreference.fromPreferences(this),
|
||||
flowFilterBarPadding = FlowFilterBarPaddingPreference.fromPreferences(this),
|
||||
|
@ -46,9 +50,32 @@ fun Preferences.toSettings(): Settings {
|
|||
),
|
||||
flowArticleListTonalElevation = FlowArticleListTonalElevationPreference.fromPreferences(this),
|
||||
|
||||
// Reading page
|
||||
readingTheme = ReadingThemePreference.fromPreferences(this),
|
||||
readingDarkTheme = ReadingDarkThemePreference.fromPreferences(this),
|
||||
readingPageTonalElevation = ReadingPageTonalElevationPreference.fromPreferences(this),
|
||||
readingAutoHideToolbar = ReadingAutoHideToolbarPreference.fromPreferences(this),
|
||||
readingTextFontSize = ReadingTextFontSizePreference.fromPreferences(this),
|
||||
readingLetterSpacing = ReadingLetterSpacingPreference.fromPreferences(this),
|
||||
readingTextHorizontalPadding = ReadingTextHorizontalPaddingPreference.fromPreferences(this),
|
||||
readingTextAlign = ReadingTextAlignPreference.fromPreferences(this),
|
||||
readingTextBold = ReadingTextBoldPreference.fromPreferences(this),
|
||||
readingTitleAlign = ReadingTitleAlignPreference.fromPreferences(this),
|
||||
readingSubheadAlign = ReadingSubheadAlignPreference.fromPreferences(this),
|
||||
readingFonts = ReadingFontsPreference.fromPreferences(this),
|
||||
readingTitleBold = ReadingTitleBoldPreference.fromPreferences(this),
|
||||
readingSubheadBold = ReadingSubheadBoldPreference.fromPreferences(this),
|
||||
readingTitleUpperCase = ReadingTitleUpperCasePreference.fromPreferences(this),
|
||||
readingSubheadUpperCase = ReadingSubheadUpperCasePreference.fromPreferences(this),
|
||||
readingImageHorizontalPadding = ReadingImageHorizontalPaddingPreference.fromPreferences(this),
|
||||
readingImageRoundedCorners = ReadingImageRoundedCornersPreference.fromPreferences(this),
|
||||
readingImageMaximize = ReadingImageMaximizePreference.fromPreferences(this),
|
||||
|
||||
// Interaction
|
||||
initialPage = InitialPagePreference.fromPreferences(this),
|
||||
initialFilter = InitialFilterPreference.fromPreferences(this),
|
||||
|
||||
// Languages
|
||||
languages = LanguagesPreference.fromPreferences(this),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingAutoHideToolbarPreference(val value: Boolean) : Preference() {
|
||||
object ON : ReadingAutoHideToolbarPreference(true)
|
||||
object OFF : ReadingAutoHideToolbarPreference(false)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(DataStoreKeys.ReadingAutoHideToolbar, value)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = ON
|
||||
val values = listOf(ON, OFF)
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
when (preferences[DataStoreKeys.ReadingAutoHideToolbar.key]) {
|
||||
true -> ON
|
||||
false -> OFF
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun ReadingAutoHideToolbarPreference.not(): ReadingAutoHideToolbarPreference =
|
||||
when (value) {
|
||||
true -> ReadingAutoHideToolbarPreference.OFF
|
||||
false -> ReadingAutoHideToolbarPreference.ON
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingDarkThemePreference(val value: Int) : Preference() {
|
||||
object UseAppTheme : ReadingDarkThemePreference(0)
|
||||
object ON : ReadingDarkThemePreference(1)
|
||||
object OFF : ReadingDarkThemePreference(2)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(
|
||||
DataStoreKeys.ReadingDarkTheme,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun toDesc(context: Context): String =
|
||||
when (this) {
|
||||
UseAppTheme -> context.getString(R.string.use_app_theme)
|
||||
ON -> context.getString(R.string.on)
|
||||
OFF -> context.getString(R.string.off)
|
||||
}
|
||||
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun isDarkTheme(): Boolean = when (this) {
|
||||
UseAppTheme -> LocalDarkTheme.current.isDarkTheme()
|
||||
ON -> true
|
||||
OFF -> false
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = UseAppTheme
|
||||
val values = listOf(UseAppTheme, ON, OFF)
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
when (preferences[DataStoreKeys.ReadingDarkTheme.key]) {
|
||||
0 -> UseAppTheme
|
||||
1 -> ON
|
||||
2 -> OFF
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
operator fun ReadingDarkThemePreference.not(): ReadingDarkThemePreference =
|
||||
when (this) {
|
||||
ReadingDarkThemePreference.UseAppTheme -> if (LocalDarkTheme.current.isDarkTheme()) {
|
||||
ReadingDarkThemePreference.OFF
|
||||
} else {
|
||||
ReadingDarkThemePreference.ON
|
||||
}
|
||||
|
||||
ReadingDarkThemePreference.ON -> ReadingDarkThemePreference.OFF
|
||||
ReadingDarkThemePreference.OFF -> ReadingDarkThemePreference.ON
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
import me.ash.reader.ui.theme.googleSansDisplay
|
||||
import me.ash.reader.ui.theme.googleSansText
|
||||
|
||||
sealed class ReadingFontsPreference(val value: Int) : Preference() {
|
||||
object GoogleSans : ReadingFontsPreference(0)
|
||||
object Serif : ReadingFontsPreference(1)
|
||||
object SansSerif : ReadingFontsPreference(2)
|
||||
object Monospace : ReadingFontsPreference(3)
|
||||
object Cursive : ReadingFontsPreference(4)
|
||||
object External : ReadingFontsPreference(5)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(DataStoreKeys.ReadingFonts, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun toDesc(context: Context): String =
|
||||
when (this) {
|
||||
GoogleSans -> "Google Sans"
|
||||
Serif -> "Serif"
|
||||
SansSerif -> "Sans-Serif"
|
||||
Monospace -> "Monospace"
|
||||
Cursive -> "Cursive"
|
||||
External -> context.getString(R.string.external_fonts)
|
||||
}
|
||||
|
||||
fun asFontFamily(isDisplay: Boolean = false): FontFamily =
|
||||
when (this) {
|
||||
GoogleSans -> if (isDisplay) googleSansDisplay else googleSansText
|
||||
Serif -> FontFamily.Serif
|
||||
SansSerif -> FontFamily.SansSerif
|
||||
Monospace -> FontFamily.Monospace
|
||||
Cursive -> FontFamily.Cursive
|
||||
External -> FontFamily.Default
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = GoogleSans
|
||||
val values = listOf(GoogleSans, Serif, SansSerif, Monospace, Cursive, External)
|
||||
|
||||
fun fromPreferences(preferences: Preferences): ReadingFontsPreference =
|
||||
when (preferences[DataStoreKeys.ReadingFonts.key]) {
|
||||
0 -> GoogleSans
|
||||
1 -> Serif
|
||||
2 -> SansSerif
|
||||
3 -> Monospace
|
||||
4 -> Cursive
|
||||
5 -> External
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
object ReadingImageHorizontalPaddingPreference {
|
||||
|
||||
const val default = 24
|
||||
|
||||
fun put(context: Context, scope: CoroutineScope, value: Int) {
|
||||
scope.launch {
|
||||
context.dataStore.put(DataStoreKeys.ReadingImageHorizontalPadding, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
preferences[DataStoreKeys.ReadingImageHorizontalPadding.key] ?: default
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingImageMaximizePreference(val value: Boolean) : Preference() {
|
||||
object ON : ReadingImageMaximizePreference(true)
|
||||
object OFF : ReadingImageMaximizePreference(false)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(DataStoreKeys.ReadingImageMaximize, value)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = ON
|
||||
val values = listOf(ON, OFF)
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
when (preferences[DataStoreKeys.ReadingImageMaximize.key]) {
|
||||
true -> ON
|
||||
false -> OFF
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun ReadingImageMaximizePreference.not(): ReadingImageMaximizePreference =
|
||||
when (value) {
|
||||
true -> ReadingImageMaximizePreference.OFF
|
||||
false -> ReadingImageMaximizePreference.ON
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
object ReadingImageRoundedCornersPreference {
|
||||
|
||||
const val default = 32
|
||||
|
||||
fun put(context: Context, scope: CoroutineScope, value: Int) {
|
||||
scope.launch {
|
||||
context.dataStore.put(DataStoreKeys.ReadingImageRoundedCorners, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
preferences[DataStoreKeys.ReadingImageRoundedCorners.key] ?: default
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
object ReadingLetterSpacingPreference {
|
||||
|
||||
const val default = 0.5
|
||||
|
||||
fun put(context: Context, scope: CoroutineScope, value: Double) {
|
||||
scope.launch {
|
||||
context.dataStore.put(DataStoreKeys.ReadingLetterSpacing, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
preferences[DataStoreKeys.ReadingLetterSpacing.key] ?: default
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.data.constant.ElevationTokens
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingPageTonalElevationPreference(val value: Int) : Preference() {
|
||||
object Level0 : ReadingPageTonalElevationPreference(ElevationTokens.Level0)
|
||||
object Level1 : ReadingPageTonalElevationPreference(ElevationTokens.Level1)
|
||||
object Level2 : ReadingPageTonalElevationPreference(ElevationTokens.Level2)
|
||||
object Level3 : ReadingPageTonalElevationPreference(ElevationTokens.Level3)
|
||||
object Level4 : ReadingPageTonalElevationPreference(ElevationTokens.Level4)
|
||||
object Level5 : ReadingPageTonalElevationPreference(ElevationTokens.Level5)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(DataStoreKeys.ReadingPageTonalElevation, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun toDesc(context: Context): String =
|
||||
when (this) {
|
||||
Level0 -> "Level 0 (${ElevationTokens.Level0}dp)"
|
||||
Level1 -> "Level 1 (${ElevationTokens.Level1}dp)"
|
||||
Level2 -> "Level 2 (${ElevationTokens.Level2}dp)"
|
||||
Level3 -> "Level 3 (${ElevationTokens.Level3}dp)"
|
||||
Level4 -> "Level 4 (${ElevationTokens.Level4}dp)"
|
||||
Level5 -> "Level 5 (${ElevationTokens.Level5}dp)"
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = Level0
|
||||
val values = listOf(Level0, Level1, Level2, Level3, Level4, Level5)
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
when (preferences[DataStoreKeys.ReadingPageTonalElevation.key]) {
|
||||
ElevationTokens.Level0 -> Level0
|
||||
ElevationTokens.Level1 -> Level1
|
||||
ElevationTokens.Level2 -> Level2
|
||||
ElevationTokens.Level3 -> Level3
|
||||
ElevationTokens.Level4 -> Level4
|
||||
ElevationTokens.Level5 -> Level5
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingSubheadAlignPreference(val value: Int) : Preference() {
|
||||
object Left : ReadingSubheadAlignPreference(0)
|
||||
object Right : ReadingSubheadAlignPreference(1)
|
||||
object Center : ReadingSubheadAlignPreference(2)
|
||||
object Justify : ReadingSubheadAlignPreference(3)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(
|
||||
DataStoreKeys.ReadingSubheadAlign,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun toDesc(context: Context): String =
|
||||
when (this) {
|
||||
Left -> context.getString(R.string.align_left)
|
||||
Right -> context.getString(R.string.align_right)
|
||||
Center -> context.getString(R.string.center_text)
|
||||
Justify -> context.getString(R.string.justify)
|
||||
}
|
||||
|
||||
fun toTextAlign(): TextAlign =
|
||||
when (this) {
|
||||
Left -> TextAlign.Start
|
||||
Right -> TextAlign.End
|
||||
Center -> TextAlign.Center
|
||||
Justify -> TextAlign.Justify
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = Left
|
||||
val values = listOf(Left, Right, Center, Justify)
|
||||
|
||||
fun fromPreferences(preferences: Preferences): ReadingSubheadAlignPreference =
|
||||
when (preferences[DataStoreKeys.ReadingSubheadAlign.key]) {
|
||||
0 -> Left
|
||||
1 -> Right
|
||||
2 -> Center
|
||||
3 -> Justify
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingSubheadBoldPreference(val value: Boolean) : Preference() {
|
||||
object ON : ReadingSubheadBoldPreference(true)
|
||||
object OFF : ReadingSubheadBoldPreference(false)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(
|
||||
DataStoreKeys.ReadingSubheadBold,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = OFF
|
||||
val values = listOf(ON, OFF)
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
when (preferences[DataStoreKeys.ReadingSubheadBold.key]) {
|
||||
true -> ON
|
||||
false -> OFF
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun ReadingSubheadBoldPreference.not(): ReadingSubheadBoldPreference =
|
||||
when (value) {
|
||||
true -> ReadingSubheadBoldPreference.OFF
|
||||
false -> ReadingSubheadBoldPreference.ON
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingSubheadUpperCasePreference(val value: Boolean) : Preference() {
|
||||
object ON : ReadingSubheadUpperCasePreference(true)
|
||||
object OFF : ReadingSubheadUpperCasePreference(false)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(
|
||||
DataStoreKeys.ReadingSubheadUpperCase,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = OFF
|
||||
val values = listOf(ON, OFF)
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
when (preferences[DataStoreKeys.ReadingSubheadUpperCase.key]) {
|
||||
true -> ON
|
||||
false -> OFF
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun ReadingSubheadUpperCasePreference.not(): ReadingSubheadUpperCasePreference =
|
||||
when (value) {
|
||||
true -> ReadingSubheadUpperCasePreference.OFF
|
||||
false -> ReadingSubheadUpperCasePreference.ON
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingTextAlignPreference(val value: Int) : Preference() {
|
||||
object Left : ReadingTextAlignPreference(0)
|
||||
object Right : ReadingTextAlignPreference(1)
|
||||
object Center : ReadingTextAlignPreference(2)
|
||||
object Justify : ReadingTextAlignPreference(3)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(
|
||||
DataStoreKeys.ReadingTextAlign,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun toDesc(context: Context): String =
|
||||
when (this) {
|
||||
Left -> context.getString(R.string.align_left)
|
||||
Right -> context.getString(R.string.align_right)
|
||||
Center -> context.getString(R.string.center_text)
|
||||
Justify -> context.getString(R.string.justify)
|
||||
}
|
||||
|
||||
fun toTextAlign(): TextAlign =
|
||||
when (this) {
|
||||
Left -> TextAlign.Start
|
||||
Right -> TextAlign.End
|
||||
Center -> TextAlign.Center
|
||||
Justify -> TextAlign.Justify
|
||||
}
|
||||
fun toAlignment(): Alignment.Horizontal =
|
||||
when (this) {
|
||||
Left -> Alignment.Start
|
||||
Right -> Alignment.End
|
||||
Center -> Alignment.CenterHorizontally
|
||||
Justify -> Alignment.Start
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = Left
|
||||
val values = listOf(Left, Right, Center, Justify)
|
||||
|
||||
fun fromPreferences(preferences: Preferences): ReadingTextAlignPreference =
|
||||
when (preferences[DataStoreKeys.ReadingTextAlign.key]) {
|
||||
0 -> Left
|
||||
1 -> Right
|
||||
2 -> Center
|
||||
3 -> Justify
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingTextBoldPreference(val value: Boolean) : Preference() {
|
||||
object ON : ReadingTextBoldPreference(true)
|
||||
object OFF : ReadingTextBoldPreference(false)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(
|
||||
DataStoreKeys.ReadingTextBold,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = OFF
|
||||
val values = listOf(ON, OFF)
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
when (preferences[DataStoreKeys.ReadingTextBold.key]) {
|
||||
true -> ON
|
||||
false -> OFF
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun ReadingTextBoldPreference.not(): ReadingTextBoldPreference =
|
||||
when (value) {
|
||||
true -> ReadingTextBoldPreference.OFF
|
||||
false -> ReadingTextBoldPreference.ON
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
object ReadingTextFontSizePreference {
|
||||
|
||||
const val default = 17
|
||||
|
||||
fun put(context: Context, scope: CoroutineScope, value: Int) {
|
||||
scope.launch {
|
||||
context.dataStore.put(DataStoreKeys.ReadingTextFontSize, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
preferences[DataStoreKeys.ReadingTextFontSize.key] ?: default
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
object ReadingTextHorizontalPaddingPreference {
|
||||
|
||||
const val default = 24
|
||||
|
||||
fun put(context: Context, scope: CoroutineScope, value: Int) {
|
||||
scope.launch {
|
||||
context.dataStore.put(DataStoreKeys.ReadingTextHorizontalPadding, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
preferences[DataStoreKeys.ReadingTextHorizontalPadding.key] ?: default
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Immutable
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
@Immutable
|
||||
sealed class ReadingThemePreference(val value: Int) : Preference() {
|
||||
|
||||
object MaterialYou : ReadingThemePreference(0)
|
||||
object Reeder : ReadingThemePreference(1)
|
||||
object Paper : ReadingThemePreference(2)
|
||||
object Custom : ReadingThemePreference(3)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(DataStoreKeys.ReadingTheme, value)
|
||||
}
|
||||
}
|
||||
|
||||
fun toDesc(context: Context): String =
|
||||
when (this) {
|
||||
MaterialYou -> "Material You"
|
||||
Reeder -> "Reeder"
|
||||
Paper -> "Paper"
|
||||
Custom -> "Custom"
|
||||
}
|
||||
|
||||
fun applyTheme(context: Context, scope: CoroutineScope) {
|
||||
when (this) {
|
||||
MaterialYou -> {
|
||||
ReadingTitleBoldPreference.default.put(context, scope)
|
||||
ReadingTitleUpperCasePreference.default.put(context, scope)
|
||||
ReadingTitleAlignPreference.default.put(context, scope)
|
||||
ReadingSubheadBoldPreference.default.put(context, scope)
|
||||
ReadingSubheadUpperCasePreference.default.put(context, scope)
|
||||
ReadingSubheadAlignPreference.default.put(context, scope)
|
||||
ReadingTextBoldPreference.default.put(context, scope)
|
||||
ReadingTextHorizontalPaddingPreference.put(context, scope,
|
||||
ReadingTextHorizontalPaddingPreference.default)
|
||||
ReadingTextAlignPreference.default.put(context, scope)
|
||||
ReadingLetterSpacingPreference.put(context, scope, ReadingLetterSpacingPreference.default)
|
||||
ReadingTextFontSizePreference.put(context, scope, ReadingTextFontSizePreference.default)
|
||||
ReadingImageRoundedCornersPreference.put(context, scope, ReadingImageRoundedCornersPreference.default)
|
||||
ReadingImageHorizontalPaddingPreference.put(context, scope,
|
||||
ReadingImageHorizontalPaddingPreference.default)
|
||||
ReadingImageMaximizePreference.default.put(context, scope)
|
||||
}
|
||||
|
||||
Reeder -> {
|
||||
ReadingTitleBoldPreference.ON.put(context, scope)
|
||||
ReadingTitleUpperCasePreference.default.put(context, scope)
|
||||
ReadingTitleAlignPreference.default.put(context, scope)
|
||||
ReadingSubheadBoldPreference.ON.put(context, scope)
|
||||
ReadingSubheadUpperCasePreference.default.put(context, scope)
|
||||
ReadingSubheadAlignPreference.default.put(context, scope)
|
||||
ReadingTextBoldPreference.default.put(context, scope)
|
||||
ReadingTextHorizontalPaddingPreference.put(context, scope,
|
||||
ReadingTextHorizontalPaddingPreference.default)
|
||||
ReadingTextAlignPreference.default.put(context, scope)
|
||||
ReadingLetterSpacingPreference.put(context, scope, ReadingLetterSpacingPreference.default)
|
||||
ReadingTextFontSizePreference.put(context, scope, 18)
|
||||
ReadingImageRoundedCornersPreference.put(context, scope, 0)
|
||||
ReadingImageHorizontalPaddingPreference.put(context, scope, 0)
|
||||
ReadingImageMaximizePreference.default.put(context, scope)
|
||||
}
|
||||
|
||||
Paper -> {
|
||||
ReadingTitleBoldPreference.ON.put(context, scope)
|
||||
ReadingTitleUpperCasePreference.ON.put(context, scope)
|
||||
ReadingTitleAlignPreference.Center.put(context, scope)
|
||||
ReadingSubheadBoldPreference.ON.put(context, scope)
|
||||
ReadingSubheadUpperCasePreference.ON.put(context, scope)
|
||||
ReadingSubheadAlignPreference.Center.put(context, scope)
|
||||
ReadingTextBoldPreference.default.put(context, scope)
|
||||
ReadingTextHorizontalPaddingPreference.put(context, scope,
|
||||
ReadingTextHorizontalPaddingPreference.default)
|
||||
ReadingTextAlignPreference.Center.put(context, scope)
|
||||
ReadingLetterSpacingPreference.put(context, scope, ReadingLetterSpacingPreference.default)
|
||||
ReadingTextFontSizePreference.put(context, scope, 20)
|
||||
ReadingImageRoundedCornersPreference.put(context, scope, 0)
|
||||
ReadingImageHorizontalPaddingPreference.put(context, scope,
|
||||
ReadingImageHorizontalPaddingPreference.default)
|
||||
ReadingImageMaximizePreference.default.put(context, scope)
|
||||
}
|
||||
|
||||
Custom -> {
|
||||
ReadingTitleBoldPreference.default.put(context, scope)
|
||||
ReadingTitleUpperCasePreference.default.put(context, scope)
|
||||
ReadingTitleAlignPreference.default.put(context, scope)
|
||||
ReadingSubheadBoldPreference.default.put(context, scope)
|
||||
ReadingSubheadUpperCasePreference.default.put(context, scope)
|
||||
ReadingSubheadAlignPreference.default.put(context, scope)
|
||||
ReadingTextBoldPreference.default.put(context, scope)
|
||||
ReadingTextHorizontalPaddingPreference.put(context, scope,
|
||||
ReadingTextHorizontalPaddingPreference.default)
|
||||
ReadingTextAlignPreference.default.put(context, scope)
|
||||
ReadingLetterSpacingPreference.put(context, scope, ReadingLetterSpacingPreference.default)
|
||||
ReadingTextFontSizePreference.put(context, scope, ReadingTextFontSizePreference.default)
|
||||
ReadingImageRoundedCornersPreference.put(context, scope, ReadingImageRoundedCornersPreference.default)
|
||||
ReadingImageHorizontalPaddingPreference.put(context, scope,
|
||||
ReadingImageHorizontalPaddingPreference.default)
|
||||
ReadingImageMaximizePreference.default.put(context, scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = MaterialYou
|
||||
val values = listOf(MaterialYou, Reeder, Paper, Custom)
|
||||
|
||||
fun fromPreferences(preferences: Preferences): ReadingThemePreference =
|
||||
when (preferences[DataStoreKeys.ReadingTheme.key]) {
|
||||
0 -> MaterialYou
|
||||
1 -> Reeder
|
||||
2 -> Paper
|
||||
3 -> Custom
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingTitleAlignPreference(val value: Int) : Preference() {
|
||||
object Left : ReadingTitleAlignPreference(0)
|
||||
object Right : ReadingTitleAlignPreference(1)
|
||||
object Center : ReadingTitleAlignPreference(2)
|
||||
object Justify : ReadingTitleAlignPreference(3)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(
|
||||
DataStoreKeys.ReadingTitleAlign,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
fun toDesc(context: Context): String =
|
||||
when (this) {
|
||||
Left -> context.getString(R.string.align_left)
|
||||
Right -> context.getString(R.string.align_right)
|
||||
Center -> context.getString(R.string.center_text)
|
||||
Justify -> context.getString(R.string.justify)
|
||||
}
|
||||
|
||||
@Stable
|
||||
fun toTextAlign(): TextAlign =
|
||||
when (this) {
|
||||
Left -> TextAlign.Start
|
||||
Right -> TextAlign.End
|
||||
Center -> TextAlign.Center
|
||||
Justify -> TextAlign.Justify
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = Left
|
||||
val values = listOf(Left, Right, Center, Justify)
|
||||
|
||||
fun fromPreferences(preferences: Preferences): ReadingTitleAlignPreference =
|
||||
when (preferences[DataStoreKeys.ReadingTitleAlign.key]) {
|
||||
0 -> Left
|
||||
1 -> Right
|
||||
2 -> Center
|
||||
3 -> Justify
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingTitleBoldPreference(val value: Boolean) : Preference() {
|
||||
object ON : ReadingTitleBoldPreference(true)
|
||||
object OFF : ReadingTitleBoldPreference(false)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(
|
||||
DataStoreKeys.ReadingTitleBold,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = OFF
|
||||
val values = listOf(ON, OFF)
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
when (preferences[DataStoreKeys.ReadingTitleBold.key]) {
|
||||
true -> ON
|
||||
false -> OFF
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun ReadingTitleBoldPreference.not(): ReadingTitleBoldPreference =
|
||||
when (value) {
|
||||
true -> ReadingTitleBoldPreference.OFF
|
||||
false -> ReadingTitleBoldPreference.ON
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package me.ash.reader.data.model.preference
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.ui.ext.DataStoreKeys
|
||||
import me.ash.reader.ui.ext.dataStore
|
||||
import me.ash.reader.ui.ext.put
|
||||
|
||||
sealed class ReadingTitleUpperCasePreference(val value: Boolean) : Preference() {
|
||||
object ON : ReadingTitleUpperCasePreference(true)
|
||||
object OFF : ReadingTitleUpperCasePreference(false)
|
||||
|
||||
override fun put(context: Context, scope: CoroutineScope) {
|
||||
scope.launch {
|
||||
context.dataStore.put(
|
||||
DataStoreKeys.ReadingTitleUpperCase,
|
||||
value
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
val default = OFF
|
||||
val values = listOf(ON, OFF)
|
||||
|
||||
fun fromPreferences(preferences: Preferences) =
|
||||
when (preferences[DataStoreKeys.ReadingTitleUpperCase.key]) {
|
||||
true -> ON
|
||||
false -> OFF
|
||||
else -> default
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun ReadingTitleUpperCasePreference.not(): ReadingTitleUpperCasePreference =
|
||||
when (value) {
|
||||
true -> ReadingTitleUpperCasePreference.OFF
|
||||
false -> ReadingTitleUpperCasePreference.ON
|
||||
}
|
|
@ -12,6 +12,7 @@ import me.ash.reader.ui.ext.collectAsStateValue
|
|||
import me.ash.reader.ui.ext.dataStore
|
||||
|
||||
data class Settings(
|
||||
// Version
|
||||
val newVersionNumber: Version = NewVersionNumberPreference.default,
|
||||
val skipVersionNumber: Version = SkipVersionNumberPreference.default,
|
||||
val newVersionPublishDate: String = NewVersionPublishDatePreference.default,
|
||||
|
@ -19,11 +20,13 @@ data class Settings(
|
|||
val newVersionSize: String = NewVersionSizePreference.default,
|
||||
val newVersionDownloadUrl: String = NewVersionDownloadUrlPreference.default,
|
||||
|
||||
// Theme
|
||||
val themeIndex: Int = ThemeIndexPreference.default,
|
||||
val customPrimaryColor: String = CustomPrimaryColorPreference.default,
|
||||
val darkTheme: DarkThemePreference = DarkThemePreference.default,
|
||||
val amoledDarkTheme: AmoledDarkThemePreference = AmoledDarkThemePreference.default,
|
||||
|
||||
// Feeds page
|
||||
val feedsFilterBarStyle: FeedsFilterBarStylePreference = FeedsFilterBarStylePreference.default,
|
||||
val feedsFilterBarFilled: FeedsFilterBarFilledPreference = FeedsFilterBarFilledPreference.default,
|
||||
val feedsFilterBarPadding: Int = FeedsFilterBarPaddingPreference.default,
|
||||
|
@ -32,6 +35,7 @@ data class Settings(
|
|||
val feedsGroupListExpand: FeedsGroupListExpandPreference = FeedsGroupListExpandPreference.default,
|
||||
val feedsGroupListTonalElevation: FeedsGroupListTonalElevationPreference = FeedsGroupListTonalElevationPreference.default,
|
||||
|
||||
// Flow page
|
||||
val flowFilterBarStyle: FlowFilterBarStylePreference = FlowFilterBarStylePreference.default,
|
||||
val flowFilterBarFilled: FlowFilterBarFilledPreference = FlowFilterBarFilledPreference.default,
|
||||
val flowFilterBarPadding: Int = FlowFilterBarPaddingPreference.default,
|
||||
|
@ -45,67 +49,36 @@ data class Settings(
|
|||
val flowArticleListDateStickyHeader: FlowArticleListDateStickyHeaderPreference = FlowArticleListDateStickyHeaderPreference.default,
|
||||
val flowArticleListTonalElevation: FlowArticleListTonalElevationPreference = FlowArticleListTonalElevationPreference.default,
|
||||
|
||||
// Reading page
|
||||
val readingTheme: ReadingThemePreference = ReadingThemePreference.default,
|
||||
val readingDarkTheme: ReadingDarkThemePreference = ReadingDarkThemePreference.default,
|
||||
val readingPageTonalElevation: ReadingPageTonalElevationPreference = ReadingPageTonalElevationPreference.default,
|
||||
val readingAutoHideToolbar: ReadingAutoHideToolbarPreference = ReadingAutoHideToolbarPreference.default,
|
||||
val readingTextFontSize: Int = ReadingTextFontSizePreference.default,
|
||||
val readingLetterSpacing: Double = ReadingLetterSpacingPreference.default,
|
||||
val readingTextHorizontalPadding: Int = ReadingTextHorizontalPaddingPreference.default,
|
||||
val readingTextAlign: ReadingTextAlignPreference = ReadingTextAlignPreference.default,
|
||||
val readingTextBold: ReadingTextBoldPreference = ReadingTextBoldPreference.default,
|
||||
val readingTitleAlign: ReadingTitleAlignPreference = ReadingTitleAlignPreference.default,
|
||||
val readingSubheadAlign: ReadingSubheadAlignPreference = ReadingSubheadAlignPreference.default,
|
||||
val readingFonts: ReadingFontsPreference = ReadingFontsPreference.default,
|
||||
val readingTitleBold: ReadingTitleBoldPreference = ReadingTitleBoldPreference.default,
|
||||
val readingSubheadBold: ReadingSubheadBoldPreference = ReadingSubheadBoldPreference.default,
|
||||
val readingTitleUpperCase: ReadingTitleUpperCasePreference = ReadingTitleUpperCasePreference.default,
|
||||
val readingSubheadUpperCase: ReadingSubheadUpperCasePreference = ReadingSubheadUpperCasePreference.default,
|
||||
val readingImageHorizontalPadding: Int = ReadingImageHorizontalPaddingPreference.default,
|
||||
val readingImageRoundedCorners: Int = ReadingImageRoundedCornersPreference.default,
|
||||
val readingImageMaximize: ReadingImageMaximizePreference = ReadingImageMaximizePreference.default,
|
||||
|
||||
// Interaction
|
||||
val initialPage: InitialPagePreference = InitialPagePreference.default,
|
||||
val initialFilter: InitialFilterPreference = InitialFilterPreference.default,
|
||||
|
||||
// Languages
|
||||
val languages: LanguagesPreference = LanguagesPreference.default,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun SettingsProvider(
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val settings = remember {
|
||||
context.dataStore.data.map {
|
||||
Log.i("RLog", "AppTheme: ${it}")
|
||||
it.toSettings()
|
||||
}
|
||||
}.collectAsStateValue(initial = Settings())
|
||||
|
||||
CompositionLocalProvider(
|
||||
LocalNewVersionNumber provides settings.newVersionNumber,
|
||||
LocalSkipVersionNumber provides settings.skipVersionNumber,
|
||||
LocalNewVersionPublishDate provides settings.newVersionPublishDate,
|
||||
LocalNewVersionLog provides settings.newVersionLog,
|
||||
LocalNewVersionSize provides settings.newVersionSize,
|
||||
LocalNewVersionDownloadUrl provides settings.newVersionDownloadUrl,
|
||||
|
||||
LocalThemeIndex provides settings.themeIndex,
|
||||
LocalCustomPrimaryColor provides settings.customPrimaryColor,
|
||||
LocalDarkTheme provides settings.darkTheme,
|
||||
LocalAmoledDarkTheme provides settings.amoledDarkTheme,
|
||||
|
||||
LocalFeedsTopBarTonalElevation provides settings.feedsTopBarTonalElevation,
|
||||
LocalFeedsGroupListExpand provides settings.feedsGroupListExpand,
|
||||
LocalFeedsGroupListTonalElevation provides settings.feedsGroupListTonalElevation,
|
||||
LocalFeedsFilterBarStyle provides settings.feedsFilterBarStyle,
|
||||
LocalFeedsFilterBarFilled provides settings.feedsFilterBarFilled,
|
||||
LocalFeedsFilterBarPadding provides settings.feedsFilterBarPadding,
|
||||
LocalFeedsFilterBarTonalElevation provides settings.feedsFilterBarTonalElevation,
|
||||
|
||||
LocalFlowTopBarTonalElevation provides settings.flowTopBarTonalElevation,
|
||||
LocalFlowArticleListFeedIcon provides settings.flowArticleListFeedIcon,
|
||||
LocalFlowArticleListFeedName provides settings.flowArticleListFeedName,
|
||||
LocalFlowArticleListImage provides settings.flowArticleListImage,
|
||||
LocalFlowArticleListDesc provides settings.flowArticleListDesc,
|
||||
LocalFlowArticleListTime provides settings.flowArticleListTime,
|
||||
LocalFlowArticleListDateStickyHeader provides settings.flowArticleListDateStickyHeader,
|
||||
LocalFlowArticleListTonalElevation provides settings.flowArticleListTonalElevation,
|
||||
LocalFlowFilterBarStyle provides settings.flowFilterBarStyle,
|
||||
LocalFlowFilterBarFilled provides settings.flowFilterBarFilled,
|
||||
LocalFlowFilterBarPadding provides settings.flowFilterBarPadding,
|
||||
LocalFlowFilterBarTonalElevation provides settings.flowFilterBarTonalElevation,
|
||||
|
||||
LocalInitialPage provides settings.initialPage,
|
||||
LocalInitialFilter provides settings.initialFilter,
|
||||
|
||||
LocalLanguages provides settings.languages,
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
// Version
|
||||
val LocalNewVersionNumber = compositionLocalOf { NewVersionNumberPreference.default }
|
||||
val LocalSkipVersionNumber = compositionLocalOf { SkipVersionNumberPreference.default }
|
||||
val LocalNewVersionPublishDate = compositionLocalOf { NewVersionPublishDatePreference.default }
|
||||
|
@ -113,6 +86,7 @@ val LocalNewVersionLog = compositionLocalOf { NewVersionLogPreference.default }
|
|||
val LocalNewVersionSize = compositionLocalOf { NewVersionSizePreference.default }
|
||||
val LocalNewVersionDownloadUrl = compositionLocalOf { NewVersionDownloadUrlPreference.default }
|
||||
|
||||
// Theme
|
||||
val LocalThemeIndex =
|
||||
compositionLocalOf { ThemeIndexPreference.default }
|
||||
val LocalCustomPrimaryColor =
|
||||
|
@ -122,6 +96,7 @@ val LocalDarkTheme =
|
|||
val LocalAmoledDarkTheme =
|
||||
compositionLocalOf<AmoledDarkThemePreference> { AmoledDarkThemePreference.default }
|
||||
|
||||
// Feeds page
|
||||
val LocalFeedsFilterBarStyle =
|
||||
compositionLocalOf<FeedsFilterBarStylePreference> { FeedsFilterBarStylePreference.default }
|
||||
val LocalFeedsFilterBarFilled =
|
||||
|
@ -137,6 +112,7 @@ val LocalFeedsGroupListExpand =
|
|||
val LocalFeedsGroupListTonalElevation =
|
||||
compositionLocalOf<FeedsGroupListTonalElevationPreference> { FeedsGroupListTonalElevationPreference.default }
|
||||
|
||||
// Flow page
|
||||
val LocalFlowFilterBarStyle =
|
||||
compositionLocalOf<FlowFilterBarStylePreference> { FlowFilterBarStylePreference.default }
|
||||
val LocalFlowFilterBarFilled =
|
||||
|
@ -162,9 +138,119 @@ val LocalFlowArticleListDateStickyHeader =
|
|||
val LocalFlowArticleListTonalElevation =
|
||||
compositionLocalOf<FlowArticleListTonalElevationPreference> { FlowArticleListTonalElevationPreference.default }
|
||||
|
||||
// Reading page
|
||||
val LocalReadingTheme = compositionLocalOf<ReadingThemePreference> { ReadingThemePreference.default }
|
||||
val LocalReadingDarkTheme = compositionLocalOf<ReadingDarkThemePreference> { ReadingDarkThemePreference.default }
|
||||
val LocalReadingPageTonalElevation = compositionLocalOf<ReadingPageTonalElevationPreference> { ReadingPageTonalElevationPreference.default }
|
||||
val LocalReadingAutoHideToolbar = compositionLocalOf<ReadingAutoHideToolbarPreference> { ReadingAutoHideToolbarPreference.default }
|
||||
val LocalReadingTextFontSize = compositionLocalOf { ReadingTextFontSizePreference.default }
|
||||
val LocalReadingLetterSpacing = compositionLocalOf { ReadingLetterSpacingPreference.default }
|
||||
val LocalReadingTextHorizontalPadding = compositionLocalOf { ReadingTextHorizontalPaddingPreference.default }
|
||||
val LocalReadingTextAlign = compositionLocalOf<ReadingTextAlignPreference> { ReadingTextAlignPreference.default }
|
||||
val LocalReadingTextBold = compositionLocalOf<ReadingTextBoldPreference> { ReadingTextBoldPreference.default }
|
||||
val LocalReadingTitleAlign = compositionLocalOf<ReadingTitleAlignPreference> { ReadingTitleAlignPreference.default }
|
||||
val LocalReadingSubheadAlign =
|
||||
compositionLocalOf<ReadingSubheadAlignPreference> { ReadingSubheadAlignPreference.default }
|
||||
val LocalReadingFonts = compositionLocalOf<ReadingFontsPreference> { ReadingFontsPreference.default }
|
||||
val LocalReadingTitleBold = compositionLocalOf<ReadingTitleBoldPreference> { ReadingTitleBoldPreference.default }
|
||||
val LocalReadingSubheadBold =
|
||||
compositionLocalOf<ReadingSubheadBoldPreference> { ReadingSubheadBoldPreference.default }
|
||||
val LocalReadingTitleUpperCase =
|
||||
compositionLocalOf<ReadingTitleUpperCasePreference> { ReadingTitleUpperCasePreference.default }
|
||||
val LocalReadingSubheadUpperCase =
|
||||
compositionLocalOf<ReadingSubheadUpperCasePreference> { ReadingSubheadUpperCasePreference.default }
|
||||
val LocalReadingImageHorizontalPadding = compositionLocalOf { ReadingImageHorizontalPaddingPreference.default }
|
||||
val LocalReadingImageRoundedCorners = compositionLocalOf { ReadingImageRoundedCornersPreference.default }
|
||||
val LocalReadingImageMaximize = compositionLocalOf<ReadingImageMaximizePreference> { ReadingImageMaximizePreference.default }
|
||||
|
||||
// Interaction
|
||||
val LocalInitialPage = compositionLocalOf<InitialPagePreference> { InitialPagePreference.default }
|
||||
val LocalInitialFilter =
|
||||
compositionLocalOf<InitialFilterPreference> { InitialFilterPreference.default }
|
||||
|
||||
// Languages
|
||||
val LocalLanguages =
|
||||
compositionLocalOf<LanguagesPreference> { LanguagesPreference.default }
|
||||
|
||||
@Composable
|
||||
fun SettingsProvider(
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val settings = remember {
|
||||
context.dataStore.data.map {
|
||||
Log.i("RLog", "AppTheme: ${it}")
|
||||
it.toSettings()
|
||||
}
|
||||
}.collectAsStateValue(initial = Settings())
|
||||
|
||||
CompositionLocalProvider(
|
||||
// Version
|
||||
LocalNewVersionNumber provides settings.newVersionNumber,
|
||||
LocalSkipVersionNumber provides settings.skipVersionNumber,
|
||||
LocalNewVersionPublishDate provides settings.newVersionPublishDate,
|
||||
LocalNewVersionLog provides settings.newVersionLog,
|
||||
LocalNewVersionSize provides settings.newVersionSize,
|
||||
LocalNewVersionDownloadUrl provides settings.newVersionDownloadUrl,
|
||||
|
||||
// Theme
|
||||
LocalThemeIndex provides settings.themeIndex,
|
||||
LocalCustomPrimaryColor provides settings.customPrimaryColor,
|
||||
LocalDarkTheme provides settings.darkTheme,
|
||||
LocalAmoledDarkTheme provides settings.amoledDarkTheme,
|
||||
|
||||
// Feeds page
|
||||
LocalFeedsTopBarTonalElevation provides settings.feedsTopBarTonalElevation,
|
||||
LocalFeedsGroupListExpand provides settings.feedsGroupListExpand,
|
||||
LocalFeedsGroupListTonalElevation provides settings.feedsGroupListTonalElevation,
|
||||
LocalFeedsFilterBarStyle provides settings.feedsFilterBarStyle,
|
||||
LocalFeedsFilterBarFilled provides settings.feedsFilterBarFilled,
|
||||
LocalFeedsFilterBarPadding provides settings.feedsFilterBarPadding,
|
||||
LocalFeedsFilterBarTonalElevation provides settings.feedsFilterBarTonalElevation,
|
||||
|
||||
// Flow page
|
||||
LocalFlowTopBarTonalElevation provides settings.flowTopBarTonalElevation,
|
||||
LocalFlowArticleListFeedIcon provides settings.flowArticleListFeedIcon,
|
||||
LocalFlowArticleListFeedName provides settings.flowArticleListFeedName,
|
||||
LocalFlowArticleListImage provides settings.flowArticleListImage,
|
||||
LocalFlowArticleListDesc provides settings.flowArticleListDesc,
|
||||
LocalFlowArticleListTime provides settings.flowArticleListTime,
|
||||
LocalFlowArticleListDateStickyHeader provides settings.flowArticleListDateStickyHeader,
|
||||
LocalFlowArticleListTonalElevation provides settings.flowArticleListTonalElevation,
|
||||
LocalFlowFilterBarStyle provides settings.flowFilterBarStyle,
|
||||
LocalFlowFilterBarFilled provides settings.flowFilterBarFilled,
|
||||
LocalFlowFilterBarPadding provides settings.flowFilterBarPadding,
|
||||
LocalFlowFilterBarTonalElevation provides settings.flowFilterBarTonalElevation,
|
||||
|
||||
// Reading page
|
||||
LocalReadingTheme provides settings.readingTheme,
|
||||
LocalReadingDarkTheme provides settings.readingDarkTheme,
|
||||
LocalReadingPageTonalElevation provides settings.readingPageTonalElevation,
|
||||
LocalReadingAutoHideToolbar provides settings.readingAutoHideToolbar,
|
||||
LocalReadingTextFontSize provides settings.readingTextFontSize,
|
||||
LocalReadingLetterSpacing provides settings.readingLetterSpacing,
|
||||
LocalReadingTextHorizontalPadding provides settings.readingTextHorizontalPadding,
|
||||
LocalReadingTextAlign provides settings.readingTextAlign,
|
||||
LocalReadingTextBold provides settings.readingTextBold,
|
||||
LocalReadingTitleAlign provides settings.readingTitleAlign,
|
||||
LocalReadingSubheadAlign provides settings.readingSubheadAlign,
|
||||
LocalReadingFonts provides settings.readingFonts,
|
||||
LocalReadingTitleBold provides settings.readingTitleBold,
|
||||
LocalReadingSubheadBold provides settings.readingSubheadBold,
|
||||
LocalReadingTitleUpperCase provides settings.readingTitleUpperCase,
|
||||
LocalReadingSubheadUpperCase provides settings.readingSubheadUpperCase,
|
||||
LocalReadingImageHorizontalPadding provides settings.readingImageHorizontalPadding,
|
||||
LocalReadingImageRoundedCorners provides settings.readingImageRoundedCorners,
|
||||
LocalReadingImageMaximize provides settings.readingImageMaximize,
|
||||
|
||||
// Interaction
|
||||
LocalInitialPage provides settings.initialPage,
|
||||
LocalInitialFilter provides settings.initialFilter,
|
||||
|
||||
// Languages
|
||||
LocalLanguages provides settings.languages,
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
168
app/src/main/java/me/ash/reader/ui/component/ReadingThemePrev.kt
Normal file
168
app/src/main/java/me/ash/reader/ui/component/ReadingThemePrev.kt
Normal file
|
@ -0,0 +1,168 @@
|
|||
package me.ash.reader.ui.component
|
||||
|
||||
import androidx.compose.animation.core.animateDpAsState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.ash.reader.data.model.preference.LocalReadingImageHorizontalPadding
|
||||
import me.ash.reader.data.model.preference.LocalReadingImageRoundedCorners
|
||||
import me.ash.reader.data.model.preference.LocalReadingTextAlign
|
||||
import me.ash.reader.data.model.preference.ReadingThemePreference
|
||||
import me.ash.reader.ui.theme.Shape24
|
||||
import me.ash.reader.ui.theme.palette.onDark
|
||||
import me.ash.reader.ui.theme.palette.onLight
|
||||
|
||||
@Composable
|
||||
fun ReadingThemePrev(
|
||||
selected: ReadingThemePreference = ReadingThemePreference.MaterialYou,
|
||||
theme: ReadingThemePreference = ReadingThemePreference.MaterialYou,
|
||||
onClick: () -> Unit = {},
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val imageRoundedCorners = LocalReadingImageRoundedCorners.current
|
||||
val roundedCorners by remember { mutableStateOf(RoundedCornerShape((imageRoundedCorners / 2).dp)) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.width(150.dp)
|
||||
.clip(Shape24)
|
||||
.background(MaterialTheme.colorScheme.inverseOnSurface
|
||||
onLight MaterialTheme.colorScheme.surface
|
||||
)
|
||||
.border(
|
||||
width = animateDpAsState(if (selected == theme) 4.dp else (-1).dp).value,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
shape = Shape24
|
||||
)
|
||||
.clickable(onClick = onClick),
|
||||
horizontalAlignment = when (theme) {
|
||||
ReadingThemePreference.MaterialYou -> Alignment.Start
|
||||
ReadingThemePreference.Reeder -> Alignment.Start
|
||||
ReadingThemePreference.Paper -> Alignment.CenterHorizontally
|
||||
ReadingThemePreference.Custom -> LocalReadingTextAlign.current.toAlignment()
|
||||
}
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(22.dp))
|
||||
// Header
|
||||
Text(
|
||||
modifier = Modifier.padding(horizontal = 12.dp),
|
||||
text = theme.toDesc(context),
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(2.dp))
|
||||
// Metadata
|
||||
Box(modifier = Modifier
|
||||
.padding(horizontal = 12.dp)
|
||||
.size(width = 32.dp, height = 4.dp)
|
||||
.clip(CircleShape)
|
||||
.background(MaterialTheme.colorScheme.tertiaryContainer)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
// Paragraph
|
||||
Box(modifier = Modifier
|
||||
.padding(horizontal = 12.dp)
|
||||
.fillMaxWidth()
|
||||
.height(12.dp)
|
||||
.clip(CircleShape)
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Row(modifier = Modifier
|
||||
.padding(horizontal = 12.dp)
|
||||
.width(114.dp)
|
||||
.height(12.dp)
|
||||
) {
|
||||
Box(modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxSize()
|
||||
.clip(CircleShape)
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant)
|
||||
)
|
||||
Box(modifier = Modifier
|
||||
.padding(start = 4.dp)
|
||||
.weight(2f)
|
||||
.fillMaxSize()
|
||||
.clip(CircleShape)
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
// Image
|
||||
Box(modifier = Modifier
|
||||
.padding(horizontal = when (theme) {
|
||||
ReadingThemePreference.MaterialYou -> 12.dp
|
||||
ReadingThemePreference.Reeder -> 0.dp
|
||||
ReadingThemePreference.Paper -> 12.dp
|
||||
ReadingThemePreference.Custom -> (LocalReadingImageHorizontalPadding.current / 2).dp
|
||||
})
|
||||
.fillMaxWidth()
|
||||
.height(46.dp)
|
||||
.clip(when (theme) {
|
||||
ReadingThemePreference.MaterialYou -> MaterialTheme.shapes.medium
|
||||
ReadingThemePreference.Reeder -> RectangleShape
|
||||
ReadingThemePreference.Paper -> RectangleShape
|
||||
ReadingThemePreference.Custom -> roundedCorners
|
||||
})
|
||||
.background(MaterialTheme.colorScheme.primaryContainer onDark MaterialTheme.colorScheme.secondaryContainer)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
// Footer
|
||||
Box(modifier = Modifier
|
||||
.padding(horizontal = 12.dp)
|
||||
.width(100.dp)
|
||||
.height(12.dp)
|
||||
.clip(CircleShape)
|
||||
.background(MaterialTheme.colorScheme.surfaceVariant)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(14.dp))
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ReadYouPreview() {
|
||||
ReadingThemePrev(
|
||||
selected = ReadingThemePreference.MaterialYou,
|
||||
theme = ReadingThemePreference.MaterialYou,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun ReederPreview() {
|
||||
ReadingThemePrev(
|
||||
theme = ReadingThemePreference.Reeder,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun PaperPreview() {
|
||||
ReadingThemePrev(
|
||||
theme = ReadingThemePreference.Paper,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
private fun CustomPreview() {
|
||||
ReadingThemePrev(
|
||||
theme = ReadingThemePreference.Custom,
|
||||
)
|
||||
}
|
|
@ -16,6 +16,7 @@ import androidx.compose.runtime.Immutable
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.BaselineShift
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
@ -63,7 +64,7 @@ fun RadioDialog(
|
|||
text = option.text,
|
||||
style = MaterialTheme.typography.bodyLarge.copy(
|
||||
baselineShift = BaselineShift.None
|
||||
),
|
||||
).merge(other = option.style),
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
}
|
||||
|
@ -78,6 +79,7 @@ fun RadioDialog(
|
|||
@Immutable
|
||||
data class RadioDialogOption(
|
||||
val text: String = "",
|
||||
val style: TextStyle? = null,
|
||||
val selected: Boolean = false,
|
||||
val onClick: () -> Unit = {},
|
||||
)
|
|
@ -33,6 +33,7 @@ import androidx.compose.foundation.text.selection.DisableSelection
|
|||
import androidx.compose.material.Text
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
|
@ -51,6 +52,7 @@ import coil.size.Precision
|
|||
import coil.size.Size
|
||||
import coil.size.pxOrElse
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.model.preference.LocalReadingImageMaximize
|
||||
import me.ash.reader.ui.component.base.RYAsyncImage
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.helper.StringUtil
|
||||
|
@ -63,6 +65,7 @@ import kotlin.math.roundToInt
|
|||
|
||||
fun LazyListScope.htmlFormattedText(
|
||||
inputStream: InputStream,
|
||||
subheadUpperCase: Boolean = false,
|
||||
baseUrl: String,
|
||||
@DrawableRes imagePlaceholder: Int,
|
||||
onLinkClick: (String) -> Unit,
|
||||
|
@ -72,6 +75,7 @@ fun LazyListScope.htmlFormattedText(
|
|||
?.let { body ->
|
||||
formatBody(
|
||||
element = body,
|
||||
subheadUpperCase = subheadUpperCase,
|
||||
imagePlaceholder = imagePlaceholder,
|
||||
onLinkClick = onLinkClick,
|
||||
baseUrl = baseUrl,
|
||||
|
@ -81,6 +85,7 @@ fun LazyListScope.htmlFormattedText(
|
|||
|
||||
private fun LazyListScope.formatBody(
|
||||
element: Element,
|
||||
subheadUpperCase: Boolean = false,
|
||||
@DrawableRes imagePlaceholder: Int,
|
||||
onLinkClick: (String) -> Unit,
|
||||
baseUrl: String,
|
||||
|
@ -98,7 +103,7 @@ private fun LazyListScope.formatBody(
|
|||
text = paragraph,
|
||||
style = bodyStyle(),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = PADDING_HORIZONTAL.dp)
|
||||
.padding(horizontal = textHorizontalPadding().dp)
|
||||
.width(MAX_CONTENT_WIDTH.dp)
|
||||
) { offset ->
|
||||
paragraph.getStringAnnotations("URL", offset, offset)
|
||||
|
@ -112,7 +117,7 @@ private fun LazyListScope.formatBody(
|
|||
text = paragraph,
|
||||
style = bodyStyle(),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = PADDING_HORIZONTAL.dp)
|
||||
.padding(horizontal = textHorizontalPadding().dp)
|
||||
.width(MAX_CONTENT_WIDTH.dp)
|
||||
)
|
||||
}
|
||||
|
@ -121,6 +126,7 @@ private fun LazyListScope.formatBody(
|
|||
|
||||
composer.appendTextChildren(
|
||||
element.childNodes(),
|
||||
subheadUpperCase = subheadUpperCase,
|
||||
lazyListScope = this,
|
||||
imagePlaceholder = imagePlaceholder,
|
||||
onLinkClick = onLinkClick,
|
||||
|
@ -144,7 +150,7 @@ private fun LazyListScope.formatCodeBlock(
|
|||
color = codeBlockBackground(),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = PADDING_HORIZONTAL.dp),
|
||||
.padding(horizontal = textHorizontalPadding().dp),
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
@ -179,6 +185,7 @@ private fun LazyListScope.formatCodeBlock(
|
|||
private fun TextComposer.appendTextChildren(
|
||||
nodes: List<Node>,
|
||||
preFormatted: Boolean = false,
|
||||
subheadUpperCase: Boolean = false,
|
||||
lazyListScope: LazyListScope,
|
||||
@DrawableRes imagePlaceholder: Int,
|
||||
onLinkClick: (String) -> Unit,
|
||||
|
@ -238,9 +245,9 @@ private fun TextComposer.appendTextChildren(
|
|||
"h1" -> {
|
||||
withParagraph {
|
||||
withComposableStyle(
|
||||
style = { h5Style().toSpanStyle() }
|
||||
style = { h1Style().toSpanStyle() }
|
||||
) {
|
||||
append("\n${element.text()}")
|
||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -248,9 +255,9 @@ private fun TextComposer.appendTextChildren(
|
|||
"h2" -> {
|
||||
withParagraph {
|
||||
withComposableStyle(
|
||||
style = { h5Style().toSpanStyle() }
|
||||
style = { h2Style().toSpanStyle() }
|
||||
) {
|
||||
append("\n${element.text()}")
|
||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -258,9 +265,9 @@ private fun TextComposer.appendTextChildren(
|
|||
"h3" -> {
|
||||
withParagraph {
|
||||
withComposableStyle(
|
||||
style = { h5Style().toSpanStyle() }
|
||||
style = { h3Style().toSpanStyle() }
|
||||
) {
|
||||
append("\n${element.text()}")
|
||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -268,9 +275,9 @@ private fun TextComposer.appendTextChildren(
|
|||
"h4" -> {
|
||||
withParagraph {
|
||||
withComposableStyle(
|
||||
style = { h5Style().toSpanStyle() }
|
||||
style = { h4Style().toSpanStyle() }
|
||||
) {
|
||||
append("\n${element.text()}")
|
||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -280,7 +287,7 @@ private fun TextComposer.appendTextChildren(
|
|||
withComposableStyle(
|
||||
style = { h5Style().toSpanStyle() }
|
||||
) {
|
||||
append("\n${element.text()}")
|
||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,15 +295,17 @@ private fun TextComposer.appendTextChildren(
|
|||
"h6" -> {
|
||||
withParagraph {
|
||||
withComposableStyle(
|
||||
style = { h5Style().toSpanStyle() }
|
||||
style = { h6Style().toSpanStyle() }
|
||||
) {
|
||||
append("\n${element.text()}")
|
||||
append("\n${if (subheadUpperCase) element.text().uppercase() else element.text()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"strong", "b" -> {
|
||||
withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
|
||||
withComposableStyle(
|
||||
style = { boldStyle().toSpanStyle() }
|
||||
) {
|
||||
appendTextChildren(
|
||||
element.childNodes(),
|
||||
lazyListScope = lazyListScope,
|
||||
|
@ -419,8 +428,11 @@ private fun TextComposer.appendTextChildren(
|
|||
|
||||
"blockquote" -> {
|
||||
withParagraph {
|
||||
withComposableStyle(
|
||||
style = { blockQuoteStyle() }
|
||||
withStyle(
|
||||
SpanStyle(
|
||||
fontStyle = FontStyle.Italic,
|
||||
fontWeight = FontWeight.Light,
|
||||
)
|
||||
) {
|
||||
appendTextChildren(
|
||||
element.childNodes(),
|
||||
|
@ -458,10 +470,10 @@ private fun TextComposer.appendTextChildren(
|
|||
// val scale = remember { mutableStateOf(1f) }
|
||||
Column(
|
||||
modifier = Modifier
|
||||
// .padding(horizontal = PADDING_HORIZONTAL.dp)
|
||||
// .padding(horizontal = horizontalPadding().dp)
|
||||
.width(MAX_CONTENT_WIDTH.dp)
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(PADDING_HORIZONTAL.dp))
|
||||
Spacer(modifier = Modifier.height(textHorizontalPadding().dp))
|
||||
DisableSelection {
|
||||
BoxWithConstraints(
|
||||
modifier = Modifier
|
||||
|
@ -487,9 +499,10 @@ private fun TextComposer.appendTextChildren(
|
|||
val imageSize = maxImageSize()
|
||||
RYAsyncImage(
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = PADDING_HORIZONTAL.dp)
|
||||
.clip(IMAGE_SHAPE)
|
||||
.padding(horizontal = imageHorizontalPadding().dp)
|
||||
.clip(imageShape())
|
||||
.clickable { },
|
||||
data = imageCandidates.getBestImageForMaxSize(
|
||||
pixelDensity = pixelDensity(),
|
||||
|
@ -498,24 +511,24 @@ private fun TextComposer.appendTextChildren(
|
|||
contentDescription = alt,
|
||||
size = imageSize,
|
||||
precision = Precision.INEXACT,
|
||||
contentScale = ContentScale.FillWidth,
|
||||
contentScale = if (LocalReadingImageMaximize.current.value) ContentScale.FillWidth else ContentScale.Inside,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (alt.isNotBlank()) {
|
||||
Spacer(modifier = Modifier.height(PADDING_HORIZONTAL.dp / 2))
|
||||
Spacer(modifier = Modifier.height(textHorizontalPadding().dp / 2))
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = PADDING_HORIZONTAL.dp),
|
||||
.padding(horizontal = textHorizontalPadding().dp),
|
||||
text = alt,
|
||||
style = captionStyle(),
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(PADDING_HORIZONTAL.dp))
|
||||
Spacer(modifier = Modifier.height(textHorizontalPadding().dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -528,7 +541,7 @@ private fun TextComposer.appendTextChildren(
|
|||
.forEach { listItem ->
|
||||
withParagraph {
|
||||
// no break space
|
||||
append("• ")
|
||||
append(" • ")
|
||||
appendTextChildren(
|
||||
listItem.childNodes(),
|
||||
lazyListScope = lazyListScope,
|
||||
|
@ -612,7 +625,7 @@ private fun TextComposer.appendTextChildren(
|
|||
lazyListScope.item {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = PADDING_HORIZONTAL.dp)
|
||||
.padding(horizontal = textHorizontalPadding().dp)
|
||||
.width(MAX_CONTENT_WIDTH.dp)
|
||||
) {
|
||||
DisableSelection {
|
||||
|
@ -622,8 +635,8 @@ private fun TextComposer.appendTextChildren(
|
|||
RYAsyncImage(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = PADDING_HORIZONTAL.dp)
|
||||
.clip(IMAGE_SHAPE)
|
||||
.padding(horizontal = imageHorizontalPadding().dp)
|
||||
.clip(imageShape())
|
||||
.clickable {
|
||||
onLinkClick(video.link)
|
||||
},
|
||||
|
@ -636,17 +649,17 @@ private fun TextComposer.appendTextChildren(
|
|||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(PADDING_HORIZONTAL.dp / 2))
|
||||
Spacer(modifier = Modifier.height(textHorizontalPadding().dp / 2))
|
||||
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = PADDING_HORIZONTAL.dp),
|
||||
.padding(horizontal = textHorizontalPadding().dp),
|
||||
text = stringResource(R.string.touch_to_play_video),
|
||||
style = captionStyle(),
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(PADDING_HORIZONTAL.dp))
|
||||
Spacer(modifier = Modifier.height(textHorizontalPadding().dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -661,6 +674,7 @@ private fun TextComposer.appendTextChildren(
|
|||
appendTextChildren(
|
||||
nodes = element.childNodes(),
|
||||
preFormatted = preFormatted,
|
||||
subheadUpperCase = subheadUpperCase,
|
||||
lazyListScope = lazyListScope,
|
||||
imagePlaceholder = imagePlaceholder,
|
||||
onLinkClick = onLinkClick,
|
||||
|
|
|
@ -30,12 +30,14 @@ import me.ash.reader.R
|
|||
@Suppress("FunctionName")
|
||||
fun LazyListScope.Reader(
|
||||
context: Context,
|
||||
subheadUpperCase: Boolean = false,
|
||||
link: String,
|
||||
content: String,
|
||||
) {
|
||||
Log.i("RLog", "Reader: ")
|
||||
htmlFormattedText(
|
||||
inputStream = content.byteInputStream(),
|
||||
subheadUpperCase = subheadUpperCase,
|
||||
baseUrl = link,
|
||||
imagePlaceholder = R.drawable.ic_launcher_foreground,
|
||||
onLinkClick = {
|
||||
|
|
|
@ -23,6 +23,8 @@ package me.ash.reader.ui.component.reader
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
|
@ -31,79 +33,162 @@ import androidx.compose.ui.text.font.FontWeight
|
|||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import me.ash.reader.data.model.preference.*
|
||||
import me.ash.reader.ui.ext.alphaLN
|
||||
|
||||
const val PADDING_HORIZONTAL = 24.0
|
||||
const val MAX_CONTENT_WIDTH = 840.0
|
||||
val IMAGE_SHAPE = RoundedCornerShape(32.dp)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
fun bodyForeground(): Color =
|
||||
@ReadOnlyComposable
|
||||
fun imageHorizontalPadding(): Int =
|
||||
LocalReadingImageHorizontalPadding.current
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun imageShape(): RoundedCornerShape =
|
||||
RoundedCornerShape(LocalReadingImageRoundedCorners.current.dp)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun onSurfaceColor(): Color =
|
||||
MaterialTheme.colorScheme.onSurface
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun onSurfaceVariantColor(): Color =
|
||||
MaterialTheme.colorScheme.onSurfaceVariant
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun textHorizontalPadding(): Int =
|
||||
LocalReadingTextHorizontalPadding.current
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun bodyForeground(): Color = onSurfaceVariantColor()
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun bodyStyle(): TextStyle =
|
||||
MaterialTheme.typography.bodyLarge.copy(
|
||||
TextStyle(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(),
|
||||
fontWeight = if (LocalReadingTextBold.current.value) FontWeight.SemiBold else FontWeight.Normal,
|
||||
fontSize = LocalReadingTextFontSize.current.sp,
|
||||
letterSpacing = LocalReadingLetterSpacing.current.sp,
|
||||
color = bodyForeground(),
|
||||
textAlign = TextAlign.Start,
|
||||
textAlign = LocalReadingTextAlign.current.toTextAlign(),
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun h1Style(): TextStyle =
|
||||
MaterialTheme.typography.displayMedium.copy(
|
||||
color = bodyForeground(),
|
||||
textAlign = TextAlign.Start,
|
||||
TextStyle(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(isDisplay = true),
|
||||
fontWeight = if (LocalReadingSubheadBold.current.value) FontWeight.SemiBold else FontWeight.Normal,
|
||||
fontSize = 28.sp,
|
||||
letterSpacing = 0.sp,
|
||||
color = onSurfaceColor(),
|
||||
textAlign = LocalReadingSubheadAlign.current.toTextAlign(),
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun h2Style(): TextStyle =
|
||||
MaterialTheme.typography.displaySmall.copy(
|
||||
color = bodyForeground(),
|
||||
textAlign = TextAlign.Start,
|
||||
TextStyle(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(isDisplay = true),
|
||||
fontWeight = if (LocalReadingSubheadBold.current.value) FontWeight.SemiBold else FontWeight.Normal,
|
||||
fontSize = 28.sp,
|
||||
letterSpacing = 0.sp,
|
||||
color = onSurfaceColor(),
|
||||
textAlign = LocalReadingSubheadAlign.current.toTextAlign(),
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun h3Style(): TextStyle =
|
||||
MaterialTheme.typography.headlineLarge.copy(
|
||||
color = bodyForeground(),
|
||||
textAlign = TextAlign.Start,
|
||||
TextStyle(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(isDisplay = true),
|
||||
fontWeight = if (LocalReadingSubheadBold.current.value) FontWeight.SemiBold else FontWeight.Normal,
|
||||
fontSize = 19.sp,
|
||||
letterSpacing = 0.sp,
|
||||
color = onSurfaceColor(),
|
||||
textAlign = LocalReadingSubheadAlign.current.toTextAlign(),
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun h4Style(): TextStyle =
|
||||
MaterialTheme.typography.headlineMedium.copy(
|
||||
color = bodyForeground(),
|
||||
textAlign = TextAlign.Start,
|
||||
TextStyle(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(isDisplay = true),
|
||||
fontWeight = if (LocalReadingSubheadBold.current.value) FontWeight.SemiBold else FontWeight.Normal,
|
||||
fontSize = 17.sp,
|
||||
letterSpacing = 0.sp,
|
||||
color = onSurfaceColor(),
|
||||
textAlign = LocalReadingSubheadAlign.current.toTextAlign(),
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun h5Style(): TextStyle =
|
||||
MaterialTheme.typography.headlineSmall.copy(
|
||||
color = bodyForeground(),
|
||||
textAlign = TextAlign.Start,
|
||||
TextStyle(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(isDisplay = true),
|
||||
fontWeight = if (LocalReadingSubheadBold.current.value) FontWeight.SemiBold else FontWeight.Normal,
|
||||
fontSize = 17.sp,
|
||||
letterSpacing = 0.sp,
|
||||
color = onSurfaceColor(),
|
||||
textAlign = LocalReadingSubheadAlign.current.toTextAlign(),
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun h6Style(): TextStyle =
|
||||
MaterialTheme.typography.titleLarge.copy(
|
||||
color = bodyForeground(),
|
||||
textAlign = TextAlign.Start,
|
||||
TextStyle(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(isDisplay = true),
|
||||
fontWeight = if (LocalReadingSubheadBold.current.value) FontWeight.SemiBold else FontWeight.Normal,
|
||||
fontSize = 17.sp,
|
||||
letterSpacing = 0.sp,
|
||||
color = onSurfaceColor(),
|
||||
textAlign = LocalReadingSubheadAlign.current.toTextAlign(),
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun captionStyle(): TextStyle =
|
||||
MaterialTheme.typography.bodySmall.copy(
|
||||
MaterialTheme.typography.bodySmall.merge(
|
||||
TextStyle(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(),
|
||||
color = bodyForeground().copy(alpha = 0.6f),
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
|
||||
@Composable
|
||||
fun linkTextStyle(): TextStyle =
|
||||
TextStyle(
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
textDecoration = TextDecoration.Underline
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
fun linkTextStyle(): TextStyle =
|
||||
TextStyle(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(),
|
||||
fontSize = LocalReadingTextFontSize.current.sp,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
textDecoration = TextDecoration.Underline,
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
fun codeBlockStyle(): TextStyle =
|
||||
MaterialTheme.typography.titleSmall.merge(
|
||||
|
@ -113,21 +198,27 @@ fun codeBlockStyle(): TextStyle =
|
|||
)
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
fun codeBlockBackground(): Color =
|
||||
MaterialTheme.colorScheme.secondary.copy(alpha = (0.dp).alphaLN(weight = 3.2f))
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
fun blockQuoteStyle(): SpanStyle =
|
||||
MaterialTheme.typography.titleSmall.toSpanStyle().merge(
|
||||
fun boldStyle(): TextStyle =
|
||||
bodyStyle().merge(
|
||||
SpanStyle(
|
||||
fontWeight = FontWeight.Light
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = onSurfaceColor(),
|
||||
)
|
||||
)
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
fun codeInlineStyle(): SpanStyle =
|
||||
MaterialTheme.typography.titleSmall.toSpanStyle().copy(
|
||||
MaterialTheme.typography.titleSmall.toSpanStyle().merge(
|
||||
SpanStyle(
|
||||
color = bodyForeground(),
|
||||
fontFamily = FontFamily.Monospace,
|
||||
)
|
||||
)
|
||||
|
|
|
@ -69,6 +69,7 @@ sealed class DataStoreKeys<T> {
|
|||
|
||||
abstract val key: Preferences.Key<T>
|
||||
|
||||
// Version
|
||||
object IsFirstLaunch : DataStoreKeys<Boolean>() {
|
||||
|
||||
override val key: Preferences.Key<Boolean>
|
||||
|
@ -147,6 +148,7 @@ sealed class DataStoreKeys<T> {
|
|||
get() = booleanPreferencesKey("amoledDarkTheme")
|
||||
}
|
||||
|
||||
// Feeds page
|
||||
object FeedsFilterBarStyle : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
|
@ -189,6 +191,7 @@ sealed class DataStoreKeys<T> {
|
|||
get() = intPreferencesKey("feedsGroupListTonalElevation")
|
||||
}
|
||||
|
||||
// Flow page
|
||||
object FlowFilterBarStyle : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
|
@ -261,6 +264,122 @@ sealed class DataStoreKeys<T> {
|
|||
get() = intPreferencesKey("flowArticleListTonalElevation")
|
||||
}
|
||||
|
||||
// Reading page
|
||||
object ReadingDarkTheme : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("readingDarkTheme")
|
||||
}
|
||||
|
||||
object ReadingPageTonalElevation : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("ReadingPageTonalElevation")
|
||||
}
|
||||
|
||||
object ReadingTextFontSize : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("readingTextFontSize")
|
||||
}
|
||||
|
||||
object ReadingLetterSpacing : DataStoreKeys<Double>() {
|
||||
|
||||
override val key: Preferences.Key<Double>
|
||||
get() = doublePreferencesKey("readingLetterSpacing")
|
||||
}
|
||||
|
||||
object ReadingTextHorizontalPadding : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("readingTextHorizontalPadding")
|
||||
}
|
||||
|
||||
object ReadingTextBold : DataStoreKeys<Boolean>() {
|
||||
|
||||
override val key: Preferences.Key<Boolean>
|
||||
get() = booleanPreferencesKey("readingTextBold")
|
||||
}
|
||||
|
||||
object ReadingTextAlign : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("readingTextAlign")
|
||||
}
|
||||
|
||||
object ReadingTitleAlign : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("readingTitleAlign")
|
||||
}
|
||||
|
||||
object ReadingSubheadAlign : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("readingSubheadAlign")
|
||||
}
|
||||
|
||||
object ReadingTheme : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("readingTheme")
|
||||
}
|
||||
|
||||
object ReadingFonts : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("readingFonts")
|
||||
}
|
||||
|
||||
object ReadingAutoHideToolbar : DataStoreKeys<Boolean>() {
|
||||
|
||||
override val key: Preferences.Key<Boolean>
|
||||
get() = booleanPreferencesKey("readingAutoHideToolbar")
|
||||
}
|
||||
|
||||
object ReadingTitleBold : DataStoreKeys<Boolean>() {
|
||||
|
||||
override val key: Preferences.Key<Boolean>
|
||||
get() = booleanPreferencesKey("readingTitleBold")
|
||||
}
|
||||
|
||||
object ReadingSubheadBold : DataStoreKeys<Boolean>() {
|
||||
|
||||
override val key: Preferences.Key<Boolean>
|
||||
get() = booleanPreferencesKey("ReadingSubheadBold")
|
||||
}
|
||||
|
||||
object ReadingTitleUpperCase : DataStoreKeys<Boolean>() {
|
||||
|
||||
override val key: Preferences.Key<Boolean>
|
||||
get() = booleanPreferencesKey("readingTitleUpperCase")
|
||||
}
|
||||
|
||||
object ReadingSubheadUpperCase : DataStoreKeys<Boolean>() {
|
||||
|
||||
override val key: Preferences.Key<Boolean>
|
||||
get() = booleanPreferencesKey("ReadingSubheadUpperCase")
|
||||
}
|
||||
|
||||
object ReadingImageMaximize : DataStoreKeys<Boolean>() {
|
||||
|
||||
override val key: Preferences.Key<Boolean>
|
||||
get() = booleanPreferencesKey("readingImageMaximize")
|
||||
}
|
||||
|
||||
object ReadingImageHorizontalPadding : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("readingImageHorizontalPadding")
|
||||
}
|
||||
|
||||
object ReadingImageRoundedCorners : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
get() = intPreferencesKey("readingImageRoundedCorners")
|
||||
}
|
||||
|
||||
// Interaction
|
||||
object InitialPage : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
|
@ -273,6 +392,7 @@ sealed class DataStoreKeys<T> {
|
|||
get() = intPreferencesKey("initialFilter")
|
||||
}
|
||||
|
||||
// Languages
|
||||
object Languages : DataStoreKeys<Int>() {
|
||||
|
||||
override val key: Preferences.Key<Int>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package me.ash.reader.ui.page.common
|
||||
|
||||
import android.util.Log
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -12,8 +13,11 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
|||
import com.google.accompanist.navigation.animation.AnimatedNavHost
|
||||
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import me.ash.reader.data.model.general.Filter
|
||||
import me.ash.reader.data.model.preference.LocalDarkTheme
|
||||
import me.ash.reader.data.model.preference.LocalReadingDarkTheme
|
||||
import me.ash.reader.ui.ext.*
|
||||
import me.ash.reader.ui.page.home.HomeViewModel
|
||||
import me.ash.reader.ui.page.home.feeds.FeedsPage
|
||||
|
@ -24,6 +28,7 @@ import me.ash.reader.ui.page.settings.color.ColorAndStylePage
|
|||
import me.ash.reader.ui.page.settings.color.DarkThemePage
|
||||
import me.ash.reader.ui.page.settings.color.feeds.FeedsPageStylePage
|
||||
import me.ash.reader.ui.page.settings.color.flow.FlowPageStylePage
|
||||
import me.ash.reader.ui.page.settings.color.reading.*
|
||||
import me.ash.reader.ui.page.settings.interaction.InteractionPage
|
||||
import me.ash.reader.ui.page.settings.languages.LanguagesPage
|
||||
import me.ash.reader.ui.page.settings.tips.TipsAndSupportPage
|
||||
|
@ -36,6 +41,7 @@ fun HomeEntry(
|
|||
homeViewModel: HomeViewModel = hiltViewModel(),
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
var isReadingPage by rememberSaveable { mutableStateOf(false) }
|
||||
val filterUiState = homeViewModel.filterUiState.collectAsStateValue()
|
||||
val navController = rememberAnimatedNavController()
|
||||
|
||||
|
@ -47,6 +53,11 @@ fun HomeEntry(
|
|||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
navController.currentBackStackEntryFlow.collectLatest {
|
||||
Log.i("RLog", "isReadingPage: ${navController.currentDestination?.route}")
|
||||
delay(310L)
|
||||
isReadingPage = navController.currentDestination?.route == "${RouteName.READING}/{articleId}"
|
||||
}
|
||||
when (context.initialPage) {
|
||||
1 -> {
|
||||
navController.navigate(RouteName.FLOW) {
|
||||
|
@ -80,9 +91,16 @@ fun HomeEntry(
|
|||
}
|
||||
}
|
||||
|
||||
val useDarkTheme = LocalDarkTheme.current.isDarkTheme()
|
||||
val useDarkTheme = if (isReadingPage) {
|
||||
LocalReadingDarkTheme.current.isDarkTheme()
|
||||
} else {
|
||||
LocalDarkTheme.current.isDarkTheme()
|
||||
}
|
||||
|
||||
AppTheme(useDarkTheme = useDarkTheme) {
|
||||
AppTheme(
|
||||
useDarkTheme = if (isReadingPage) LocalReadingDarkTheme.current.isDarkTheme()
|
||||
else LocalDarkTheme.current.isDarkTheme()
|
||||
) {
|
||||
|
||||
rememberSystemUiController().run {
|
||||
setStatusBarColor(Color.Transparent, !useDarkTheme)
|
||||
|
@ -132,6 +150,24 @@ fun HomeEntry(
|
|||
animatedComposable(route = RouteName.FLOW_PAGE_STYLE) {
|
||||
FlowPageStylePage(navController)
|
||||
}
|
||||
animatedComposable(route = RouteName.READING_PAGE_STYLE) {
|
||||
ReadingStylePage(navController)
|
||||
}
|
||||
animatedComposable(route = RouteName.READING_DARK_THEME) {
|
||||
ReadingDarkThemePage(navController)
|
||||
}
|
||||
animatedComposable(route = RouteName.READING_PAGE_TITLE) {
|
||||
ReadingTitlePage(navController)
|
||||
}
|
||||
animatedComposable(route = RouteName.READING_PAGE_TEXT) {
|
||||
ReadingTextPage(navController)
|
||||
}
|
||||
animatedComposable(route = RouteName.READING_PAGE_IMAGE) {
|
||||
ReadingImagePage(navController)
|
||||
}
|
||||
animatedComposable(route = RouteName.READING_PAGE_VIDEO) {
|
||||
ReadingVideoPage(navController)
|
||||
}
|
||||
|
||||
// Interaction
|
||||
animatedComposable(route = RouteName.INTERACTION) {
|
||||
|
|
|
@ -18,6 +18,12 @@ object RouteName {
|
|||
const val DARK_THEME = "dark_theme"
|
||||
const val FEEDS_PAGE_STYLE = "feeds_page_style"
|
||||
const val FLOW_PAGE_STYLE = "flow_page_style"
|
||||
const val READING_PAGE_STYLE = "reading_page_style"
|
||||
const val READING_DARK_THEME = "reading_dark_theme"
|
||||
const val READING_PAGE_TITLE = "reading_page_title"
|
||||
const val READING_PAGE_TEXT = "reading_page_text"
|
||||
const val READING_PAGE_IMAGE = "reading_page_image"
|
||||
const val READING_PAGE_VIDEO = "reading_page_video"
|
||||
|
||||
// Interaction
|
||||
const val INTERACTION = "interaction"
|
||||
|
|
|
@ -22,6 +22,7 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.model.preference.LocalReadingPageTonalElevation
|
||||
import me.ash.reader.ui.component.base.CanBeDisabledIconButton
|
||||
|
||||
@Composable
|
||||
|
@ -34,6 +35,8 @@ fun BottomBar(
|
|||
onStarred: (isStarred: Boolean) -> Unit = {},
|
||||
onFullContent: (isFullContent: Boolean) -> Unit = {},
|
||||
) {
|
||||
val tonalElevation = LocalReadingPageTonalElevation.current
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
|
@ -43,7 +46,10 @@ fun BottomBar(
|
|||
RYExtensibleVisibility(visible = isShow) {
|
||||
val view = LocalView.current
|
||||
|
||||
Surface(modifier = Modifier.navigationBarsPadding()) {
|
||||
Surface(
|
||||
modifier = Modifier.navigationBarsPadding(),
|
||||
tonalElevation = tonalElevation.value.dp,
|
||||
) {
|
||||
// TODO: Component styles await refactoring
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
|
|
@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.ash.reader.data.model.preference.LocalReadingSubheadUpperCase
|
||||
import me.ash.reader.ui.component.reader.Reader
|
||||
import me.ash.reader.ui.ext.drawVerticalScrollbar
|
||||
import java.util.*
|
||||
|
@ -30,6 +31,7 @@ fun Content(
|
|||
isShowToolBar: Boolean,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val subheadUpperCase = LocalReadingSubheadUpperCase.current
|
||||
|
||||
SelectionContainer {
|
||||
LazyColumn(
|
||||
|
@ -56,7 +58,7 @@ fun Content(
|
|||
.padding(horizontal = 12.dp)
|
||||
) {
|
||||
DisableSelection {
|
||||
Header(
|
||||
Metadata(
|
||||
feedName = feedName,
|
||||
title = title,
|
||||
author = author,
|
||||
|
@ -88,6 +90,7 @@ fun Content(
|
|||
if (!isLoading) {
|
||||
Reader(
|
||||
context = context,
|
||||
subheadUpperCase = subheadUpperCase.value,
|
||||
link = link ?: "",
|
||||
content = content
|
||||
)
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
package me.ash.reader.ui.page.home.reading
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.ash.reader.ui.ext.formatAsString
|
||||
import me.ash.reader.ui.ext.openURL
|
||||
import me.ash.reader.ui.ext.roundClick
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
fun Header(
|
||||
feedName: String,
|
||||
title: String,
|
||||
author: String? = null,
|
||||
link: String? = null,
|
||||
publishedDate: Date,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val dateString = remember(publishedDate) {
|
||||
publishedDate.formatAsString(context, atHourMinute = true)
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.roundClick {
|
||||
context.openURL(link)
|
||||
}
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alpha(0.7f),
|
||||
text = dateString,
|
||||
color = MaterialTheme.colorScheme.outline,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
textAlign = TextAlign.Start,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = title,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.headlineLarge,
|
||||
textAlign = TextAlign.Start,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
author?.let {
|
||||
if (it.isNotEmpty()) {
|
||||
Text(
|
||||
modifier = Modifier.alpha(0.7f),
|
||||
text = it,
|
||||
color = MaterialTheme.colorScheme.outline,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
textAlign = TextAlign.Start,
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier.alpha(0.7f),
|
||||
text = feedName,
|
||||
color = MaterialTheme.colorScheme.outline,
|
||||
style = MaterialTheme.typography.labelMedium,
|
||||
textAlign = TextAlign.Start,
|
||||
)
|
||||
}
|
||||
}
|
100
app/src/main/java/me/ash/reader/ui/page/home/reading/Metadata.kt
Normal file
100
app/src/main/java/me/ash/reader/ui/page/home/reading/Metadata.kt
Normal file
|
@ -0,0 +1,100 @@
|
|||
package me.ash.reader.ui.page.home.reading
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.ash.reader.data.model.preference.LocalReadingFonts
|
||||
import me.ash.reader.data.model.preference.LocalReadingTitleAlign
|
||||
import me.ash.reader.data.model.preference.LocalReadingTitleBold
|
||||
import me.ash.reader.data.model.preference.LocalReadingTitleUpperCase
|
||||
import me.ash.reader.ui.ext.formatAsString
|
||||
import me.ash.reader.ui.ext.openURL
|
||||
import me.ash.reader.ui.ext.roundClick
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
fun Metadata(
|
||||
feedName: String,
|
||||
title: String,
|
||||
author: String? = null,
|
||||
link: String? = null,
|
||||
publishedDate: Date,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val titleBold = LocalReadingTitleBold.current
|
||||
val titleUpperCase = LocalReadingTitleUpperCase.current
|
||||
val titleAlign = LocalReadingTitleAlign.current
|
||||
val dateString = remember(publishedDate) {
|
||||
publishedDate.formatAsString(context, atHourMinute = true)
|
||||
}
|
||||
|
||||
val titleUpperCaseString by remember { derivedStateOf { title.uppercase() } }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.roundClick {
|
||||
context.openURL(link)
|
||||
}
|
||||
.padding(12.dp)
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.alpha(0.7f)
|
||||
.fillMaxWidth(),
|
||||
text = dateString,
|
||||
color = MaterialTheme.colorScheme.outline,
|
||||
style = MaterialTheme.typography.labelMedium.copy(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(),
|
||||
),
|
||||
textAlign = titleAlign.toTextAlign(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
text = if (titleUpperCase.value) titleUpperCaseString else title,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.headlineLarge.copy(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(isDisplay = true),
|
||||
fontWeight = if (titleBold.value) FontWeight.SemiBold else FontWeight.Normal,
|
||||
),
|
||||
textAlign = titleAlign.toTextAlign(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
author?.let {
|
||||
if (it.isNotEmpty()) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.alpha(0.7f)
|
||||
.fillMaxWidth(),
|
||||
text = it,
|
||||
color = MaterialTheme.colorScheme.outline,
|
||||
style = MaterialTheme.typography.labelMedium.copy(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(),
|
||||
),
|
||||
textAlign = titleAlign.toTextAlign(),
|
||||
)
|
||||
}
|
||||
}
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.alpha(0.7f)
|
||||
.fillMaxWidth(),
|
||||
text = feedName,
|
||||
color = MaterialTheme.colorScheme.outline,
|
||||
style = MaterialTheme.typography.labelMedium.copy(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(),
|
||||
),
|
||||
textAlign = titleAlign.toTextAlign(),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -6,8 +6,11 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import androidx.navigation.NavHostController
|
||||
import me.ash.reader.data.model.preference.LocalReadingAutoHideToolbar
|
||||
import me.ash.reader.data.model.preference.LocalReadingPageTonalElevation
|
||||
import me.ash.reader.ui.component.base.RYScaffold
|
||||
import me.ash.reader.ui.ext.collectAsStateValue
|
||||
import me.ash.reader.ui.ext.isScrollDown
|
||||
|
@ -17,9 +20,13 @@ fun ReadingPage(
|
|||
navController: NavHostController,
|
||||
readingViewModel: ReadingViewModel = hiltViewModel(),
|
||||
) {
|
||||
val tonalElevation = LocalReadingPageTonalElevation.current
|
||||
val readingUiState = readingViewModel.readingUiState.collectAsStateValue()
|
||||
val isShowToolBar =
|
||||
val isShowToolBar = if (LocalReadingAutoHideToolbar.current.value) {
|
||||
readingUiState.articleWithFeed != null && !readingUiState.listState.isScrollDown()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
navController.currentBackStackEntryFlow.collect {
|
||||
|
@ -39,12 +46,15 @@ fun ReadingPage(
|
|||
}
|
||||
|
||||
RYScaffold(
|
||||
topBarTonalElevation = tonalElevation.value.dp,
|
||||
containerTonalElevation = tonalElevation.value.dp,
|
||||
content = {
|
||||
Log.i("RLog", "TopBar: recomposition")
|
||||
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
// Top Bar
|
||||
TopBar(
|
||||
navController = navController,
|
||||
isShow = isShowToolBar,
|
||||
title = readingUiState.articleWithFeed?.article?.title,
|
||||
link = readingUiState.articleWithFeed?.article?.link,
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Palette
|
||||
import androidx.compose.material.icons.outlined.Share
|
||||
import androidx.compose.material.icons.rounded.Close
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
@ -18,18 +19,24 @@ import androidx.compose.ui.platform.LocalContext
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.navigation.NavHostController
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.model.preference.LocalReadingPageTonalElevation
|
||||
import me.ash.reader.ui.component.base.FeedbackIconButton
|
||||
import me.ash.reader.ui.ext.share
|
||||
import me.ash.reader.ui.ext.surfaceColorAtElevation
|
||||
import me.ash.reader.ui.page.common.RouteName
|
||||
|
||||
@Composable
|
||||
fun TopBar(
|
||||
navController: NavHostController,
|
||||
isShow: Boolean,
|
||||
title: String? = "",
|
||||
link: String? = "",
|
||||
onClose: () -> Unit = {},
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val tonalElevation = LocalReadingPageTonalElevation.current
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
|
@ -41,7 +48,9 @@ fun TopBar(
|
|||
SmallTopAppBar(
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.surface,
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
elevation = tonalElevation.value.dp
|
||||
),
|
||||
),
|
||||
title = {},
|
||||
navigationIcon = {
|
||||
|
@ -54,6 +63,16 @@ fun TopBar(
|
|||
}
|
||||
},
|
||||
actions = {
|
||||
FeedbackIconButton(
|
||||
modifier = Modifier.size(22.dp),
|
||||
imageVector = Icons.Outlined.Palette,
|
||||
contentDescription = stringResource(R.string.style),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
) {
|
||||
navController.navigate(RouteName.READING_PAGE_STYLE) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
}
|
||||
FeedbackIconButton(
|
||||
modifier = Modifier.size(20.dp),
|
||||
imageVector = Icons.Outlined.Share,
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
package me.ash.reader.ui.page.home.reading.drawer
|
||||
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material3.Tab
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.ui.component.base.BottomDrawer
|
||||
import me.ash.reader.ui.ext.collectAsStateValue
|
||||
import me.ash.reader.ui.page.home.feeds.drawer.feed.FeedOptionViewModel
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
fun StyleOptionDrawer(
|
||||
feedOptionViewModel: FeedOptionViewModel = hiltViewModel(),
|
||||
content: @Composable () -> Unit = {},
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val view = LocalView.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val feedOptionUiState = feedOptionViewModel.feedOptionUiState.collectAsStateValue()
|
||||
val feed = feedOptionUiState.feed
|
||||
val toastString = stringResource(R.string.rename_toast, feedOptionUiState.newName)
|
||||
|
||||
BackHandler(feedOptionUiState.drawerState.isVisible) {
|
||||
scope.launch {
|
||||
feedOptionUiState.drawerState.hide()
|
||||
}
|
||||
}
|
||||
|
||||
BottomDrawer(
|
||||
drawerState = feedOptionUiState.drawerState,
|
||||
sheetContent = {
|
||||
Info()
|
||||
}
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Info() {
|
||||
Column(modifier = Modifier.navigationBarsPadding()) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Tab(selected = true, onClick = { /*TODO*/ })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun Prev() {
|
||||
Tab(selected = true, onClick = { /*TODO*/ })
|
||||
}
|
|
@ -140,6 +140,7 @@ fun SettingsPage(
|
|||
}
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,11 +181,15 @@ fun ColorAndStylePage(
|
|||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.reading_page),
|
||||
enable = false,
|
||||
onClick = {},
|
||||
onClick = {
|
||||
navController.navigate(RouteName.READING_PAGE_STYLE) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
},
|
||||
) {}
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ fun DarkThemePage(
|
|||
}
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ fun FeedsPageStylePage(
|
|||
}
|
||||
}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.padding_on_both_ends),
|
||||
title = stringResource(R.string.horizontal_padding),
|
||||
desc = "${filterBarPadding}dp",
|
||||
onClick = {
|
||||
filterBarPaddingValue = filterBarPadding
|
||||
|
@ -197,7 +197,7 @@ fun FeedsPageStylePage(
|
|||
|
||||
TextFieldDialog(
|
||||
visible = filterBarPaddingDialogVisible,
|
||||
title = stringResource(R.string.padding_on_both_ends),
|
||||
title = stringResource(R.string.horizontal_padding),
|
||||
value = (filterBarPaddingValue ?: "").toString(),
|
||||
placeholder = stringResource(R.string.value),
|
||||
onValueChange = {
|
||||
|
|
|
@ -218,7 +218,7 @@ fun FlowPageStylePage(
|
|||
}
|
||||
}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.padding_on_both_ends),
|
||||
title = stringResource(R.string.horizontal_padding),
|
||||
desc = "${filterBarPadding}dp",
|
||||
onClick = {
|
||||
filterBarPaddingValue = filterBarPadding
|
||||
|
@ -234,6 +234,7 @@ fun FlowPageStylePage(
|
|||
) {}
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
|
@ -257,7 +258,7 @@ fun FlowPageStylePage(
|
|||
|
||||
TextFieldDialog(
|
||||
visible = filterBarPaddingDialogVisible,
|
||||
title = stringResource(R.string.padding_on_both_ends),
|
||||
title = stringResource(R.string.horizontal_padding),
|
||||
value = (filterBarPaddingValue ?: "").toString(),
|
||||
placeholder = stringResource(R.string.value),
|
||||
onValueChange = {
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
package me.ash.reader.ui.page.settings.color.reading
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.model.preference.LocalReadingDarkTheme
|
||||
import me.ash.reader.data.model.preference.ReadingDarkThemePreference
|
||||
import me.ash.reader.ui.component.base.DisplayText
|
||||
import me.ash.reader.ui.component.base.FeedbackIconButton
|
||||
import me.ash.reader.ui.component.base.RYScaffold
|
||||
import me.ash.reader.ui.page.settings.SettingItem
|
||||
import me.ash.reader.ui.theme.palette.onLight
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ReadingDarkThemePage(
|
||||
navController: NavHostController,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val darkTheme = LocalReadingDarkTheme.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
RYScaffold(
|
||||
containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface,
|
||||
navigationIcon = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
) {
|
||||
navController.popBackStack()
|
||||
}
|
||||
},
|
||||
content = {
|
||||
LazyColumn {
|
||||
item {
|
||||
DisplayText(text = stringResource(R.string.dark_theme), desc = "")
|
||||
}
|
||||
item {
|
||||
ReadingDarkThemePreference.values.map {
|
||||
SettingItem(
|
||||
title = it.toDesc(context),
|
||||
onClick = {
|
||||
it.put(context, scope)
|
||||
},
|
||||
) {
|
||||
RadioButton(selected = it == darkTheme, onClick = {
|
||||
it.put(context, scope)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
package me.ash.reader.ui.page.settings.color.reading
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.model.preference.*
|
||||
import me.ash.reader.ui.component.base.*
|
||||
import me.ash.reader.ui.page.settings.SettingItem
|
||||
import me.ash.reader.ui.theme.palette.onLight
|
||||
|
||||
@Composable
|
||||
fun ReadingImagePage(
|
||||
navController: NavHostController,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val readingTheme = LocalReadingTheme.current
|
||||
val roundedCorners = LocalReadingImageRoundedCorners.current
|
||||
val horizontalPadding = LocalReadingImageHorizontalPadding.current
|
||||
val maximize = LocalReadingImageMaximize.current
|
||||
|
||||
var roundedCornersDialogVisible by remember { mutableStateOf(false) }
|
||||
var horizontalPaddingDialogVisible by remember { mutableStateOf(false) }
|
||||
|
||||
var roundedCornersValue: Int? by remember { mutableStateOf(roundedCorners) }
|
||||
var horizontalPaddingValue: Int? by remember { mutableStateOf(horizontalPadding) }
|
||||
|
||||
RYScaffold(
|
||||
containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface,
|
||||
navigationIcon = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
) {
|
||||
navController.popBackStack()
|
||||
}
|
||||
},
|
||||
content = {
|
||||
LazyColumn {
|
||||
item {
|
||||
DisplayText(text = stringResource(R.string.images), 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
|
||||
// ) {
|
||||
// RYAsyncImage(
|
||||
// modifier = Modifier
|
||||
// .fillMaxSize()
|
||||
// .padding(24.dp)
|
||||
// .padding(imageHorizontalPadding().dp)
|
||||
// .clip(imageShape()),
|
||||
// data = "https://images.unsplash.com/photo-1544716278-ca5e3f4abd8c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1yZWxhdGVkfDJ8fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=800&q=60",
|
||||
// contentDescription = stringResource(R.string.images),
|
||||
// contentScale = ContentScale.Inside,
|
||||
// )
|
||||
// }
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
|
||||
|
||||
// Images
|
||||
item {
|
||||
Subtitle(
|
||||
modifier = Modifier.padding(horizontal = 24.dp),
|
||||
text = stringResource(R.string.images)
|
||||
)
|
||||
SettingItem(
|
||||
title = stringResource(R.string.rounded_corners),
|
||||
desc = "${roundedCorners}dp",
|
||||
onClick = { roundedCornersDialogVisible = true },
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.horizontal_padding),
|
||||
desc = "${horizontalPadding}dp",
|
||||
onClick = { horizontalPaddingDialogVisible = true },
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.maximize),
|
||||
onClick = {
|
||||
(!maximize).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
},
|
||||
) {
|
||||
RYSwitch(activated = maximize.value) {
|
||||
(!maximize).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
TextFieldDialog(
|
||||
visible = roundedCornersDialogVisible,
|
||||
title = stringResource(R.string.rounded_corners),
|
||||
value = (roundedCornersValue ?: "").toString(),
|
||||
placeholder = stringResource(R.string.value),
|
||||
onValueChange = {
|
||||
roundedCornersValue = it.filter { it.isDigit() }.toIntOrNull()
|
||||
},
|
||||
onDismissRequest = {
|
||||
roundedCornersDialogVisible = false
|
||||
},
|
||||
onConfirm = {
|
||||
ReadingImageRoundedCornersPreference.put(context, scope, roundedCornersValue ?: 0)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
roundedCornersDialogVisible = false
|
||||
}
|
||||
)
|
||||
|
||||
TextFieldDialog(
|
||||
visible = horizontalPaddingDialogVisible,
|
||||
title = stringResource(R.string.horizontal_padding),
|
||||
value = (horizontalPaddingValue ?: "").toString(),
|
||||
placeholder = stringResource(R.string.value),
|
||||
onValueChange = {
|
||||
horizontalPaddingValue = it.filter { it.isDigit() }.toIntOrNull()
|
||||
},
|
||||
onDismissRequest = {
|
||||
horizontalPaddingDialogVisible = false
|
||||
},
|
||||
onConfirm = {
|
||||
ReadingImageHorizontalPaddingPreference.put(context, scope, horizontalPaddingValue ?: 0)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
horizontalPaddingDialogVisible = false
|
||||
}
|
||||
)
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
package me.ash.reader.ui.page.settings.color.reading
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Image
|
||||
import androidx.compose.material.icons.outlined.Movie
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.rounded.Segment
|
||||
import androidx.compose.material.icons.rounded.Title
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
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.text.TextStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.model.preference.*
|
||||
import me.ash.reader.ui.component.ReadingThemePrev
|
||||
import me.ash.reader.ui.component.base.*
|
||||
import me.ash.reader.ui.page.common.RouteName
|
||||
import me.ash.reader.ui.page.settings.SettingItem
|
||||
import me.ash.reader.ui.theme.palette.onLight
|
||||
|
||||
@Composable
|
||||
fun ReadingStylePage(
|
||||
navController: NavHostController,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val readingTheme = LocalReadingTheme.current
|
||||
val darkTheme = LocalReadingDarkTheme.current
|
||||
val darkThemeNot = !darkTheme
|
||||
val tonalElevation = LocalReadingPageTonalElevation.current
|
||||
val fonts = LocalReadingFonts.current
|
||||
val autoHideToolbar = LocalReadingAutoHideToolbar.current
|
||||
|
||||
var tonalElevationDialogVisible by remember { mutableStateOf(false) }
|
||||
var fontsDialogVisible by remember { mutableStateOf(false) }
|
||||
|
||||
RYScaffold(
|
||||
containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface,
|
||||
navigationIcon = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
) {
|
||||
navController.popBackStack()
|
||||
}
|
||||
},
|
||||
content = {
|
||||
LazyColumn {
|
||||
item {
|
||||
DisplayText(text = stringResource(R.string.reading_page), desc = "")
|
||||
}
|
||||
|
||||
// Preview
|
||||
item {
|
||||
Row(modifier = Modifier.horizontalScroll(rememberScrollState())
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(24.dp))
|
||||
ReadingThemePreference.values.map {
|
||||
if (readingTheme == ReadingThemePreference.Custom || it != ReadingThemePreference.Custom) {
|
||||
ReadingThemePrev(selected = readingTheme, theme = it) {
|
||||
it.put(context, scope)
|
||||
it.applyTheme(context, scope)
|
||||
}
|
||||
} else {
|
||||
Spacer(modifier = Modifier.width(150.dp))
|
||||
}
|
||||
Spacer(modifier = Modifier.width(8.dp))
|
||||
}
|
||||
Spacer(modifier = Modifier.width((24 - 8).dp))
|
||||
}
|
||||
|
||||
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
|
||||
) {
|
||||
|
||||
}
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
|
||||
// General
|
||||
item {
|
||||
Subtitle(
|
||||
modifier = Modifier.padding(horizontal = 24.dp),
|
||||
text = stringResource(R.string.general)
|
||||
)
|
||||
SettingItem(
|
||||
title = stringResource(R.string.reading_fonts),
|
||||
desc = fonts.toDesc(context),
|
||||
onClick = { fontsDialogVisible = true },
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.dark_reading_theme),
|
||||
desc = darkTheme.toDesc(context),
|
||||
separatedActions = true,
|
||||
onClick = {
|
||||
navController.navigate(RouteName.READING_DARK_THEME) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
},
|
||||
) {
|
||||
RYSwitch(
|
||||
activated = darkTheme.isDarkTheme()
|
||||
) {
|
||||
darkThemeNot.put(context, scope)
|
||||
}
|
||||
}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.bionic_reading),
|
||||
separatedActions = true,
|
||||
enable = false,
|
||||
onClick = {
|
||||
// (!articleListDesc).put(context, scope)
|
||||
},
|
||||
) {
|
||||
RYSwitch(
|
||||
activated = false,
|
||||
enable = false,
|
||||
) {
|
||||
// (!articleListDesc).put(context, scope)
|
||||
}
|
||||
}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.auto_hide_toolbars),
|
||||
onClick = {
|
||||
(!autoHideToolbar).put(context, scope)
|
||||
},
|
||||
) {
|
||||
RYSwitch(activated = autoHideToolbar.value) {
|
||||
(!autoHideToolbar).put(context, scope)
|
||||
}
|
||||
}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.rearrange_buttons),
|
||||
enable = false,
|
||||
onClick = {},
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.tonal_elevation),
|
||||
desc = "${tonalElevation.value}dp",
|
||||
onClick = {
|
||||
tonalElevationDialogVisible = true
|
||||
},
|
||||
) {}
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
|
||||
// Advanced
|
||||
item {
|
||||
Subtitle(
|
||||
modifier = Modifier.padding(horizontal = 24.dp),
|
||||
text = stringResource(R.string.advanced)
|
||||
)
|
||||
SettingItem(
|
||||
title = stringResource(R.string.title),
|
||||
desc = stringResource(R.string.title_desc),
|
||||
icon = Icons.Rounded.Title,
|
||||
onClick = {
|
||||
navController.navigate(RouteName.READING_PAGE_TITLE) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
},
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.text),
|
||||
desc = stringResource(R.string.text_desc),
|
||||
icon = Icons.Rounded.Segment,
|
||||
onClick = {
|
||||
navController.navigate(RouteName.READING_PAGE_TEXT) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
},
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.images),
|
||||
desc = stringResource(R.string.images_desc),
|
||||
icon = Icons.Outlined.Image,
|
||||
onClick = {
|
||||
navController.navigate(RouteName.READING_PAGE_IMAGE) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
},
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.videos),
|
||||
desc = stringResource(R.string.videos_desc),
|
||||
icon = Icons.Outlined.Movie,
|
||||
enable = false,
|
||||
onClick = {
|
||||
// navController.navigate(RouteName.READING_PAGE_VIDEO) {
|
||||
// launchSingleTop = true
|
||||
// }
|
||||
},
|
||||
) {}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
RadioDialog(
|
||||
visible = tonalElevationDialogVisible,
|
||||
title = stringResource(R.string.tonal_elevation),
|
||||
options = ReadingPageTonalElevationPreference.values.map {
|
||||
RadioDialogOption(
|
||||
text = it.toDesc(context),
|
||||
selected = it == tonalElevation,
|
||||
) {
|
||||
it.put(context, scope)
|
||||
}
|
||||
}
|
||||
) {
|
||||
tonalElevationDialogVisible = false
|
||||
}
|
||||
|
||||
RadioDialog(
|
||||
visible = fontsDialogVisible,
|
||||
title = stringResource(R.string.reading_fonts),
|
||||
options = ReadingFontsPreference.values.map {
|
||||
RadioDialogOption(
|
||||
text = it.toDesc(context),
|
||||
style = TextStyle(fontFamily = it.asFontFamily()),
|
||||
selected = it == fonts,
|
||||
) {
|
||||
it.put(context, scope)
|
||||
}
|
||||
}
|
||||
) {
|
||||
fontsDialogVisible = false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
package me.ash.reader.ui.page.settings.color.reading
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.model.preference.*
|
||||
import me.ash.reader.ui.component.base.*
|
||||
import me.ash.reader.ui.page.settings.SettingItem
|
||||
import me.ash.reader.ui.theme.palette.onLight
|
||||
|
||||
@Composable
|
||||
fun ReadingTextPage(
|
||||
navController: NavHostController,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val readingTheme = LocalReadingTheme.current
|
||||
val fontSize = LocalReadingTextFontSize.current
|
||||
val letterSpacing = LocalReadingLetterSpacing.current
|
||||
val horizontalPadding = LocalReadingTextHorizontalPadding.current
|
||||
val align = LocalReadingTextAlign.current
|
||||
val bold = LocalReadingTextBold.current
|
||||
|
||||
var fontSizeDialogVisible by remember { mutableStateOf(false) }
|
||||
var letterSpacingDialogVisible by remember { mutableStateOf(false) }
|
||||
var horizontalPaddingDialogVisible by remember { mutableStateOf(false) }
|
||||
var alignDialogVisible by remember { mutableStateOf(false) }
|
||||
|
||||
var fontSizeValue: Int? by remember { mutableStateOf(fontSize) }
|
||||
var letterSpacingValue: String? by remember { mutableStateOf(letterSpacing.toString()) }
|
||||
var horizontalPaddingValue: Int? by remember { mutableStateOf(horizontalPadding) }
|
||||
|
||||
RYScaffold(
|
||||
containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface,
|
||||
navigationIcon = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
) {
|
||||
navController.popBackStack()
|
||||
}
|
||||
},
|
||||
content = {
|
||||
LazyColumn {
|
||||
item {
|
||||
DisplayText(text = stringResource(R.string.text), 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
|
||||
) {
|
||||
TitleAndTextPreview()
|
||||
}
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
|
||||
// Text
|
||||
item {
|
||||
Subtitle(
|
||||
modifier = Modifier.padding(horizontal = 24.dp),
|
||||
text = stringResource(R.string.text)
|
||||
)
|
||||
SettingItem(
|
||||
title = stringResource(R.string.font_size),
|
||||
desc = "${fontSize}sp",
|
||||
onClick = { fontSizeDialogVisible = true },
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.bold),
|
||||
onClick = {
|
||||
(!bold).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
},
|
||||
) {
|
||||
RYSwitch(activated = bold.value) {
|
||||
(!bold).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
}
|
||||
}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.letter_spacing),
|
||||
desc = "${letterSpacing}sp",
|
||||
onClick = { letterSpacingDialogVisible = true },
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.horizontal_padding),
|
||||
desc = "${horizontalPadding}dp",
|
||||
onClick = { horizontalPaddingDialogVisible = true },
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.alignment),
|
||||
desc = align.toDesc(context),
|
||||
onClick = { alignDialogVisible = true },
|
||||
) {}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
TextFieldDialog(
|
||||
visible = fontSizeDialogVisible,
|
||||
title = stringResource(R.string.font_size),
|
||||
value = (fontSizeValue ?: "").toString(),
|
||||
placeholder = stringResource(R.string.value),
|
||||
onValueChange = {
|
||||
fontSizeValue = it.filter { it.isDigit() }.toIntOrNull()
|
||||
},
|
||||
onDismissRequest = {
|
||||
fontSizeDialogVisible = false
|
||||
},
|
||||
onConfirm = {
|
||||
ReadingTextFontSizePreference.put(context, scope, fontSizeValue ?: 0)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
fontSizeDialogVisible = false
|
||||
}
|
||||
)
|
||||
|
||||
TextFieldDialog(
|
||||
visible = letterSpacingDialogVisible,
|
||||
title = stringResource(R.string.letter_spacing),
|
||||
value = (letterSpacingValue ?: "").toString(),
|
||||
placeholder = stringResource(R.string.value),
|
||||
onValueChange = {
|
||||
letterSpacingValue = it
|
||||
},
|
||||
onDismissRequest = {
|
||||
letterSpacingDialogVisible = false
|
||||
},
|
||||
onConfirm = {
|
||||
ReadingLetterSpacingPreference.put(context, scope, letterSpacingValue?.toDoubleOrNull() ?: 0.0)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
letterSpacingDialogVisible = false
|
||||
}
|
||||
)
|
||||
|
||||
TextFieldDialog(
|
||||
visible = horizontalPaddingDialogVisible,
|
||||
title = stringResource(R.string.horizontal_padding),
|
||||
value = (horizontalPaddingValue ?: "").toString(),
|
||||
placeholder = stringResource(R.string.value),
|
||||
onValueChange = {
|
||||
horizontalPaddingValue = it.filter { it.isDigit() }.toIntOrNull()
|
||||
},
|
||||
onDismissRequest = {
|
||||
horizontalPaddingDialogVisible = false
|
||||
},
|
||||
onConfirm = {
|
||||
ReadingTextHorizontalPaddingPreference.put(context, scope, horizontalPaddingValue ?: 0)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
horizontalPaddingDialogVisible = false
|
||||
}
|
||||
)
|
||||
|
||||
RadioDialog(
|
||||
visible = alignDialogVisible,
|
||||
title = stringResource(R.string.alignment),
|
||||
options = ReadingTextAlignPreference.values.map {
|
||||
RadioDialogOption(
|
||||
text = it.toDesc(context),
|
||||
selected = it == align,
|
||||
) {
|
||||
it.put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
}
|
||||
}
|
||||
) {
|
||||
alignDialogVisible = false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,196 @@
|
|||
package me.ash.reader.ui.page.settings.color.reading
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.model.preference.*
|
||||
import me.ash.reader.ui.component.base.*
|
||||
import me.ash.reader.ui.page.settings.SettingItem
|
||||
import me.ash.reader.ui.theme.palette.onLight
|
||||
|
||||
@Composable
|
||||
fun ReadingTitlePage(
|
||||
navController: NavHostController,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val titleBold = LocalReadingTitleBold.current
|
||||
val subtitleBold = LocalReadingSubheadBold.current
|
||||
val titleAlign = LocalReadingTitleAlign.current
|
||||
val subtitleAlign = LocalReadingSubheadAlign.current
|
||||
val titleUpperCase = LocalReadingTitleUpperCase.current
|
||||
val subheadUpperCase = LocalReadingSubheadUpperCase.current
|
||||
|
||||
var titleAlignDialogVisible by remember { mutableStateOf(false) }
|
||||
var subtitleAlignDialogVisible by remember { mutableStateOf(false) }
|
||||
|
||||
RYScaffold(
|
||||
containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface,
|
||||
navigationIcon = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
) {
|
||||
navController.popBackStack()
|
||||
}
|
||||
},
|
||||
content = {
|
||||
LazyColumn {
|
||||
item {
|
||||
DisplayText(text = stringResource(R.string.title), 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
|
||||
) {
|
||||
TitleAndTextPreview()
|
||||
}
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
|
||||
// Title
|
||||
item {
|
||||
Subtitle(
|
||||
modifier = Modifier.padding(horizontal = 24.dp),
|
||||
text = stringResource(R.string.title)
|
||||
)
|
||||
SettingItem(
|
||||
title = stringResource(R.string.bold),
|
||||
onClick = {
|
||||
(!titleBold).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
},
|
||||
) {
|
||||
RYSwitch(activated = titleBold.value) {
|
||||
(!titleBold).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
}
|
||||
}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.upper_case),
|
||||
onClick = {
|
||||
(!titleUpperCase).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
},
|
||||
) {
|
||||
RYSwitch(activated = titleUpperCase.value) {
|
||||
(!titleUpperCase).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
}
|
||||
}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.alignment),
|
||||
desc = titleAlign.toDesc(context),
|
||||
onClick = { titleAlignDialogVisible = true },
|
||||
) {}
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
|
||||
// Subhead
|
||||
item {
|
||||
Subtitle(
|
||||
modifier = Modifier.padding(horizontal = 24.dp),
|
||||
text = stringResource(R.string.subhead)
|
||||
)
|
||||
SettingItem(
|
||||
title = stringResource(R.string.bold),
|
||||
onClick = {
|
||||
(!subtitleBold).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
},
|
||||
) {
|
||||
RYSwitch(activated = subtitleBold.value) {
|
||||
(!subtitleBold).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
}
|
||||
}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.upper_case),
|
||||
onClick = {
|
||||
(!subheadUpperCase).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
},
|
||||
) {
|
||||
RYSwitch(activated = subheadUpperCase.value) {
|
||||
(!subheadUpperCase).put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
}
|
||||
}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.alignment),
|
||||
desc = subtitleAlign.toDesc(context),
|
||||
enable = false,
|
||||
onClick = {
|
||||
// subtitleAlignDialogVisible = true
|
||||
},
|
||||
) {}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
RadioDialog(
|
||||
visible = titleAlignDialogVisible,
|
||||
title = stringResource(R.string.alignment),
|
||||
options = ReadingTitleAlignPreference.values.map {
|
||||
RadioDialogOption(
|
||||
text = it.toDesc(context),
|
||||
selected = it == titleAlign,
|
||||
) {
|
||||
it.put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
}
|
||||
}
|
||||
) {
|
||||
titleAlignDialogVisible = false
|
||||
}
|
||||
|
||||
RadioDialog(
|
||||
visible = subtitleAlignDialogVisible,
|
||||
title = stringResource(R.string.alignment),
|
||||
options = ReadingSubheadAlignPreference.values.map {
|
||||
RadioDialogOption(
|
||||
text = it.toDesc(context),
|
||||
selected = it == subtitleAlign,
|
||||
) {
|
||||
it.put(context, scope)
|
||||
ReadingThemePreference.Custom.put(context, scope)
|
||||
}
|
||||
}
|
||||
) {
|
||||
subtitleAlignDialogVisible = false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package me.ash.reader.ui.page.settings.color.reading
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.ui.component.base.DisplayText
|
||||
import me.ash.reader.ui.component.base.FeedbackIconButton
|
||||
import me.ash.reader.ui.component.base.RYScaffold
|
||||
import me.ash.reader.ui.component.base.Subtitle
|
||||
import me.ash.reader.ui.page.settings.SettingItem
|
||||
import me.ash.reader.ui.theme.palette.onLight
|
||||
|
||||
@Composable
|
||||
fun ReadingVideoPage(
|
||||
navController: NavHostController,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
RYScaffold(
|
||||
containerColor = MaterialTheme.colorScheme.surface onLight MaterialTheme.colorScheme.inverseOnSurface,
|
||||
navigationIcon = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
) {
|
||||
navController.popBackStack()
|
||||
}
|
||||
},
|
||||
content = {
|
||||
LazyColumn {
|
||||
item {
|
||||
DisplayText(text = stringResource(R.string.videos), desc = "")
|
||||
}
|
||||
|
||||
// Preview
|
||||
item {
|
||||
Row(modifier = Modifier.horizontalScroll(rememberScrollState())
|
||||
) {
|
||||
}
|
||||
|
||||
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
|
||||
) {
|
||||
|
||||
}
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
|
||||
// Videos
|
||||
item {
|
||||
Subtitle(
|
||||
modifier = Modifier.padding(horizontal = 24.dp),
|
||||
text = stringResource(R.string.videos)
|
||||
)
|
||||
SettingItem(
|
||||
title = stringResource(R.string.rounded_corners),
|
||||
onClick = {},
|
||||
) {}
|
||||
SettingItem(
|
||||
title = stringResource(R.string.horizontal_padding),
|
||||
desc = "dp",
|
||||
onClick = {},
|
||||
) {}
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package me.ash.reader.ui.page.settings.color.reading
|
||||
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.model.preference.*
|
||||
import me.ash.reader.ui.component.reader.bodyStyle
|
||||
import me.ash.reader.ui.component.reader.h3Style
|
||||
import me.ash.reader.ui.component.reader.textHorizontalPadding
|
||||
|
||||
@Composable
|
||||
fun TitleAndTextPreview() {
|
||||
val context = LocalContext.current
|
||||
val titleBold = LocalReadingTitleBold.current
|
||||
val subtitleBold = LocalReadingSubheadBold.current
|
||||
val titleUpperCase = LocalReadingTitleUpperCase.current
|
||||
val subheadUpperCase = LocalReadingSubheadUpperCase.current
|
||||
val titleAlign = LocalReadingTitleAlign.current
|
||||
val subtitleAlign = LocalReadingSubheadAlign.current
|
||||
|
||||
|
||||
val titleUpperCaseString by remember {
|
||||
derivedStateOf {
|
||||
context.getString(R.string.title).uppercase()
|
||||
}
|
||||
}
|
||||
|
||||
val subheadUpperCaseString by remember {
|
||||
derivedStateOf {
|
||||
context.getString(R.string.subhead).uppercase()
|
||||
}
|
||||
}
|
||||
Column(modifier = Modifier.padding(24.dp)) {
|
||||
Text(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = textHorizontalPadding().dp),
|
||||
text = if (titleUpperCase.value) titleUpperCaseString else stringResource(id = R.string.title),
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.headlineLarge.copy(
|
||||
fontFamily = LocalReadingFonts.current.asFontFamily(isDisplay = true),
|
||||
fontWeight = if (titleBold.value) FontWeight.SemiBold else FontWeight.Normal,
|
||||
),
|
||||
textAlign = titleAlign.toTextAlign(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Text(
|
||||
text = if (subheadUpperCase.value) subheadUpperCaseString else stringResource(id = R.string.subhead),
|
||||
style = h3Style().copy(textAlign = bodyStyle().textAlign),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = textHorizontalPadding().dp)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
Text(
|
||||
text = stringResource(id = R.string.preview_article_desc),
|
||||
style = bodyStyle(),
|
||||
modifier = Modifier.padding(horizontal = textHorizontalPadding().dp)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -69,6 +69,7 @@ fun InteractionPage(
|
|||
) {}
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ fun LanguagesPage(
|
|||
}
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
Spacer(modifier = Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ val Shapes = Shapes(
|
|||
@Stable
|
||||
val Shape20 = RoundedCornerShape(20.0.dp)
|
||||
|
||||
@Stable
|
||||
val Shape24 = RoundedCornerShape(24.0.dp)
|
||||
|
||||
@Stable
|
||||
val Shape32 = RoundedCornerShape(32.0.dp)
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.material3.darkColorScheme
|
||||
import androidx.compose.material3.lightColorScheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.ReadOnlyComposable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import me.ash.reader.data.model.preference.LocalAmoledDarkTheme
|
||||
|
@ -80,7 +81,9 @@ infix fun Color.onLight(lightColor: Color): Color =
|
|||
infix fun Color.onDark(darkColor: Color): Color =
|
||||
if (LocalDarkTheme.current.isDarkTheme()) darkColor else this
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
infix fun Color.alwaysLight(isAlways: Boolean): Color {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
return if (isAlways && LocalDarkTheme.current.isDarkTheme()) {
|
||||
|
@ -120,6 +123,48 @@ infix fun Color.alwaysLight(isAlways: Boolean): Color {
|
|||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
@ReadOnlyComposable
|
||||
infix fun Color.alwaysDark(isAlways: Boolean): Color {
|
||||
val colorScheme = MaterialTheme.colorScheme
|
||||
return if (isAlways && !LocalDarkTheme.current.isDarkTheme()) {
|
||||
when (this) {
|
||||
colorScheme.primary -> colorScheme.onPrimary
|
||||
colorScheme.secondary -> colorScheme.onSecondary
|
||||
colorScheme.tertiary -> colorScheme.onTertiary
|
||||
colorScheme.background -> colorScheme.onBackground
|
||||
colorScheme.error -> colorScheme.onError
|
||||
colorScheme.surface -> colorScheme.onSurface
|
||||
colorScheme.surfaceVariant -> colorScheme.onSurfaceVariant
|
||||
colorScheme.error -> colorScheme.onError
|
||||
colorScheme.primaryContainer -> colorScheme.onPrimaryContainer
|
||||
colorScheme.secondaryContainer -> colorScheme.onSecondaryContainer
|
||||
colorScheme.tertiaryContainer -> colorScheme.onTertiaryContainer
|
||||
colorScheme.errorContainer -> colorScheme.onErrorContainer
|
||||
colorScheme.inverseSurface -> colorScheme.inverseOnSurface
|
||||
|
||||
colorScheme.onPrimary -> colorScheme.primary
|
||||
colorScheme.onSecondary -> colorScheme.secondary
|
||||
colorScheme.onTertiary -> colorScheme.tertiary
|
||||
colorScheme.onBackground -> colorScheme.background
|
||||
colorScheme.onError -> colorScheme.error
|
||||
colorScheme.onSurface -> colorScheme.surface
|
||||
colorScheme.onSurfaceVariant -> colorScheme.surfaceVariant
|
||||
colorScheme.onError -> colorScheme.error
|
||||
colorScheme.onPrimaryContainer -> colorScheme.primaryContainer
|
||||
colorScheme.onSecondaryContainer -> colorScheme.secondaryContainer
|
||||
colorScheme.onTertiaryContainer -> colorScheme.tertiaryContainer
|
||||
colorScheme.onErrorContainer -> colorScheme.errorContainer
|
||||
colorScheme.inverseOnSurface -> colorScheme.inverseSurface
|
||||
|
||||
else -> Color.Unspecified
|
||||
}
|
||||
} else {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
fun String.checkColorHex(): String? {
|
||||
var s = this.trim()
|
||||
if (s.length > 6) {
|
||||
|
|
|
@ -239,7 +239,7 @@
|
|||
<string name="other">Ostatní</string>
|
||||
<string name="amoled_dark_theme">Tmavé téma AMOLED</string>
|
||||
<string name="tonal_elevation">Zvýraznění tónů</string>
|
||||
<string name="fonts">Písma</string>
|
||||
<string name="reading_fonts">Přečtení písma</string>
|
||||
<string name="basic_fonts">Základní písma</string>
|
||||
<string name="feeds_page">Stránka se zdroji</string>
|
||||
<string name="flow_page">Stránka Flow</string>
|
||||
|
@ -263,7 +263,7 @@
|
|||
<string name="preview_article_desc">Blázen je osmým a závěrečným dílem série Pán záhad, jehož autorem je sépie, která se ráda potápí.</string>
|
||||
<string name="preview_feed_name">Reddit</string>
|
||||
<string name="value">value</string>
|
||||
<string name="padding_on_both_ends">Odsazení na obou koncích</string>
|
||||
<string name="horizontal_padding">Horizontální polstrování</string>
|
||||
<string name="article_date">Čas zveřejnění článku</string>
|
||||
<string name="article_desc">Popis článku</string>
|
||||
<string name="article_images">Obrázky článku</string>
|
||||
|
@ -286,4 +286,33 @@
|
|||
<string name="tips_group_list_tonal_elevation">Zvýšení tónu seznamu skupin je dostupné pouze ve světlém režimu.</string>
|
||||
<string name="share">Sdílet</string>
|
||||
<string name="touch_to_play_video">Klepněte pro přehráníé videa</string>
|
||||
<string name="text">Text</string>
|
||||
<string name="font_size">Font size</string>
|
||||
<string name="letter_spacing">Letter spacing</string>
|
||||
<string name="line_spacing">Line spacing</string>
|
||||
<string name="alignment">Alignment</string>
|
||||
<string name="general">General</string>
|
||||
<string name="auto_hide_toolbars">Auto hide toolbars</string>
|
||||
<string name="rearrange_buttons">Rearrange buttons</string>
|
||||
<string name="bionic_reading">Bionic Reading</string>
|
||||
<string name="images">Images</string>
|
||||
<string name="rounded_corners">Rounded corners</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="align_left">Align left</string>
|
||||
<string name="align_right">Align right</string>
|
||||
<string name="center_text">Center text</string>
|
||||
<string name="justify">Justify</string>
|
||||
<string name="external_fonts">External fonts</string>
|
||||
<string name="title">Title</string>
|
||||
<string name="bold">Bold</string>
|
||||
<string name="upper_case">Upper case</string>
|
||||
<string name="subhead">Subhead</string>
|
||||
<string name="use_app_theme">Use app theme</string>
|
||||
<string name="advanced">Advanced</string>
|
||||
<string name="dark_reading_theme">Dark reading theme</string>
|
||||
<string name="title_desc">Bold, upper case, alignment</string>
|
||||
<string name="text_desc">Font size, letter spacing, alignment</string>
|
||||
<string name="images_desc">Rounded corners, horizontal padding</string>
|
||||
<string name="videos_desc">Rounded corners, horizontal padding</string>
|
||||
<string name="maximize">Maximize</string>
|
||||
</resources>
|
||||
|
|
|
@ -98,7 +98,7 @@
|
|||
<string name="interaction">Interaktion</string>
|
||||
<string name="interaction_desc">Beim Start, haptisches Feedback</string>
|
||||
<string name="languages">Sprachen</string>
|
||||
<string name="languages_desc">English, Deutsch, mehr</string>
|
||||
<string name="languages_desc">Deutsch, Englisch, andere</string>
|
||||
<string name="help_translate">Hilf uns beim Übersetzen</string>
|
||||
<string name="use_device_languages">Gerätesprache verwenden</string>
|
||||
<string name="tips_and_support">Tipps & Support</string>
|
||||
|
@ -233,7 +233,7 @@
|
|||
<string name="other">Sonstiges</string>
|
||||
<string name="amoled_dark_theme">AMOLED Dunkles Design</string>
|
||||
<string name="tonal_elevation">Farbliches Hervorheben</string>
|
||||
<string name="fonts">Schriftarten</string>
|
||||
<string name="reading_fonts">Leseschriftarten</string>
|
||||
<string name="basic_fonts">Grundschriftarten</string>
|
||||
<string name="feeds_page">Feeds Seite</string>
|
||||
<string name="flow_page">Flow Seite</string>
|
||||
|
@ -257,7 +257,7 @@
|
|||
<string name="preview_article_desc">The Fool ist der achte und letzte Band der Lord of the Mysteries Reihe, geschrieben von Cuttlefish That Loves Diving.</string>
|
||||
<string name="preview_feed_name">Reddit</string>
|
||||
<string name="value">Wert</string>
|
||||
<string name="padding_on_both_ends">Rand an beiden Enden</string>
|
||||
<string name="horizontal_padding">Horizontaler Rand</string>
|
||||
<string name="article_date">Artikel Veröffentlichungszeit</string>
|
||||
<string name="article_desc">Artikel Beschreibungen</string>
|
||||
<string name="article_images">Artikel Bilder</string>
|
||||
|
@ -278,6 +278,35 @@
|
|||
<string name="tips_top_bar_tonal_elevation">Das farbliche Hervorheben der oberen Leiste ist nur beim Scrollen verfügbar.</string>
|
||||
<string name="tips_article_list_tonal_elevation">Das farbliche Hervorheben der Artikelliste ist nur für das helle Design verfügbar.</string>
|
||||
<string name="tips_group_list_tonal_elevation">Das farbliche Hervorheben der Gruppenliste ist nur für das helle Design verfügbar.</string>
|
||||
<string name="share">Aktie</string>
|
||||
<string name="share">Teilen</string>
|
||||
<string name="touch_to_play_video">Berühren, um Video abzuspielen</string>
|
||||
<string name="text">Text</string>
|
||||
<string name="font_size">Schriftgröße</string>
|
||||
<string name="letter_spacing">Zeichenabstand</string>
|
||||
<string name="line_spacing">Zeilenabstand</string>
|
||||
<string name="alignment">Ausrichtung</string>
|
||||
<string name="general">Allgemein</string>
|
||||
<string name="auto_hide_toolbars">Leisten automatisch ausblenden</string>
|
||||
<string name="rearrange_buttons">Schaltflächen umpositionieren</string>
|
||||
<string name="bionic_reading">Bionic Reading</string>
|
||||
<string name="images">Bilder</string>
|
||||
<string name="rounded_corners">Abgerundete Ecken</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="align_left">Linksbündig</string>
|
||||
<string name="align_right">Rechtsbündig</string>
|
||||
<string name="center_text">Zentriert</string>
|
||||
<string name="justify">Blocksatz</string>
|
||||
<string name="external_fonts">Externe Schriftart</string>
|
||||
<string name="title">Titel</string>
|
||||
<string name="bold">Fettgedruckt</string>
|
||||
<string name="upper_case">Großbuchstaben</string>
|
||||
<string name="subhead">Untertitel</string>
|
||||
<string name="use_app_theme">Appdesign verwenden</string>
|
||||
<string name="advanced">Erweitert</string>
|
||||
<string name="dark_reading_theme">Dunkles Lesedesign</string>
|
||||
<string name="title_desc">Fettgedruckt, Großbuchstaben, Ausrichtung</string>
|
||||
<string name="text_desc">Schriftgröße, Zeichenabstand, Ausrichtung</string>
|
||||
<string name="images_desc">Abgerundete Ecken, Horizontaler Rand</string>
|
||||
<string name="videos_desc">Abgerundete Ecken, Horizontaler Rand</string>
|
||||
<string name="maximize">Maximieren</string>
|
||||
</resources>
|
||||
|
|
|
@ -236,7 +236,7 @@
|
|||
<string name="other">Autres options</string>
|
||||
<string name="amoled_dark_theme">Thème sombre AMOLED</string>
|
||||
<string name="tonal_elevation">Intensité</string>
|
||||
<string name="fonts">Polices</string>
|
||||
<string name="reading_fonts">Polices de lecture</string>
|
||||
<string name="basic_fonts">Polices de base</string>
|
||||
<string name="feeds_page">Page des flux</string>
|
||||
<string name="flow_page">Page des articles</string>
|
||||
|
@ -260,7 +260,7 @@
|
|||
<string name="preview_article_desc">Le Fou est le huitième et dernier volume de la série Le Seigneur des Mystères écrite par Cuttlefish That Loves Diving.</string>
|
||||
<string name="preview_feed_name">Reddit</string>
|
||||
<string name="value">Valeur</string>
|
||||
<string name="padding_on_both_ends">Espacement des deux côtés</string>
|
||||
<string name="horizontal_padding">Rembourrage Horizontal</string>
|
||||
<string name="article_date">Heure de publication des articles</string>
|
||||
<string name="article_desc">Descriptions des articles</string>
|
||||
<string name="article_images">Images des articles</string>
|
||||
|
@ -283,4 +283,33 @@
|
|||
<string name="tips_group_list_tonal_elevation">L\'intensité de la liste des groupes est uniquement disponible pour le thème clair.</string>
|
||||
<string name="share">Partager</string>
|
||||
<string name="touch_to_play_video">Appuyer pour lancer la lecture</string>
|
||||
<string name="text">Text</string>
|
||||
<string name="font_size">Font size</string>
|
||||
<string name="letter_spacing">Letter spacing</string>
|
||||
<string name="line_spacing">Line spacing</string>
|
||||
<string name="alignment">Alignment</string>
|
||||
<string name="general">General</string>
|
||||
<string name="auto_hide_toolbars">Auto hide toolbars</string>
|
||||
<string name="rearrange_buttons">Rearrange buttons</string>
|
||||
<string name="bionic_reading">Bionic Reading</string>
|
||||
<string name="images">Images</string>
|
||||
<string name="rounded_corners">Rounded corners</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="align_left">Align left</string>
|
||||
<string name="align_right">Align right</string>
|
||||
<string name="center_text">Center text</string>
|
||||
<string name="justify">Justify</string>
|
||||
<string name="external_fonts">External fonts</string>
|
||||
<string name="title">Title</string>
|
||||
<string name="bold">Bold</string>
|
||||
<string name="upper_case">Upper case</string>
|
||||
<string name="subhead">Subhead</string>
|
||||
<string name="use_app_theme">Use app theme</string>
|
||||
<string name="advanced">Advanced</string>
|
||||
<string name="dark_reading_theme">Dark reading theme</string>
|
||||
<string name="title_desc">Bold, upper case, alignment</string>
|
||||
<string name="text_desc">Font size, letter spacing, alignment</string>
|
||||
<string name="images_desc">Rounded corners, horizontal padding</string>
|
||||
<string name="videos_desc">Rounded corners, horizontal padding</string>
|
||||
<string name="maximize">Maximize</string>
|
||||
</resources>
|
||||
|
|
311
app/src/main/res/values-hi-rIN/strings.xml
Normal file
311
app/src/main/res/values-hi-rIN/strings.xml
Normal file
|
@ -0,0 +1,311 @@
|
|||
<resources>
|
||||
<string name="all">सभी</string>
|
||||
<plurals name="all_desc">
|
||||
<item quantity="one">%1$d संग्रहित पाठ </item>
|
||||
<item quantity="other">%1$d संग्रहित पाठ</item>
|
||||
</plurals>
|
||||
<string name="unread">अपठित पाठ </string>
|
||||
<plurals name="unread_desc">
|
||||
<item quantity="one">%1$d अपठित पाठ </item>
|
||||
<item quantity="other">%1$d अपठित पाठ </item>
|
||||
</plurals>
|
||||
<string name="starred">चिन्हित</string>
|
||||
<plurals name="starred_desc">
|
||||
<item quantity="one">%1$d चिन्हित पाठ</item>
|
||||
<item quantity="other">%1$d चिन्हित पाठ</item>
|
||||
</plurals>
|
||||
<string name="feeds">फीड </string>
|
||||
<string name="syncing">सिंक्रनाइज़ किए जा रहे…</string>
|
||||
<string name="loading">लोड हो रहा है…</string>
|
||||
<string name="expand_less">समेटे</string>
|
||||
<string name="expand_more">विस्तृत करें</string>
|
||||
<string name="confirm">पुष्टि करें</string>
|
||||
<string name="cancel">रद्द करें</string>
|
||||
<string name="allow">अनुमति </string>
|
||||
<string name="deny">अस्वीकार </string>
|
||||
<string name="defaults">सामान्य विकल्प </string>
|
||||
<string name="unknown">अज्ञात</string>
|
||||
<string name="back">पीछे </string>
|
||||
<string name="go_to"> गो टू</string>
|
||||
<string name="settings">सेटिंग्स</string>
|
||||
<string name="refresh">रिफ्रेश</string>
|
||||
<string name="search">खोजो</string>
|
||||
<string name="searching">खोज रहे है …</string>
|
||||
<string name="subscribe">सदस्यता लें </string>
|
||||
<string name="already_subscribed">सदस्यता ले ली है </string>
|
||||
<string name="clear">क्लिअर</string>
|
||||
<string name="paste">पेस्ट</string>
|
||||
<string name="feed_or_site_url">यु अरे एल अथवा फ़ीड्स </string>
|
||||
<string name="import_from_opml">ओ पी एम् एल से आयात करें </string>
|
||||
<string name="preset">प्रीसेट</string>
|
||||
<string name="selected">चयनित</string>
|
||||
<string name="allow_notification">नोटिफिकेशन की अनुमति दें</string>
|
||||
<string name="all_allow_notification_tips"> \"%1$s\" ग्रुप के सभी फ़ीड्स को नोटीफिकेशन की स्वीकृति दें </string>
|
||||
<string name="all_allow_notification_toast">\"%1$s\" ग्रुप के सभी नोटीफिकेशन स्वीकृत है </string>
|
||||
<string name="all_deny_notification_toast"> \"%1$s\" ग्रुप के सभी नोटीफिकेशन अस्वीकृत है </string>
|
||||
<string name="parse_full_content">पूरा पाठ दिखाएँ </string>
|
||||
<string name="all_parse_full_content_tips"> \"%1$s\" ग्रुप के सभी पाठ पूरे दिखाएँ </string>
|
||||
<string name="all_parse_full_content_toast"> \"%1$s\" ग्रुप के सभी पाठ पूरे दिखाएँ</string>
|
||||
<string name="all_deny_parse_full_content_toast"> \"%1$s\" ग्रुप के सभी पाठ पूरे ना दिखाएँ</string>
|
||||
<string name="clear_articles">पाठ हटाएँ </string>
|
||||
<string name="clear_articles_in_feed_toast">\"%1$s\" फीड के सभी संग्रहित पाठो को हटाएँ </string>
|
||||
<string name="clear_articles_in_group_toast"> \"%1$s\"फीड के सभी संग्रहित पाठ हटा दिए है </string>
|
||||
<string name="clear_articles_feed_tips"> \"%1$s\" फीड के सभी संग्रहित पाठ हटाएँ .</string>
|
||||
<string name="clear_articles_group_tips">\"%1$s\" ग्रुप के सभी संग्रहित पाठो को हटाएँ.</string>
|
||||
<string name="add_to_group">ग्रुप में जोड़ें </string>
|
||||
<string name="move_to_group">ग्रुप में स्तानान्तरित करें </string>
|
||||
<string name="all_move_to_group_tips">\"%1$s\" ग्रुप के सभी पाठो को \"%2$s\" में स्थानांतरित करें .</string>
|
||||
<string name="all_move_to_group_toast">\"%1$s\" ग्रुप में स्थानांतरण पूरा हुआ </string>
|
||||
<string name="rename">नाम बदलें </string>
|
||||
<string name="change_url">यु आर एल बदलें </string>
|
||||
<string name="rename_toast">नया नाम \"%1$s\"</string>
|
||||
<string name="create_new_group">नया ग्रुप बनाएँ </string>
|
||||
<string name="name">नाम </string>
|
||||
<string name="open_with">खोलें %1$s</string>
|
||||
<string name="options">विकल्प </string>
|
||||
<string name="delete">मिटाएं </string>
|
||||
<string name="delete_toast">मिट गया \"%1$s\"</string>
|
||||
<string name="unsubscribe">सदस्यता छोडें</string>
|
||||
<string name="unsubscribe_tips"> \"%1$s\" से सदस्यता छोडें और सभी संग्रहित पाठों को मिटाएं </string>
|
||||
<string name="delete_group">ग्रुप को मिटाएँ </string>
|
||||
<string name="delete_group_tips"> \"%1$s\" ग्रुप के सभी फ़ीड्स अथवा संग्रहित पाठों को मिटाएँ </string>
|
||||
<string name="group_option_tips">निम्नलिखित विकल्प ग्रुप के सभी फ़ीडस् पर लागू होंगे</string>
|
||||
<string name="today">आज </string>
|
||||
<string name="yesterday">कल </string>
|
||||
<string name="date_at_time">तिथि %1$s समय %2$s</string>
|
||||
<string name="search_for_in"> %1$s के लिए \"%2$s\ में खोजें "</string>
|
||||
<string name="search_for">पाठों में %1$s खोजें </string>
|
||||
<string name="mark_as_read">पढ़ा हुआ चिन्हित करें </string>
|
||||
<string name="mark_all_as_read">सभी को पढ़ा हुआ चिन्हित करें</string>
|
||||
<string name="mark_as_unread">अपठित के रूप में चिह्नित करें</string>
|
||||
<string name="mark_as_starred">तारांकित के रूप में चिह्नित करें</string>
|
||||
<string name="mark_as_unstar">अतारांकित के रूप में चिह्नित करें</string>
|
||||
<string name="mark_as_read_one_day">1 दिन से अधिक पढ़ें के रूप में चिह्नित करें</string>
|
||||
<string name="mark_as_read_three_days">3 दिन से अधिक पढ़ें के रूप में चिह्नित करें</string>
|
||||
<string name="mark_as_read_seven_days">7 दिन से अधिक पढ़ें के रूप में चिह्नित करें</string>
|
||||
<string name="one_day">1 दिन </string>
|
||||
<string name="three_days">3 दिन </string>
|
||||
<string name="seven_days">7 दिन </string>
|
||||
<string name="close">बंद करें </string>
|
||||
<string name="get_new_updates">नया अपडेट प्राप्त करें</string>
|
||||
<string name="get_new_updates_desc"> %1$s वर्ज़न उपलब्ध है </string>
|
||||
<string name="in_coding">कोडिंग चल रही है....</string>
|
||||
<string name="coming_soon">जल्द आ रहा है...</string>
|
||||
<string name="accounts">खाते</string>
|
||||
<string name="accounts_desc">लोकल, नया आर एस एस </string>
|
||||
<string name="color_and_style">रंग अथवा शैली </string>
|
||||
<string name="color_and_style_desc">थीम , रंग शैली , लिपि आकार </string>
|
||||
<string name="interaction">Interaction</string>
|
||||
<string name="interaction_desc">शुरू होने पे , हैप्टिक फीडबैक </string>
|
||||
<string name="languages">भाषाएँ </string>
|
||||
<string name="languages_desc">अंग्रेजी , चाइनीज, और..</string>
|
||||
<string name="help_translate">अनुवाद में मदद करें</string>
|
||||
<string name="use_device_languages">डिवाइस भाषा का उपयोग करें</string>
|
||||
<string name="tips_and_support">सुझाव और सहायता</string>
|
||||
<string name="tips_and_support_desc">परिचय, ओपन सोर्स लाइसेंस</string>
|
||||
<string name="welcome">स्वागत है </string>
|
||||
<string name="tos_tips">आगे बढ़ने के लिए Read Youकी सेवा शर्तें और गोपनीयता नीति को पढ़े और स्वीकार करें </string>
|
||||
<string name="browse_tos_tips">यहाँ <i><u>सेवा शर्तें और गोपनीयता नीति पढ़े </u></i>
|
||||
</string>
|
||||
<string name="terms_of_service">सेवा की शर्तें</string>
|
||||
<string name="tos_content">
|
||||
<h5>
|
||||
|
||||
गोपनीयता नीति
|
||||
|
||||
</h5>
|
||||
<br/>
|
||||
<p>
|
||||
|
||||
मैं आपकी गोपनीयता को बहुत गंभीरता से लेता हूं
|
||||
|
||||
</p>
|
||||
<br/>
|
||||
<p>
|
||||
<b>Read You</b>
|
||||
|
||||
कोई उपयोगकर्ता डेटा एकत्र नहीं करता है, और सभी संवेदनशील जानकारी (पासवर्ड और अन्य खाता जानकारी)
|
||||
आपके डिवाइस पर स्थानीय एप्लिकेशन डेटाबेस में सुरक्षित रूप से संग्रहीत है|
|
||||
|
||||
</p>
|
||||
<br/>
|
||||
<p>
|
||||
<b>Read You</b>
|
||||
|
||||
आपको सेवा प्रदान करने के लिए निम्नलिखित अनुमतियों का उपयोग किया जाएगा।
|
||||
|
||||
</p>
|
||||
<br/>
|
||||
<p>
|
||||
|
||||
- एक्सेस नेटवर्क अनुमति (आपके द्वारा निर्देशित ऑनलाइन सामग्री तक पहुँचने के लिए)
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
- नेटवर्क स्थिति की अनुमति (यह जानने करने के लिए कि क्या डिवाइस में वर्तमान में नेटवर्क की स्थिति उपलब्ध है)
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
-पृष्ठभूमिक सेवा अनुमति (नियमित रूप से अपने पसंदीदार पाठों को स्वचालित रूप से नियमित सिंक करने के लिए आधार)
|
||||
|
||||
</p>
|
||||
<br/>
|
||||
<br/>
|
||||
<h5>
|
||||
|
||||
तृतीय पक्ष सेवाएं
|
||||
|
||||
</h5>
|
||||
<br/>
|
||||
<p>
|
||||
|
||||
यह नीति आपके द्वारा <b>Read You</b>के साथ उपयोग की जाने वाली तृतीय-पक्ष सेवाओं पर लागू नहीं होती है. आप उन वेबसाइटों की गोपनीयता नीतियों की समीक्षा
|
||||
करने हेतु स्वतंत्र है|
|
||||
|
||||
</p>
|
||||
<br/>
|
||||
<br/>
|
||||
<h5>
|
||||
|
||||
अस्वीकरण
|
||||
|
||||
</h5>
|
||||
<br/>
|
||||
<p>
|
||||
<b>Read You</b>
|
||||
|
||||
केवल एक सामग्री संग्रह उपकरण है।. आपके द्वारा <b>Read You</b> का उपयोग आपके देश/राष्ट्र और क्षेत्र के नियम ऐवं कानून के अंतर्गत है
|
||||
और आपके कार्यों से उत्पन्न होने वाले किसी भी दायित्व का वहन आपके द्वारा ही किया जाएगा |
|
||||
|
||||
</p>
|
||||
<br/>
|
||||
<br/>
|
||||
<h5>
|
||||
|
||||
ओपन सोर्स लाइसेंस
|
||||
|
||||
</h5>
|
||||
<br/>
|
||||
<p>
|
||||
<b>Read You</b>
|
||||
|
||||
GNU GPL 3.0 Open Source License[1] के अंतर्गत एक ओपन सौरसे प्रोजेक्ट है, जो आपको <b>Read You</b> के सोर्स कोड को उपयोग,
|
||||
प्रासंगिक सन्दर्भ और मुफ्त में संशोधित करेने के अनुमति देता है, परन्तु संशोधित और व्युत्पन्न कोड को क्लोज्ड-सोर्स वाणिज्यिक सॉफ्टवेयर के रूप में वितरित और बेचा जाने की अनुमति नहीं देता ।
|
||||
पूर्ण जानकारी हेतु GNU GPL 3.0 Open Source License[2]. देखें।
|
||||
|
||||
</p>
|
||||
<br/>
|
||||
<br/>
|
||||
<h5>
|
||||
|
||||
शेषसंग्रह
|
||||
|
||||
</h5>
|
||||
<br/>
|
||||
<p>
|
||||
|
||||
- [1] https://github.com/Ashinch/ReadYou
|
||||
|
||||
</p>
|
||||
<p>
|
||||
|
||||
- [2] https://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
</p>
|
||||
</string>
|
||||
<string name="agree">स्वीकृत करें </string>
|
||||
<string name="wallpaper_colors">वॉलपेपर रंग</string>
|
||||
<string name="no_palettes">कोई पैलेट नहीं</string>
|
||||
<string name="only_android_8.1_plus">केवल Android 8.1+ हेतु </string>
|
||||
<string name="basic_colors">मूल रंग</string>
|
||||
<string name="primary_color">प्राथमिक रंग</string>
|
||||
<string name="primary_color_hint">जैसे #666666 या 666666</string>
|
||||
<string name="appearance">रूप </string>
|
||||
<string name="style">शैली</string>
|
||||
<string name="dark_theme">डार्क थीम </string>
|
||||
<string name="use_device_theme"> डिवाइस थीम का उपयोग करें </string>
|
||||
<string name="on">ओन</string>
|
||||
<string name="off">ऑफ</string>
|
||||
<string name="other">अन्य </string>
|
||||
<string name="amoled_dark_theme">अमोलेड डार्क थीम</string>
|
||||
<string name="tonal_elevation">टोनल एलिवेशन</string>
|
||||
<string name="reading_fonts">रीडिंग फोंट</string>
|
||||
<string name="basic_fonts">बेसिक फोंट </string>
|
||||
<string name="feeds_page">फ़ीड्स पेज </string>
|
||||
<string name="flow_page">फ्लो पेज </string>
|
||||
<string name="reading_page">रीडिंग पेज </string>
|
||||
<string name="sponsor">प्रायोजक</string>
|
||||
<string name="open_source_licenses">Open source licenses</string>
|
||||
<string name="update_link">https://api.github.com/repos/Ashinch/ReadYou/releases/latest</string>
|
||||
<string name="change_log">बदलाव सूचि </string>
|
||||
<string name="update">अपडेट</string>
|
||||
<string name="skip_this_version">इस वर्जन को छोडें </string>
|
||||
<string name="checking_updates">अपडेट के लिए जाँच कर रहा है</string>
|
||||
<string name="is_latest_version">यह लेटेस्ट अपडेट है </string>
|
||||
<string name="check_failure">अपडेट की जाँच नहीं कर पाए </string>
|
||||
<string name="download_failure">अपडेट डाउनलोड नहीं कर पाए </string>
|
||||
<string name="rate_limit">अनुरोध दर सीमित है</string>
|
||||
<string name="help">सहायता </string>
|
||||
<string name="on_start">चालू होने पर</string>
|
||||
<string name="initial_page">प्रारंभिक पृष्ठ</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="horizontal_padding">दोनों सिरों पर पैडिंग</string>
|
||||
<string name="article_date">पाठ प्रकाशन दिनांक </string>
|
||||
<string name="article_desc">पाठ विवरण </string>
|
||||
<string name="article_images">पाठ चित्र कलाएँ</string>
|
||||
<string name="feed_names">फीड के नाम </string>
|
||||
<string name="feed_favicons">फीड फविकों </string>
|
||||
<string name="article_date_sticky_header">प्रकाशन तिथि के लिए स्टिकी हेडर (प्रयोगात्मक)</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>
|
||||
<string name="share">साँझा करें </string>
|
||||
<string name="touch_to_play_video">विडियो चलने हेतु टच करें </string>
|
||||
<string name="text">पाठा </string>
|
||||
<string name="font_size">फोंट साइज</string>
|
||||
<string name="letter_spacing">लैटर स्पेसिंग</string>
|
||||
<string name="line_spacing">लाइन स्पेसिंग </string>
|
||||
<string name="alignment">संरेखण</string>
|
||||
<string name="general">सामान्य </string>
|
||||
<string name="auto_hide_toolbars">टूलबार स्वतः छुपाएँ </string>
|
||||
<string name="rearrange_buttons">बटन पुनर्व्यवस्थित करें </string>
|
||||
<string name="bionic_reading">बैओनिक पाठन</string>
|
||||
<string name="images">चित्र</string>
|
||||
<string name="rounded_corners">गोल कोने </string>
|
||||
<string name="videos">चलचित्र</string>
|
||||
<string name="align_left">बाये संरेखित करें </string>
|
||||
<string name="align_right">दाएँ संरेखित करें </string>
|
||||
<string name="center_text">पाठ मध्य संरेखित करें </string>
|
||||
<string name="justify">संयोजिक करें </string>
|
||||
<string name="external_fonts">बाहरी फोंट</string>
|
||||
<string name="title">शीर्षक</string>
|
||||
<string name="bold">बोल्ड</string>
|
||||
<string name="upper_case">अपरकेस</string>
|
||||
<string name="subhead">उप शीर्षक</string>
|
||||
<string name="use_app_theme">एप की थीम लगाएं </string>
|
||||
<string name="advanced">एडवांस </string>
|
||||
<string name="dark_reading_theme">डार्क रीडर थीम</string>
|
||||
<string name="title_desc">बोल्ड, उपरेखा, संरेखित </string>
|
||||
<string name="text_desc">फोंट साईज, पंक्ति और अनुछेद रिक्त , संरेख</string>
|
||||
<string name="images_desc">गोल कोण ,क्षैतिज पेडिंग </string>
|
||||
<string name="videos_desc">गोल कोण ,क्षैतिज पेडिंग</string>
|
||||
<string name="maximize">बड़ा करें</string>
|
||||
</resources>
|
|
@ -233,7 +233,7 @@
|
|||
<string name="other">Altro</string>
|
||||
<string name="amoled_dark_theme">Tema scuro AMOLED</string>
|
||||
<string name="tonal_elevation">Elevazione tonale</string>
|
||||
<string name="fonts">Font</string>
|
||||
<string name="reading_fonts">Font di lettura</string>
|
||||
<string name="basic_fonts">Font di base</string>
|
||||
<string name="feeds_page">Pagina dei feed</string>
|
||||
<string name="flow_page">Pagina dei flow</string>
|
||||
|
@ -257,7 +257,7 @@
|
|||
<string name="preview_article_desc">Lo Sciocco è l\'ottavo e ultimo volume della serie Il Signore dei Misteri, scritta da Seppia Che Ama Le Immersioni.</string>
|
||||
<string name="preview_feed_name">Reddit</string>
|
||||
<string name="value">valore</string>
|
||||
<string name="padding_on_both_ends">Padding su entrambe le estremità</string>
|
||||
<string name="horizontal_padding">Imbottitura orizzontale</string>
|
||||
<string name="article_date">Tempo di pubblicazione dell\'articolo</string>
|
||||
<string name="article_desc">Descrizione dell\'articolo</string>
|
||||
<string name="article_images">Immagini dell\'articolo</string>
|
||||
|
@ -280,4 +280,33 @@
|
|||
<string name="tips_group_list_tonal_elevation">Questa elevazione tonale è disponibile solo con il tema chiaro.</string>
|
||||
<string name="share">Condividi</string>
|
||||
<string name="touch_to_play_video">Tocca per riprodurre il video</string>
|
||||
<string name="text">Text</string>
|
||||
<string name="font_size">Font size</string>
|
||||
<string name="letter_spacing">Letter spacing</string>
|
||||
<string name="line_spacing">Line spacing</string>
|
||||
<string name="alignment">Alignment</string>
|
||||
<string name="general">General</string>
|
||||
<string name="auto_hide_toolbars">Auto hide toolbars</string>
|
||||
<string name="rearrange_buttons">Rearrange buttons</string>
|
||||
<string name="bionic_reading">Bionic Reading</string>
|
||||
<string name="images">Images</string>
|
||||
<string name="rounded_corners">Rounded corners</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="align_left">Align left</string>
|
||||
<string name="align_right">Align right</string>
|
||||
<string name="center_text">Center text</string>
|
||||
<string name="justify">Justify</string>
|
||||
<string name="external_fonts">External fonts</string>
|
||||
<string name="title">Title</string>
|
||||
<string name="bold">Bold</string>
|
||||
<string name="upper_case">Upper case</string>
|
||||
<string name="subhead">Subhead</string>
|
||||
<string name="use_app_theme">Use app theme</string>
|
||||
<string name="advanced">Advanced</string>
|
||||
<string name="dark_reading_theme">Dark reading theme</string>
|
||||
<string name="title_desc">Bold, upper case, alignment</string>
|
||||
<string name="text_desc">Font size, letter spacing, alignment</string>
|
||||
<string name="images_desc">Rounded corners, horizontal padding</string>
|
||||
<string name="videos_desc">Rounded corners, horizontal padding</string>
|
||||
<string name="maximize">Maximize</string>
|
||||
</resources>
|
||||
|
|
|
@ -224,7 +224,7 @@
|
|||
<string name="amoled_dark_theme">AMOLED 深色主题</string>
|
||||
<string name="other">其他</string>
|
||||
<string name="tonal_elevation">色调海拔</string>
|
||||
<string name="fonts">字体</string>
|
||||
<string name="reading_fonts">阅读字体</string>
|
||||
<string name="basic_fonts">基本字体</string>
|
||||
<string name="feeds_page">订阅源页面</string>
|
||||
<string name="flow_page">信息流页面</string>
|
||||
|
@ -245,10 +245,12 @@
|
|||
<string name="initial_page">起始页面</string>
|
||||
<string name="initial_filter">起始过滤条件</string>
|
||||
<string name="preview_article_title">呜呜呜,黎明之剑完结了</string>
|
||||
<string name="preview_article_desc">是宴席,就有结束的时候,但这本书真的陪了我好久啊,好舍不得,而且主线结束了坑却没填完,不知道啥时候才有番外啊</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="horizontal_padding">水平填充</string>
|
||||
<string name="article_date">文章发布时间</string>
|
||||
<string name="article_desc">文章描述</string>
|
||||
<string name="article_images">文章插图</string>
|
||||
|
@ -271,4 +273,33 @@
|
|||
<string name="tips_group_list_tonal_elevation">分组列表的色调海拔仅在亮色主题时可用。</string>
|
||||
<string name="share">分享</string>
|
||||
<string name="touch_to_play_video">轻触播放视频</string>
|
||||
<string name="text">文本</string>
|
||||
<string name="font_size">字体大小</string>
|
||||
<string name="letter_spacing">字符间距</string>
|
||||
<string name="line_spacing">行间距</string>
|
||||
<string name="alignment">对齐</string>
|
||||
<string name="general">通用</string>
|
||||
<string name="auto_hide_toolbars">自动隐藏工具条</string>
|
||||
<string name="rearrange_buttons">重新排列按钮</string>
|
||||
<string name="bionic_reading">仿生阅读</string>
|
||||
<string name="images">图片</string>
|
||||
<string name="rounded_corners">圆角</string>
|
||||
<string name="videos">视频</string>
|
||||
<string name="align_left">左对齐</string>
|
||||
<string name="align_right">右对齐</string>
|
||||
<string name="center_text">居中对齐</string>
|
||||
<string name="justify">两端对齐</string>
|
||||
<string name="external_fonts">外部字体</string>
|
||||
<string name="title">标题</string>
|
||||
<string name="bold">加粗</string>
|
||||
<string name="upper_case">大写字母</string>
|
||||
<string name="subhead">子标题</string>
|
||||
<string name="use_app_theme">跟随应用设置</string>
|
||||
<string name="advanced">高级</string>
|
||||
<string name="dark_reading_theme">深色阅读主题</string>
|
||||
<string name="title_desc">加粗、大写字母、对齐</string>
|
||||
<string name="text_desc">字体大小、字符间距、对齐</string>
|
||||
<string name="images_desc">圆角、水平边距</string>
|
||||
<string name="videos_desc">圆角、水平边距</string>
|
||||
<string name="maximize">最大化</string>
|
||||
</resources>
|
||||
|
|
|
@ -111,6 +111,7 @@
|
|||
<string name="french" translatable="false">français</string>
|
||||
<string name="czech" translatable="false">Čeština</string>
|
||||
<string name="italian" translatable="false">italiano</string>
|
||||
<string name="hindi" translatable="false">हिंदी</string>
|
||||
<string name="tips_and_support">Tips & support</string>
|
||||
<string name="tips_and_support_desc">About, open source licenses</string>
|
||||
<string name="welcome">Welcome</string>
|
||||
|
@ -244,7 +245,7 @@
|
|||
<string name="other">Other</string>
|
||||
<string name="amoled_dark_theme">AMOLED dark theme</string>
|
||||
<string name="tonal_elevation">Tonal elevation</string>
|
||||
<string name="fonts">Fonts</string>
|
||||
<string name="reading_fonts">Reading fonts</string>
|
||||
<string name="basic_fonts">Basic fonts</string>
|
||||
<string name="feeds_page">Feeds page</string>
|
||||
<string name="flow_page">Flow page</string>
|
||||
|
@ -272,7 +273,7 @@
|
|||
</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="horizontal_padding">Horizontal padding</string>
|
||||
<string name="article_date">Article publication time</string>
|
||||
<string name="article_desc">Article descriptions</string>
|
||||
<string name="article_images">Article images</string>
|
||||
|
@ -295,4 +296,33 @@
|
|||
<string name="tips_group_list_tonal_elevation">This tonal elevation is only available in the light theme.</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="touch_to_play_video">Touch to play video</string>
|
||||
<string name="text">Text</string>
|
||||
<string name="font_size">Font size</string>
|
||||
<string name="letter_spacing">Letter spacing</string>
|
||||
<string name="line_spacing">Line spacing</string>
|
||||
<string name="alignment">Alignment</string>
|
||||
<string name="general">General</string>
|
||||
<string name="auto_hide_toolbars">Auto hide toolbars</string>
|
||||
<string name="rearrange_buttons">Rearrange buttons</string>
|
||||
<string name="bionic_reading">Bionic Reading</string>
|
||||
<string name="images">Images</string>
|
||||
<string name="rounded_corners">Rounded corners</string>
|
||||
<string name="videos">Videos</string>
|
||||
<string name="align_left">Align left</string>
|
||||
<string name="align_right">Align right</string>
|
||||
<string name="center_text">Center text</string>
|
||||
<string name="justify">Justify</string>
|
||||
<string name="external_fonts">External fonts</string>
|
||||
<string name="title">Title</string>
|
||||
<string name="bold">Bold</string>
|
||||
<string name="upper_case">Upper case</string>
|
||||
<string name="subhead">Subhead</string>
|
||||
<string name="use_app_theme">Use app theme</string>
|
||||
<string name="advanced">Advanced</string>
|
||||
<string name="dark_reading_theme">Dark reading theme</string>
|
||||
<string name="title_desc">Bold, upper case, alignment</string>
|
||||
<string name="text_desc">Font size, letter spacing, alignment</string>
|
||||
<string name="images_desc">Rounded corners, horizontal padding</string>
|
||||
<string name="videos_desc">Rounded corners, horizontal padding</string>
|
||||
<string name="maximize">Maximize</string>
|
||||
</resources>
|
||||
|
|
17
fastlane/metadata/android/de-DE/changelogs/12.txt
Normal file
17
fastlane/metadata/android/de-DE/changelogs/12.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
## 0.8.1
|
||||
|
||||
1. Französische Sprache hinzugefügt (Dank an DodoLeDev).
|
||||
|
||||
2. Tschechische Sprache hinzugefügt (Dank an Fjuro).
|
||||
|
||||
3. Einige übersetzte Texte geändert (Dank an comradekingu).
|
||||
|
||||
4. Behebung des Problems, das nach dem Import einer OPML-Datei aus Version 0.8.0 nicht synchronisiert werden kann.
|
||||
|
||||
5. Behebung eines Absturzes beim Laden sehr großer Bilder (50 MB+) (Dank an Feeder).
|
||||
|
||||
6. Behebung des Problems, dass einige Feeds nicht abonniert werden konnten (Dank an kzaemrio).
|
||||
|
||||
7. Optimierung im Falle von zu vielen Feeds (100+).
|
||||
|
||||
8. Einige Leistungsoptimierungen und Detailänderungen.
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user