feat:添加浅色、深色切换提醒功能 (#1584)
* feat:添加浅色、深色切换提醒功能 * refactor: 重构SwitchDayNightReminder为通用ActionReminder - ReadConfigScreen 补上 主题模式切换提醒 开关
This commit is contained in:
@@ -103,6 +103,7 @@ object PreferKey {
|
||||
const val adaptSpecialStyle = "adaptSpecialStyle"
|
||||
const val autoClearExpired = "autoClearExpired"
|
||||
const val autoChangeSource = "autoChangeSource"
|
||||
const val autoSuggestDayNight = "autoSuggestDayNight"
|
||||
const val importKeepName = "importKeepName"
|
||||
const val importKeepGroup = "importKeepGroup"
|
||||
const val screenOrientation = "screenOrientation"
|
||||
|
||||
@@ -45,6 +45,7 @@ data class ReadPreferences(
|
||||
val sliderVibrator: Boolean = false,
|
||||
val selectVibrator: Boolean = false,
|
||||
val autoChangeSource: Boolean = true,
|
||||
val autoSuggestDayNight: Boolean = false,
|
||||
val selectText: Boolean = true,
|
||||
val noAnimScrollPage: Boolean = false,
|
||||
val clickImgWay: String = "2",
|
||||
@@ -214,6 +215,9 @@ class ReadSettingsRepository(
|
||||
suspend fun setAutoChangeSource(value: Boolean) =
|
||||
settingsRepository.putBoolean(PreferKey.autoChangeSource, value)
|
||||
|
||||
suspend fun setAutoSuggestDayNight(value: Boolean) =
|
||||
settingsRepository.putBoolean(PreferKey.autoSuggestDayNight, value)
|
||||
|
||||
suspend fun setSelectText(value: Boolean) =
|
||||
settingsRepository.putBoolean(PreferKey.selectText, value)
|
||||
|
||||
@@ -422,6 +426,7 @@ class ReadSettingsRepository(
|
||||
sliderVibrator = this[Keys.SliderVibrator] ?: false,
|
||||
selectVibrator = this[Keys.SelectVibrator] ?: false,
|
||||
autoChangeSource = this[Keys.AutoChangeSource] ?: true,
|
||||
autoSuggestDayNight = this[Keys.AutoSuggestDayNight] ?: false,
|
||||
selectText = this[Keys.SelectText] ?: true,
|
||||
noAnimScrollPage = this[Keys.NoAnimScrollPage] ?: false,
|
||||
clickImgWay = this[Keys.ClickImgWay] ?: "2",
|
||||
@@ -522,6 +527,7 @@ class ReadSettingsRepository(
|
||||
val SliderVibrator = booleanPreferencesKey(PreferKey.sliderVibrator)
|
||||
val SelectVibrator = booleanPreferencesKey(PreferKey.selectVibrator)
|
||||
val AutoChangeSource = booleanPreferencesKey(PreferKey.autoChangeSource)
|
||||
val AutoSuggestDayNight = booleanPreferencesKey(PreferKey.autoSuggestDayNight)
|
||||
val SelectText = booleanPreferencesKey(PreferKey.selectText)
|
||||
val NoAnimScrollPage = booleanPreferencesKey(PreferKey.noAnimScrollPage)
|
||||
val ClickImgWay = stringPreferencesKey(PreferKey.clickImgWay)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package io.legado.app.ui.book.read
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import io.legado.app.ui.theme.LegadoTheme
|
||||
import io.legado.app.ui.widget.components.card.NormalCard
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@Composable
|
||||
fun ActionReminder(
|
||||
modifier: Modifier = Modifier,
|
||||
reminder: ReminderUiState?,
|
||||
onAction: (ReminderUiState) -> Unit,
|
||||
onDismiss: () -> Unit,
|
||||
) {
|
||||
val show = reminder != null
|
||||
var currentReminder by remember { mutableStateOf(reminder) }
|
||||
if (reminder != null) {
|
||||
currentReminder = reminder
|
||||
}
|
||||
|
||||
LaunchedEffect(show, reminder?.id) {
|
||||
if (show) {
|
||||
delay(4.seconds)
|
||||
onDismiss()
|
||||
}
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.navigationBarsPadding(),
|
||||
contentAlignment = Alignment.BottomCenter,
|
||||
) {
|
||||
AnimatedVisibility(
|
||||
visible = show,
|
||||
enter = slideInVertically(initialOffsetY = { it }) + fadeIn(),
|
||||
exit = slideOutVertically(targetOffsetY = { it }) + fadeOut(),
|
||||
) {
|
||||
currentReminder?.let { target ->
|
||||
NormalCard(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 8.dp),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 16.dp, top = 8.dp, end = 12.dp, bottom = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
Text(
|
||||
text = target.message,
|
||||
fontSize = 13.sp,
|
||||
style = LegadoTheme.typography.bodyMedium,
|
||||
color = LegadoTheme.colorScheme.onSurface,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(end = 12.dp),
|
||||
)
|
||||
if (target.actionText != null) {
|
||||
Button(
|
||||
onClick = {
|
||||
onDismiss()
|
||||
onAction(target)
|
||||
},
|
||||
modifier = Modifier.height(32.dp),
|
||||
contentPadding = PaddingValues(horizontal = 14.dp, vertical = 0.dp),
|
||||
) {
|
||||
Text(target.actionText, fontSize = 12.sp)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,15 @@ import kotlinx.collections.immutable.ImmutableList
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
import java.util.UUID
|
||||
|
||||
@Stable
|
||||
data class ReminderUiState(
|
||||
val id: String = UUID.randomUUID().toString(),
|
||||
val message: String,
|
||||
val actionText: String? = null,
|
||||
val actionIntent: ReadBookIntent? = null,
|
||||
)
|
||||
|
||||
@Stable
|
||||
data class ReadBookMenuState(
|
||||
@@ -94,6 +103,7 @@ data class ReadBookUiState(
|
||||
val isLocalBook: Boolean = true,
|
||||
val msg: String? = null,
|
||||
val isInitFinish: Boolean = false,
|
||||
val activeReminder: ReminderUiState? = null,
|
||||
// Search
|
||||
val searchMenuVisible: Boolean = false,
|
||||
val isShowingSearchResult: Boolean = false,
|
||||
@@ -242,6 +252,8 @@ sealed interface ReadBookIntent {
|
||||
// Initialization
|
||||
data class InitData(val intent: android.content.Intent) : ReadBookIntent
|
||||
data class InitReadBookConfig(val intent: android.content.Intent) : ReadBookIntent
|
||||
data class CheckSwitchDayNight(val lux: Float) : ReadBookIntent
|
||||
data object DismissReminder : ReadBookIntent
|
||||
|
||||
// Navigation
|
||||
data object NextPage : ReadBookIntent
|
||||
@@ -1175,6 +1187,9 @@ sealed interface ConfigUpdate {
|
||||
data class AutoChangeSource(val value: Boolean) : ConfigUpdate {
|
||||
override val actions = emptySet<ConfigUpdateAction>()
|
||||
}
|
||||
data class AutoSuggestDayNight(val value: Boolean) : ConfigUpdate {
|
||||
override val actions = emptySet<ConfigUpdateAction>()
|
||||
}
|
||||
data class SelectText(val value: Boolean) : ConfigUpdate {
|
||||
override val actions = emptySet<ConfigUpdateAction>()
|
||||
}
|
||||
|
||||
@@ -17,10 +17,18 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import android.content.Context
|
||||
import android.hardware.Sensor
|
||||
import android.hardware.SensorEvent
|
||||
import android.hardware.SensorEventListener
|
||||
import android.hardware.SensorManager
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import io.legado.app.ui.config.readConfig.ReadConfig
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.kyant.backdrop.backdrops.layerBackdrop
|
||||
@@ -233,6 +241,44 @@ fun ReadBookRouteScreen(
|
||||
viewModel.onIntent(ReadBookIntent.BookInfoResult(result.resultCode == android.app.Activity.RESULT_OK))
|
||||
}
|
||||
|
||||
DisposableEffect(lifecycleOwner) {
|
||||
val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as? SensorManager
|
||||
val lightSensor = sensorManager?.getDefaultSensor(Sensor.TYPE_LIGHT)
|
||||
var listener: SensorEventListener? = null
|
||||
|
||||
val observer = LifecycleEventObserver { _, event ->
|
||||
if (event == Lifecycle.Event.ON_RESUME) {
|
||||
if (!ReadConfig.autoSuggestDayNight) return@LifecycleEventObserver
|
||||
if (lightSensor != null) {
|
||||
listener = object : SensorEventListener {
|
||||
override fun onSensorChanged(sensorEvent: SensorEvent?) {
|
||||
sensorEvent?.values?.firstOrNull()?.let { lux ->
|
||||
//Log.d("fansangg","lux = $lux")
|
||||
viewModel.onIntent(ReadBookIntent.CheckSwitchDayNight(lux))
|
||||
}
|
||||
listener?.let { sensorManager.unregisterListener(it) }
|
||||
listener = null
|
||||
}
|
||||
|
||||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
|
||||
}
|
||||
sensorManager.registerListener(listener, lightSensor, SensorManager.SENSOR_DELAY_NORMAL)
|
||||
}
|
||||
} else if (event == Lifecycle.Event.ON_PAUSE) {
|
||||
listener?.let {
|
||||
sensorManager?.unregisterListener(it)
|
||||
listener = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleOwner.lifecycle.addObserver(observer)
|
||||
onDispose {
|
||||
lifecycleOwner.lifecycle.removeObserver(observer)
|
||||
listener?.let { sensorManager?.unregisterListener(it) }
|
||||
}
|
||||
}
|
||||
|
||||
// ── Effect collection: route handles launcher effects, rest goes to bridge ──
|
||||
|
||||
LaunchedEffect(viewModel) {
|
||||
|
||||
@@ -503,4 +503,10 @@ fun ReadBookScreen(
|
||||
// Sheets using AppModalBottomSheet are composed unconditionally above
|
||||
else -> {}
|
||||
}
|
||||
|
||||
ActionReminder(
|
||||
reminder = state.activeReminder,
|
||||
onAction = { reminder -> reminder.actionIntent?.let { onIntent(it) } },
|
||||
onDismiss = { onIntent(ReadBookIntent.DismissReminder) },
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import android.provider.OpenableColumns
|
||||
import android.speech.tts.TextToSpeech
|
||||
import android.util.Base64
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.core.graphics.toColorInt
|
||||
import androidx.core.graphics.ColorUtils as AndroidColorUtils
|
||||
import io.legado.app.BuildConfig
|
||||
import io.legado.app.R
|
||||
import io.legado.app.constant.AppConst
|
||||
@@ -76,6 +78,7 @@ import io.legado.app.ui.config.themeConfig.ThemeConfig
|
||||
import io.legado.app.ui.widget.components.importComponents.BaseImportUiState
|
||||
import io.legado.app.ui.widget.components.importComponents.ImportItemWrapper
|
||||
import io.legado.app.ui.widget.components.importComponents.ImportStatus
|
||||
import io.legado.app.utils.ColorUtils
|
||||
import io.legado.app.utils.GSON
|
||||
import io.legado.app.utils.ImageSaveUtils
|
||||
import io.legado.app.utils.NetworkUtils
|
||||
@@ -120,6 +123,7 @@ import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.FileNotFoundException
|
||||
import kotlin.coroutines.coroutineContext
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
/**
|
||||
* 阅读界面 ViewModel — MVI/UDF 架构
|
||||
@@ -196,6 +200,8 @@ class ReadBookViewModel(
|
||||
justInitData = true
|
||||
}
|
||||
is ReadBookIntent.InitReadBookConfig -> initReadBookConfig(intent.intent)
|
||||
is ReadBookIntent.CheckSwitchDayNight -> checkSwitchDayNight(intent.lux)
|
||||
is ReadBookIntent.DismissReminder -> dismissReminder()
|
||||
is ReadBookIntent.NextPage -> ReadBook.moveToNextPage()
|
||||
is ReadBookIntent.PrevPage -> ReadBook.moveToPrevPage()
|
||||
is ReadBookIntent.NextChapter -> ReadBook.moveToNextChapter(upContent = true)
|
||||
@@ -3430,6 +3436,12 @@ class ReadBookViewModel(
|
||||
readSettingsRepository.setAutoChangeSource(update.value)
|
||||
}
|
||||
}
|
||||
is ConfigUpdate.AutoSuggestDayNight -> {
|
||||
ReadConfig.autoSuggestDayNight = update.value
|
||||
viewModelScope.launch {
|
||||
readSettingsRepository.setAutoSuggestDayNight(update.value)
|
||||
}
|
||||
}
|
||||
is ConfigUpdate.SelectText -> {
|
||||
ReadConfig.selectText = update.value
|
||||
viewModelScope.launch {
|
||||
@@ -4007,6 +4019,86 @@ class ReadBookViewModel(
|
||||
context.toastOnUi("添加书籍失败")
|
||||
}
|
||||
}
|
||||
|
||||
private var lastSwitchDayNightReminderTime: Long = 0L
|
||||
private val reminderQueue = ArrayDeque<ReminderUiState>()
|
||||
|
||||
private fun showReminder(reminder: ReminderUiState) {
|
||||
if (_uiState.value.activeReminder == null && reminderQueue.isEmpty()) {
|
||||
_uiState.update { it.copy(activeReminder = reminder) }
|
||||
} else {
|
||||
reminderQueue.addLast(reminder)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isReadBgLight(colorInt: Int): Boolean {
|
||||
// io.legado.app.utils.ColorUtils.isColorLight 判断条件是 >= 0.5
|
||||
// 实际很多肉眼觉得亮的颜色会被判断为false,例如 0xFFC5B098
|
||||
return AndroidColorUtils.calculateLuminance(colorInt) >= LIGHT_LUMINANCE_THRESHOLD
|
||||
}
|
||||
|
||||
private fun checkSwitchDayNight(lux: Float) {
|
||||
if (!ReadConfig.autoSuggestDayNight) return
|
||||
if (System.currentTimeMillis() - lastSwitchDayNightReminderTime < REMINDER_COOLDOWN_MS) return
|
||||
|
||||
val isNight = ReadConfig.isNightTheme
|
||||
val styleConfig = _uiState.value.styleConfig
|
||||
if (!isNight && lux <= DARK_LUX_THRESHOLD) {
|
||||
val bgType = styleConfig.bgType
|
||||
val isLightBg = if (bgType == 0) {
|
||||
val colorInt = runCatching { styleConfig.bgStr.toColorInt() }.getOrDefault(0xFFEEEEEE.toInt())
|
||||
isReadBgLight(colorInt)
|
||||
} else {
|
||||
val meanColor = ReadBookConfig.bgMeanColor
|
||||
//Log.d("fansangg","meanColor = ${ColorUtils.intToString(meanColor)},isLight = ${isReadBgLight(meanColor)}")
|
||||
if (meanColor != 0) isReadBgLight(meanColor) else true
|
||||
}
|
||||
if (isLightBg) {
|
||||
lastSwitchDayNightReminderTime = System.currentTimeMillis()
|
||||
showReminder(
|
||||
ReminderUiState(
|
||||
message = context.getString(R.string.switch_to_dark_mode_tip),
|
||||
actionText = context.getString(R.string.switch_action),
|
||||
actionIntent = ReadBookIntent.ToggleDayNight,
|
||||
)
|
||||
)
|
||||
}
|
||||
} else if (isNight && lux >= BRIGHT_LUX_THRESHOLD) {
|
||||
val bgTypeNight = styleConfig.bgTypeNight
|
||||
val isDarkBg = if (bgTypeNight == 0) {
|
||||
val colorInt = runCatching { styleConfig.bgStrNight.toColorInt() }.getOrDefault(0xFF000000.toInt())
|
||||
!isReadBgLight(colorInt)
|
||||
} else {
|
||||
val meanColor = ReadBookConfig.bgMeanColor
|
||||
//Log.d("fansangg","meanColor = ${ColorUtils.intToString(meanColor)},isLight = ${isReadBgLight(meanColor)}")
|
||||
if (meanColor != 0) !isReadBgLight(meanColor) else true
|
||||
}
|
||||
if (isDarkBg) {
|
||||
lastSwitchDayNightReminderTime = System.currentTimeMillis()
|
||||
showReminder(
|
||||
ReminderUiState(
|
||||
message = context.getString(R.string.switch_to_light_mode_tip),
|
||||
actionText = context.getString(R.string.switch_action),
|
||||
actionIntent = ReadBookIntent.ToggleDayNight,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun dismissReminder() {
|
||||
_uiState.update { it.copy(activeReminder = null) }
|
||||
if (reminderQueue.isNotEmpty()) {
|
||||
viewModelScope.launch {
|
||||
//延迟一下,让上一个提醒的动画结束
|
||||
delay(500.milliseconds)
|
||||
if (_uiState.value.activeReminder == null && reminderQueue.isNotEmpty()) {
|
||||
val next = reminderQueue.removeFirst()
|
||||
_uiState.update { it.copy(activeReminder = next) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const val TITLE_BAR_ICON_PREFS = "title_bar_icons"
|
||||
@@ -4015,6 +4107,11 @@ private const val TOOL_BUTTON_PREFS = "tool_button_config"
|
||||
private const val TOOL_BUTTON_KEY = "tool_buttons"
|
||||
private const val DEFAULT_ENABLED_BUTTON_COUNT = 5
|
||||
|
||||
private const val DARK_LUX_THRESHOLD = 10f
|
||||
private const val BRIGHT_LUX_THRESHOLD = 100f
|
||||
private const val LIGHT_LUMINANCE_THRESHOLD = 0.35
|
||||
private const val REMINDER_COOLDOWN_MS = 10 * 60 * 1000L
|
||||
|
||||
private data class SearchTextPoint(
|
||||
val pageIndex: Int,
|
||||
val lineIndex: Int,
|
||||
|
||||
@@ -125,6 +125,9 @@ fun MoreConfigSheet(
|
||||
onAutoChangeSourceChange = {
|
||||
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.AutoChangeSource(it)))
|
||||
},
|
||||
onAutoSuggestDayNightChange = {
|
||||
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.AutoSuggestDayNight(it)))
|
||||
},
|
||||
onSelectTextChange = {
|
||||
onIntent(ReadBookIntent.UpdateConfig(ConfigUpdate.SelectText(it)))
|
||||
},
|
||||
@@ -298,6 +301,7 @@ private fun OtherSettings(
|
||||
onSliderVibratorChange: (Boolean) -> Unit,
|
||||
onSelectVibratorChange: (Boolean) -> Unit,
|
||||
onAutoChangeSourceChange: (Boolean) -> Unit,
|
||||
onAutoSuggestDayNightChange: (Boolean) -> Unit,
|
||||
onSelectTextChange: (Boolean) -> Unit,
|
||||
onNoAnimScrollPageChange: (Boolean) -> Unit,
|
||||
onOptimizeRenderChange: (Boolean) -> Unit,
|
||||
@@ -329,6 +333,12 @@ private fun OtherSettings(
|
||||
checked = preferences.autoChangeSource,
|
||||
onCheckedChange = onAutoChangeSourceChange,
|
||||
)
|
||||
TinySwitchSettingItem(
|
||||
title = stringResource(R.string.auto_switch_theme_reminder_title),
|
||||
description = stringResource(R.string.auto_switch_theme_reminder_desc),
|
||||
checked = preferences.autoSuggestDayNight,
|
||||
onCheckedChange = onAutoSuggestDayNightChange,
|
||||
)
|
||||
TinySwitchSettingItem(
|
||||
title = stringResource(R.string.selectText),
|
||||
checked = preferences.selectText,
|
||||
|
||||
@@ -214,6 +214,9 @@ object ReadConfig {
|
||||
var autoChangeSource
|
||||
get() = ReadDataConfig.autoChangeSource
|
||||
set(value) { ReadDataConfig.autoChangeSource = value }
|
||||
var autoSuggestDayNight
|
||||
get() = ReadDataConfig.autoSuggestDayNight
|
||||
set(value) { ReadDataConfig.autoSuggestDayNight = value }
|
||||
var defaultSourceChangeAll
|
||||
get() = ReadDataConfig.defaultSourceChangeAll
|
||||
set(value) { ReadDataConfig.defaultSourceChangeAll = value }
|
||||
@@ -299,6 +302,7 @@ object ReadConfig {
|
||||
keepLight = preferences.keepLight
|
||||
screenOrientation = preferences.screenOrientation
|
||||
autoChangeSource = preferences.autoChangeSource
|
||||
autoSuggestDayNight = preferences.autoSuggestDayNight
|
||||
defaultSourceChangeAll = preferences.defaultSourceChangeAll
|
||||
tocUiUseReplace = preferences.tocUiUseReplace
|
||||
tocCountWords = preferences.tocCountWords
|
||||
|
||||
@@ -29,6 +29,7 @@ data class ReadConfigUiState(
|
||||
val sliderVibrator: Boolean = false,
|
||||
val selectVibrator: Boolean = false,
|
||||
val autoChangeSource: Boolean = true,
|
||||
val autoSuggestDayNight: Boolean = false,
|
||||
val selectText: Boolean = true,
|
||||
val noAnimScrollPage: Boolean = false,
|
||||
val clickImgWay: String = "2",
|
||||
@@ -82,5 +83,6 @@ sealed interface ReadConfigIntent {
|
||||
data class TextSelectMenuFilterChanged(val value: String) : ReadConfigIntent
|
||||
data class ShowReadTitleAdditionChanged(val value: Boolean) : ReadConfigIntent
|
||||
data class ShowMenuIconChanged(val value: Boolean) : ReadConfigIntent
|
||||
data class AutoSuggestDayNightChanged(val value: Boolean) : ReadConfigIntent
|
||||
data class PageKeysChanged(val prevKeys: String, val nextKeys: String) : ReadConfigIntent
|
||||
}
|
||||
|
||||
@@ -307,6 +307,15 @@ fun ReadConfigScreen(
|
||||
}
|
||||
)
|
||||
|
||||
SwitchSettingItem(
|
||||
title = stringResource(R.string.auto_switch_theme_reminder_title),
|
||||
description = stringResource(R.string.auto_switch_theme_reminder_desc),
|
||||
checked = state.autoSuggestDayNight,
|
||||
onCheckedChange = {
|
||||
viewModel.onIntent(ReadConfigIntent.AutoSuggestDayNightChanged(it))
|
||||
}
|
||||
)
|
||||
|
||||
SwitchSettingItem(
|
||||
title = stringResource(R.string.selectText),
|
||||
checked = state.selectText,
|
||||
|
||||
@@ -166,6 +166,11 @@ class ReadConfigViewModel(
|
||||
readSettingsRepository.setAutoChangeSource(intent.value)
|
||||
}
|
||||
|
||||
is ReadConfigIntent.AutoSuggestDayNightChanged -> {
|
||||
ReadConfig.autoSuggestDayNight = intent.value
|
||||
readSettingsRepository.setAutoSuggestDayNight(intent.value)
|
||||
}
|
||||
|
||||
is ReadConfigIntent.SelectTextChanged -> {
|
||||
ReadConfig.selectText = intent.value
|
||||
readSettingsRepository.setSelectText(intent.value)
|
||||
@@ -267,6 +272,7 @@ class ReadConfigViewModel(
|
||||
sliderVibrator = sliderVibrator,
|
||||
selectVibrator = selectVibrator,
|
||||
autoChangeSource = autoChangeSource,
|
||||
autoSuggestDayNight = autoSuggestDayNight,
|
||||
selectText = selectText,
|
||||
noAnimScrollPage = noAnimScrollPage,
|
||||
clickImgWay = clickImgWay,
|
||||
|
||||
@@ -25,6 +25,11 @@ object ReadDataConfig {
|
||||
true
|
||||
)
|
||||
|
||||
var autoSuggestDayNight by prefDelegate(
|
||||
PreferKey.autoSuggestDayNight,
|
||||
false
|
||||
)
|
||||
|
||||
var defaultSourceChangeAll by prefDelegate(
|
||||
PreferKey.defaultSourceChangeAll,
|
||||
true
|
||||
|
||||
@@ -2213,4 +2213,11 @@
|
||||
<string name="is_event_listener">EventListener</string>
|
||||
<string name="rule_call_back">callBackJs</string>
|
||||
<!-- Missing zh-rTW/HK translations (683 keys) -->
|
||||
|
||||
<!-- 日夜间/深浅色主题切换提醒 -->
|
||||
<string name="auto_switch_theme_reminder_title">主题模式切换提醒</string>
|
||||
<string name="auto_switch_theme_reminder_desc">根据环境光提醒切换浅色/深色模式</string>
|
||||
<string name="switch_to_dark_mode_tip">当前环境光较暗,是否切换至深色模式?</string>
|
||||
<string name="switch_to_light_mode_tip">当前环境光较亮,是否切换至浅色模式?</string>
|
||||
<string name="switch_action">切换</string>
|
||||
</resources>
|
||||
|
||||
@@ -2205,4 +2205,11 @@
|
||||
<string name="weekday_tue">週二</string>
|
||||
<string name="weekday_wed">週三</string>
|
||||
<string name="welcome_title">歡迎!</string>
|
||||
|
||||
<!-- 日夜間/深淺色主題切換提醒 -->
|
||||
<string name="auto_switch_theme_reminder_title">主題模式切換提醒</string>
|
||||
<string name="auto_switch_theme_reminder_desc">根據環境光提醒切換淺色/深色模式</string>
|
||||
<string name="switch_to_dark_mode_tip">當前環境光較暗,是否切換至深色模式?</string>
|
||||
<string name="switch_to_light_mode_tip">當前環境光較亮,是否切換至淺色模式?</string>
|
||||
<string name="switch_action">切換</string>
|
||||
</resources>
|
||||
|
||||
@@ -2210,4 +2210,11 @@
|
||||
<string name="export_complete">匯出完成</string>
|
||||
<string name="download_no_storage_permission">下載失敗:無儲存權限</string>
|
||||
<string name="already_in_download_list">已在下載列表中</string>
|
||||
|
||||
<!-- 日夜間/深淺色主題切換提醒 -->
|
||||
<string name="auto_switch_theme_reminder_title">主題模式切換提醒</string>
|
||||
<string name="auto_switch_theme_reminder_desc">根據環境光提醒切換淺色/深色模式</string>
|
||||
<string name="switch_to_dark_mode_tip">目前環境光較暗,是否切換至深色模式?</string>
|
||||
<string name="switch_to_light_mode_tip">目前環境光較亮,是否切換至淺色模式?</string>
|
||||
<string name="switch_action">切換</string>
|
||||
</resources>
|
||||
|
||||
@@ -2218,4 +2218,11 @@
|
||||
<string name="export_complete">Export complete</string>
|
||||
<string name="download_no_storage_permission">Download error: no storage permission</string>
|
||||
<string name="already_in_download_list">Already in download list</string>
|
||||
|
||||
<!-- Day/Night Theme Switch Reminder -->
|
||||
<string name="auto_switch_theme_reminder_title">Theme Mode Switch Reminder</string>
|
||||
<string name="auto_switch_theme_reminder_desc">Remind to switch light/dark mode based on ambient light</string>
|
||||
<string name="switch_to_dark_mode_tip">Ambient light is low. Switch to dark mode?</string>
|
||||
<string name="switch_to_light_mode_tip">Ambient light is bright. Switch to light mode?</string>
|
||||
<string name="switch_action">Switch</string>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user