feat: support Monet dynamic color (Android 12+) - Add toggle in UI settings, default enabled, auto-disable on unsupported devices (#6067)

This commit is contained in:
Xiaochang authored and GitHub committed 2026-08-14 15:09:46 +08:00
1 parent 9cdbc5cebb
commit 2607b5cbff
13 files changed
+66 -1

No files matched your search

@@ -58,6 +58,7 @@ object AppConfig {
const val PREF_LANGUAGE = "pref_language"
const val PREF_APP_LOCALE_MIGRATED = "pref_app_locale_migrated"
const val PREF_UI_MODE_NIGHT = "pref_ui_mode_night"
const val PREF_DYNAMIC_COLOR = "pref_dynamic_color"
const val PREF_IPV6_ENABLED = "pref_ipv6_enabled"
const val PREF_PREFER_IPV6 = "pref_prefer_ipv6"
const val PREF_PROXY_SHARING = "pref_proxy_sharing_enabled"
@@ -19,6 +19,7 @@ object SettingsChangeManager {
AppConfig.PREF_GROUP_ALL_DISPLAY,
AppConfig.PREF_LANGUAGE,
AppConfig.PREF_UI_MODE_NIGHT,
AppConfig.PREF_DYNAMIC_COLOR,
AppConfig.PREF_IS_BOOTED,
)
@@ -1,11 +1,14 @@
package com.v2ray.ang.ui.compose
import android.app.Activity
import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.material3.dynamicDarkColorScheme
import androidx.compose.material3.dynamicLightColorScheme
import androidx.compose.material3.lightColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
@@ -15,6 +18,7 @@ import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.core.view.WindowCompat
import com.v2ray.ang.AppConfig
@@ -122,14 +126,26 @@ object ThemeManager {
)
val themeMode: StateFlow<String> = _themeMode.asStateFlow()
private val _dynamicColorEnabled = MutableStateFlow(
MmkvManager.decodeSettingsBool(AppConfig.PREF_DYNAMIC_COLOR, true)
)
val dynamicColorEnabled: StateFlow<Boolean> = _dynamicColorEnabled.asStateFlow()
fun setThemeMode(mode: String) {
MmkvManager.encodeSettings(AppConfig.PREF_UI_MODE_NIGHT, mode)
_themeMode.value = mode
}
fun setDynamicColorEnabled(enabled: Boolean) {
MmkvManager.encodeSettings(AppConfig.PREF_DYNAMIC_COLOR, enabled)
_dynamicColorEnabled.value = enabled
}
fun refresh() {
_themeMode.value =
MmkvManager.decodeSettingsString(AppConfig.PREF_UI_MODE_NIGHT, "0") ?: "0"
_dynamicColorEnabled.value =
MmkvManager.decodeSettingsBool(AppConfig.PREF_DYNAMIC_COLOR, true)
}
}
@@ -150,7 +166,15 @@ fun AppTheme(
darkTheme: Boolean = resolveDarkTheme(),
content: @Composable () -> Unit
) {
val colorScheme = if (darkTheme) DarkColor else LightColor
val dynamicColor by ThemeManager.dynamicColorEnabled.collectAsState()
val context = LocalContext.current
val colorScheme = when {
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context)
}
darkTheme -> DarkColor
else -> LightColor
}
val snackbarController = rememberAppSnackbarController()
val view = LocalView.current
@@ -1,5 +1,6 @@
package com.v2ray.ang.ui.settings
import android.os.Build
import android.os.Bundle
import androidx.activity.viewModels
import androidx.compose.foundation.layout.Column
@@ -13,6 +14,7 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.ScaffoldDefaults
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
@@ -129,6 +131,7 @@ fun SettingsScreen(
)
}
var uiModeNight by rememberMmkvString(AppConfig.PREF_UI_MODE_NIGHT, "0")
var dynamicColor by rememberMmkvBool(AppConfig.PREF_DYNAMIC_COLOR, true)
var ipv6Enabled by rememberMmkvBool(AppConfig.PREF_IPV6_ENABLED, false)
var preferIpv6 by rememberMmkvBool(AppConfig.PREF_PREFER_IPV6, false)
@@ -151,6 +154,14 @@ fun SettingsScreen(
val effectiveLocalProxy = enableLocalProxy || localProxyForced
val muxXudpConcurrencyInt = muxXudpConcurrency.toIntOrNull() ?: 8
val dynamicColorSupported = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
LaunchedEffect(dynamicColorSupported) {
if (!dynamicColorSupported && dynamicColor) {
dynamicColor = false
ThemeManager.setDynamicColorEnabled(false)
}
}
val languageEntries = stringArrayResource(R.array.language_select).toList()
val languageValues = stringArrayResource(R.array.language_select_value).toList()
val uiModeNightEntries = stringArrayResource(R.array.ui_mode_night).toList()
@@ -227,6 +238,16 @@ fun SettingsScreen(
SettingsChangeManager.makeSetupGroupTab()
}
)
SettingsSwitchItem(
title = stringResource(R.string.title_pref_dynamic_color),
summary = stringResource(R.string.summary_pref_dynamic_color),
checked = dynamicColor,
enabled = dynamicColorSupported,
onCheckedChange = {
dynamicColor = it
ThemeManager.setDynamicColorEnabled(it)
}
)
SettingsListItem(
title = stringResource(R.string.title_language),
entries = languageEntries,
@@ -298,6 +298,8 @@
<string name="title_language">اللغة</string>
<string name="title_ui_settings">إعدادات واجهة المستخدم</string>
<string name="title_pref_ui_mode_night">إعدادات وضع واجهة المستخدم ليلاً</string>
<string name="title_pref_dynamic_color">تفعيل الألوان الديناميكية</string>
<string name="summary_pref_dynamic_color">يعمل فقط على أندرويد 12+</string>
<string name="title_pref_use_hev_tunnel">تمكين ميزة Hev TUN</string>
<string name="summary_pref_use_hev_tunnel">عند التمكين، سيستخدم TUN ‏hev-socks5-tunnel؛ وإلا فسيستخدم xray-core.</string>
<string name="title_pref_hev_tunnel_loglevel">مستوى سجل Hev TUN</string>
@@ -298,6 +298,8 @@
<string name="title_language">ভাষা</string>
<string name="title_ui_settings">ইউআই সেটিংস</string>
<string name="title_pref_ui_mode_night">ইউআই মোড সেটিংস</string>
<string name="title_pref_dynamic_color">ডায়নামিক রঙ চালু করুন</string>
<string name="summary_pref_dynamic_color">শুধুমাত্র Android 12+ ডিভাইসে কাজ করে</string>
<string name="title_pref_use_hev_tunnel">Hev TUN সুবিধা চালু করুন</string>
<string name="summary_pref_use_hev_tunnel">চালু থাকলে TUN hev-socks5-tunnel ব্যবহার করবে; অন্যথায় xray-core ব্যবহার করবে।</string>
<string name="title_pref_hev_tunnel_loglevel">Hev TUN লগ স্তর</string>
@@ -298,6 +298,8 @@
<string name="title_language">زووݩ</string>
<string name="title_ui_settings">سامووا رابط منتوری</string>
<string name="title_pref_ui_mode_night">سامووا حالت رابط منتوری</string>
<string name="title_pref_dynamic_color">فعال‌سازی رنگ پویا</string>
<string name="summary_pref_dynamic_color">فقط روی اندروید ۱۲+ کار می‌کند</string>
<string name="title_pref_use_hev_tunnel">و کار گرؽڌن ویژیی Hev TUN</string>
<string name="summary_pref_use_hev_tunnel">مجالی ک ره ونده بۊ، TUN ایا hev-socks5-tunnel ن و کار اگره؛ ٱر ره نوۊفته بۊ، همو xray-core ن و کار اگره.</string>
<string name="title_pref_hev_tunnel_loglevel">Hev TUN سئت گوزارشا</string>
@@ -298,6 +298,8 @@
<string name="title_language">زبان</string>
<string name="title_ui_settings">تنظیمات رابط کاربری</string>
<string name="title_pref_ui_mode_night">تنظیمات حالت رابط کاربری</string>
<string name="title_pref_dynamic_color">فعال‌سازی رنگ پویا</string>
<string name="summary_pref_dynamic_color">فقط روی اندروید ۱۲+ کار می‌کند</string>
<string name="title_pref_use_hev_tunnel">استفاده از Hev TUN</string>
<string name="summary_pref_use_hev_tunnel">اگر فعال باشد، تونل VPN از hev-socks5-tunnel استفاده می‌کند؛ در غیر این صورت از xray-core استفاده خواهد شد.</string>
<string name="title_pref_hev_tunnel_loglevel">سطح گزارش‌های Hev TUN</string>
@@ -298,6 +298,8 @@
<string name="title_language">Язык</string>
<string name="title_ui_settings">Настройки интерфейса</string>
<string name="title_pref_ui_mode_night">Тема интерфейса</string>
<string name="title_pref_dynamic_color">Включить динамические цвета</string>
<string name="summary_pref_dynamic_color">Работает только на Android 12+</string>
<string name="title_pref_use_hev_tunnel">Использовать Hev TUN</string>
<string name="summary_pref_use_hev_tunnel">Если включено, TUN будет использовать hev-socks5-tunnel; иначе будет использован xray-core</string>
<string name="title_pref_hev_tunnel_loglevel">Уровень журналирования Hev TUN</string>
@@ -298,6 +298,8 @@
<string name="title_language">Ngôn ngữ</string>
<string name="title_ui_settings">Cài đặt UI</string>
<string name="title_pref_ui_mode_night">Cài đặt chế độ UI</string>
<string name="title_pref_dynamic_color">Bật màu động</string>
<string name="summary_pref_dynamic_color">Chỉ hoạt động trên Android 12+</string>
<string name="title_pref_use_hev_tunnel">Dùng Hev TUN</string>
<string name="summary_pref_use_hev_tunnel">Khi bật, TUN sẽ dùng hev-socks5-tunnel; nếu không, TUN sẽ dùng xray-core.</string>
<string name="title_pref_hev_tunnel_loglevel">Mức nhật ký Hev TUN</string>
@@ -298,6 +298,8 @@
<string name="title_language">语言</string>
<string name="title_ui_settings">用户界面设置</string>
<string name="title_pref_ui_mode_night">深色模式</string>
<string name="title_pref_dynamic_color">开启莫奈取色</string>
<string name="summary_pref_dynamic_color">仅在 Android 12+ 设备上工作</string>
<string name="title_pref_use_hev_tunnel">启用 Hev TUN 功能</string>
<string name="summary_pref_use_hev_tunnel">选择启用后 TUN 将使用 hev-socks5-tunnel 否则使用 xray-core</string>
<string name="title_pref_hev_tunnel_loglevel">Hev TUN 日志级别</string>
@@ -298,6 +298,8 @@
<string name="title_language">語言</string>
<string name="title_ui_settings">介面顯示設定</string>
<string name="title_pref_ui_mode_night">深色模式</string>
<string name="title_pref_dynamic_color">開啟莫奈取色</string>
<string name="summary_pref_dynamic_color">僅在 Android 12+ 裝置上工作</string>
<string name="title_pref_use_hev_tunnel">啟用 Hev TUN 功能</string>
<string name="summary_pref_use_hev_tunnel">啟用後,TUN 會使用 hev-socks5-tunnel;否則使用 xray-core。</string>
<string name="title_pref_hev_tunnel_loglevel">Hev TUN 日誌層級</string>
@@ -298,6 +298,8 @@
<string name="title_language">Language</string>
<string name="title_ui_settings">UI settings</string>
<string name="title_pref_ui_mode_night">UI mode settings</string>
<string name="title_pref_dynamic_color">Enable dynamic color</string>
<string name="summary_pref_dynamic_color">Only works on Android 12+ devices</string>
<string name="title_pref_use_hev_tunnel">Use Hev TUN</string>
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use xray-core.</string>
<string name="title_pref_hev_tunnel_loglevel">Hev TUN log level</string>