From af5094801c4d94b4743c28d503a0a6946880744a Mon Sep 17 00:00:00 2001 From: fansan Date: Tue, 30 Jun 2026 01:50:52 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E6=B7=BB=E5=8A=A0=E6=B5=85=E8=89=B2?= =?UTF-8?q?=E3=80=81=E6=B7=B1=E8=89=B2=E5=88=87=E6=8D=A2=E6=8F=90=E9=86=92?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=20(#1584)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat:添加浅色、深色切换提醒功能 * refactor: 重构SwitchDayNightReminder为通用ActionReminder - ReadConfigScreen 补上 主题模式切换提醒 开关 --- .../java/io/legado/app/constant/PreferKey.kt | 1 + .../data/repository/ReadSettingsRepository.kt | 6 + .../legado/app/ui/book/read/ActionReminder.kt | 107 ++++++++++++++++++ .../app/ui/book/read/ReadBookContract.kt | 15 +++ .../app/ui/book/read/ReadBookRouteScreen.kt | 46 ++++++++ .../legado/app/ui/book/read/ReadBookScreen.kt | 6 + .../app/ui/book/read/ReadBookViewModel.kt | 97 ++++++++++++++++ .../app/ui/book/read/sheet/MoreConfigSheet.kt | 10 ++ .../app/ui/config/readConfig/ReadConfig.kt | 4 + .../config/readConfig/ReadConfigContract.kt | 2 + .../ui/config/readConfig/ReadConfigScreen.kt | 9 ++ .../config/readConfig/ReadConfigViewModel.kt | 6 + .../ui/config/readConfig/ReadDataConfig.kt | 5 + app/src/main/res/values-zh-rCN/strings.xml | 7 ++ app/src/main/res/values-zh-rHK/strings.xml | 7 ++ app/src/main/res/values-zh-rTW/strings.xml | 7 ++ app/src/main/res/values/strings.xml | 7 ++ 17 files changed, 342 insertions(+) create mode 100644 app/src/main/java/io/legado/app/ui/book/read/ActionReminder.kt diff --git a/app/src/main/java/io/legado/app/constant/PreferKey.kt b/app/src/main/java/io/legado/app/constant/PreferKey.kt index df18884ef..319e28a6d 100644 --- a/app/src/main/java/io/legado/app/constant/PreferKey.kt +++ b/app/src/main/java/io/legado/app/constant/PreferKey.kt @@ -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" diff --git a/app/src/main/java/io/legado/app/data/repository/ReadSettingsRepository.kt b/app/src/main/java/io/legado/app/data/repository/ReadSettingsRepository.kt index 06aecf62f..2d73b08ac 100644 --- a/app/src/main/java/io/legado/app/data/repository/ReadSettingsRepository.kt +++ b/app/src/main/java/io/legado/app/data/repository/ReadSettingsRepository.kt @@ -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) diff --git a/app/src/main/java/io/legado/app/ui/book/read/ActionReminder.kt b/app/src/main/java/io/legado/app/ui/book/read/ActionReminder.kt new file mode 100644 index 000000000..e20b43f27 --- /dev/null +++ b/app/src/main/java/io/legado/app/ui/book/read/ActionReminder.kt @@ -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) + } + } + } + } + } + } + } +} diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt index 7370a0ce6..44f6b4a93 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookContract.kt @@ -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() } + data class AutoSuggestDayNight(val value: Boolean) : ConfigUpdate { + override val actions = emptySet() + } data class SelectText(val value: Boolean) : ConfigUpdate { override val actions = emptySet() } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookRouteScreen.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookRouteScreen.kt index ef879ee04..d65ca8834 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookRouteScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookRouteScreen.kt @@ -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) { diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookScreen.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookScreen.kt index 0478b4fe6..6d1c12114 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookScreen.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookScreen.kt @@ -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) }, + ) } diff --git a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt index e6de1aa48..eaa4ae769 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/ReadBookViewModel.kt @@ -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() + + 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, diff --git a/app/src/main/java/io/legado/app/ui/book/read/sheet/MoreConfigSheet.kt b/app/src/main/java/io/legado/app/ui/book/read/sheet/MoreConfigSheet.kt index d84202a3c..aa15ebaa1 100644 --- a/app/src/main/java/io/legado/app/ui/book/read/sheet/MoreConfigSheet.kt +++ b/app/src/main/java/io/legado/app/ui/book/read/sheet/MoreConfigSheet.kt @@ -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, diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfig.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfig.kt index 96e9fa044..72aa1f73d 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfig.kt +++ b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfig.kt @@ -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 diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigContract.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigContract.kt index 949167b99..cd3194f0e 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigContract.kt +++ b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigContract.kt @@ -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 } diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt index 542b18a9e..e2a93b686 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt +++ b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigScreen.kt @@ -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, diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigViewModel.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigViewModel.kt index c230d5bd7..b6ca29219 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigViewModel.kt +++ b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadConfigViewModel.kt @@ -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, diff --git a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadDataConfig.kt b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadDataConfig.kt index 15dad2069..ae21c801f 100644 --- a/app/src/main/java/io/legado/app/ui/config/readConfig/ReadDataConfig.kt +++ b/app/src/main/java/io/legado/app/ui/config/readConfig/ReadDataConfig.kt @@ -25,6 +25,11 @@ object ReadDataConfig { true ) + var autoSuggestDayNight by prefDelegate( + PreferKey.autoSuggestDayNight, + false + ) + var defaultSourceChangeAll by prefDelegate( PreferKey.defaultSourceChangeAll, true diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 3f756d404..18210a6df 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -2213,4 +2213,11 @@ EventListener callBackJs + + + 主题模式切换提醒 + 根据环境光提醒切换浅色/深色模式 + 当前环境光较暗,是否切换至深色模式? + 当前环境光较亮,是否切换至浅色模式? + 切换 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 1f12b4e3e..b9cd80363 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -2205,4 +2205,11 @@ 週二 週三 歡迎! + + + 主題模式切換提醒 + 根據環境光提醒切換淺色/深色模式 + 當前環境光較暗,是否切換至深色模式? + 當前環境光較亮,是否切換至淺色模式? + 切換 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index fafa72a2d..7cf0bd3e4 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -2210,4 +2210,11 @@ 匯出完成 下載失敗:無儲存權限 已在下載列表中 + + + 主題模式切換提醒 + 根據環境光提醒切換淺色/深色模式 + 目前環境光較暗,是否切換至深色模式? + 目前環境光較亮,是否切換至淺色模式? + 切換 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index beaccba6a..22296ad77 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2218,4 +2218,11 @@ Export complete Download error: no storage permission Already in download list + + + Theme Mode Switch Reminder + Remind to switch light/dark mode based on ambient light + Ambient light is low. Switch to dark mode? + Ambient light is bright. Switch to light mode? + Switch