Add application DPI setting function

- Allow users to customize the display density of the current application

- Fix some popup color errors
This commit is contained in:
ShirkNeko
2025-05-13 23:56:18 +08:00
parent 6b66d9b3f8
commit 3d0d87cb0c
5 changed files with 256 additions and 8 deletions

View File

@@ -49,6 +49,9 @@ class MainActivity : ComponentActivity() {
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
// 应用DPI设置仅对当前应用生效
applyCustomDpi()
// Enable edge to edge // Enable edge to edge
enableEdgeToEdge() enableEdgeToEdge()
@@ -135,6 +138,26 @@ class MainActivity : ComponentActivity() {
} }
} }
// 应用自定义DPI设置仅对当前应用生效
private fun applyCustomDpi() {
val prefs = getSharedPreferences("settings", MODE_PRIVATE)
val customDpi = prefs.getInt("app_dpi", 0)
if (customDpi > 0) {
try {
val resources = resources
val metrics = resources.displayMetrics
// 仅更新应用内显示,不影响系统状态栏
metrics.density = customDpi / 160f
metrics.scaledDensity = customDpi / 160f
metrics.densityDpi = customDpi
} catch (e: Exception) {
e.printStackTrace()
}
}
}
override fun onPause() { override fun onPause() {
super.onPause() super.onPause()
CardConfig.save(applicationContext) CardConfig.save(applicationContext)

View File

@@ -47,11 +47,7 @@ fun SlotSelectionDialog(
} }
if (show) { if (show) {
val cardColor = if (!ThemeConfig.useDynamicColor) { val cardColor = MaterialTheme.colorScheme.surfaceContainerHighest
ThemeConfig.currentTheme.ButtonContrast
} else {
MaterialTheme.colorScheme.surfaceContainerHigh
}
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,

View File

@@ -1,6 +1,7 @@
package com.sukisu.ultra.ui.screen package com.sukisu.ultra.ui.screen
import android.content.Context import android.content.Context
import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.widget.Toast import android.widget.Toast
@@ -29,6 +30,7 @@ import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.automirrored.filled.NavigateNext import androidx.compose.material.icons.automirrored.filled.NavigateNext
import androidx.compose.material.icons.filled.AcUnit
import androidx.compose.material.icons.filled.Brush import androidx.compose.material.icons.filled.Brush
import androidx.compose.material.icons.filled.ColorLens import androidx.compose.material.icons.filled.ColorLens
import androidx.compose.material.icons.filled.DarkMode import androidx.compose.material.icons.filled.DarkMode
@@ -81,9 +83,7 @@ import androidx.core.content.edit
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.sukisu.ultra.Natives
import com.sukisu.ultra.R import com.sukisu.ultra.R
import com.sukisu.ultra.ksuApp
import com.sukisu.ultra.ui.component.ImageEditorDialog import com.sukisu.ultra.ui.component.ImageEditorDialog
import com.sukisu.ultra.ui.component.KsuIsValid import com.sukisu.ultra.ui.component.KsuIsValid
import com.sukisu.ultra.ui.component.SwitchItem import com.sukisu.ultra.ui.component.SwitchItem
@@ -227,6 +227,36 @@ fun MoreSettingsScreen(navigator: DestinationsNavigator) {
var isCustomizeExpanded by remember { mutableStateOf(false) } var isCustomizeExpanded by remember { mutableStateOf(false) }
var isAppearanceExpanded by remember { mutableStateOf(true) } var isAppearanceExpanded by remember { mutableStateOf(true) }
var isAdvancedExpanded by remember { mutableStateOf(false) } var isAdvancedExpanded by remember { mutableStateOf(false) }
var isDpiExpanded by remember { mutableStateOf(false) }
// DPI 设置
val systemDpi = remember { context.resources.displayMetrics.densityDpi }
var currentDpi by remember {
mutableIntStateOf(prefs.getInt("app_dpi", systemDpi))
}
var tempDpi by remember { mutableIntStateOf(currentDpi) }
var isDpiCustom by remember { mutableStateOf(true) }
var showDpiConfirmDialog by remember { mutableStateOf(false) }
// 预设 DPI 选项
val dpiPresets = mapOf(
stringResource(R.string.dpi_size_small) to 240,
stringResource(R.string.dpi_size_medium) to 320,
stringResource(R.string.dpi_size_large) to 420,
stringResource(R.string.dpi_size_extra_large) to 560
)
// 获取DPI大小
@Composable
fun getDpiFriendlyName(dpi: Int): String {
return when (dpi) {
240 -> stringResource(R.string.dpi_size_small)
320 -> stringResource(R.string.dpi_size_medium)
420 -> stringResource(R.string.dpi_size_large)
560 -> stringResource(R.string.dpi_size_extra_large)
else -> stringResource(R.string.dpi_size_custom)
}
}
// 初始化卡片配置 // 初始化卡片配置
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
@@ -263,10 +293,37 @@ fun MoreSettingsScreen(navigator: DestinationsNavigator) {
CardConfig.setDarkModeDefaults() CardConfig.setDarkModeDefaults()
} }
// 保存设置 currentDpi = prefs.getInt("app_dpi", systemDpi)
tempDpi = currentDpi
CardConfig.save(context) CardConfig.save(context)
} }
// 应用 DPI 设置
val applyDpiSetting = { dpi: Int ->
if (dpi != currentDpi) {
// 保存到 SharedPreferences
prefs.edit {
putInt("app_dpi", dpi)
}
// 只修改应用级别的DPI设置
currentDpi = dpi
tempDpi = dpi
Toast.makeText(
context,
context.getString(R.string.dpi_applied_success, dpi),
Toast.LENGTH_SHORT
).show()
val restartIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)
restartIntent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(restartIntent)
showDpiConfirmDialog = false
}
}
// 主题色选项 // 主题色选项
val themeColorOptions = listOf( val themeColorOptions = listOf(
stringResource(R.string.color_default) to ThemeColors.Default, stringResource(R.string.color_default) to ThemeColors.Default,
@@ -575,6 +632,114 @@ fun MoreSettingsScreen(navigator: DestinationsNavigator) {
} }
} }
// DPI 设置部分
SectionHeader(
title = stringResource(R.string.dpi_settings),
expanded = isDpiExpanded,
onToggle = { isDpiExpanded = !isDpiExpanded }
)
AnimatedVisibility(
visible = isDpiExpanded,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
) {
Surface(
shape = RoundedCornerShape(16.dp),
tonalElevation = 1.dp,
modifier = Modifier.padding(bottom = 16.dp)
) {
Column {
ListItem(
headlineContent = { Text(stringResource(R.string.app_dpi_title)) },
supportingContent = { Text(stringResource(R.string.app_dpi_summary)) },
leadingContent = {
Icon(
Icons.Default.AcUnit,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary
)
},
trailingContent = {
Text(
text = getDpiFriendlyName(tempDpi),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.primary
)
},
colors = ListItemDefaults.colors(
containerColor = Color.Transparent
)
)
// DPI 滑动条
Column(modifier = Modifier.padding(horizontal = 32.dp, vertical = 8.dp)) {
Slider(
value = tempDpi.toFloat(),
onValueChange = {
tempDpi = it.toInt()
isDpiCustom = !dpiPresets.containsValue(tempDpi)
},
valueRange = 160f..600f,
steps = 11,
colors = SliderDefaults.colors(
thumbColor = MaterialTheme.colorScheme.primary,
activeTrackColor = MaterialTheme.colorScheme.primary,
inactiveTrackColor = MaterialTheme.colorScheme.surfaceVariant
)
)
Row(
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp),
) {
dpiPresets.forEach { (name, dpi) ->
TextButton(
onClick = {
tempDpi = dpi
isDpiCustom = false
},
modifier = Modifier.weight(1f)
) {
Text(
text = name,
color = if (tempDpi == dpi)
MaterialTheme.colorScheme.primary
else
MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
}
TextButton(
onClick = {
if (tempDpi != currentDpi) {
showDpiConfirmDialog = true
}
},
modifier = Modifier
.fillMaxWidth()
.padding(top = 8.dp)
) {
Text(stringResource(R.string.dpi_apply_settings))
}
Text(
text = if (isDpiCustom)
"${stringResource(R.string.dpi_size_custom)}: $tempDpi"
else
"${getDpiFriendlyName(tempDpi)}: $tempDpi",
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(top = 4.dp)
)
}
}
}
}
// 自定义设置部分 // 自定义设置部分
SectionHeader( SectionHeader(
title = stringResource(R.string.custom_settings), title = stringResource(R.string.custom_settings),
@@ -863,6 +1028,42 @@ fun MoreSettingsScreen(navigator: DestinationsNavigator) {
) )
} }
// DPI 设置确认对话框
if (showDpiConfirmDialog) {
AlertDialog(
onDismissRequest = { showDpiConfirmDialog = false },
title = { Text(stringResource(R.string.dpi_confirm_title)) },
text = {
Column {
Text(stringResource(R.string.dpi_confirm_message, currentDpi, tempDpi))
Text(
stringResource(R.string.dpi_confirm_summary),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant,
modifier = Modifier.padding(top = 8.dp)
)
}
},
confirmButton = {
TextButton(
onClick = { applyDpiSetting(tempDpi) }
) {
Text(stringResource(R.string.confirm))
}
},
dismissButton = {
TextButton(
onClick = {
showDpiConfirmDialog = false
tempDpi = currentDpi
}
) {
Text(stringResource(R.string.cancel))
}
}
)
}
// 主题色选择对话框 // 主题色选择对话框
if (showThemeColorDialog) { if (showThemeColorDialog) {
AlertDialog( AlertDialog(

View File

@@ -328,4 +328,18 @@
<string name="use_webuix_summary">使用支持更多 API 的 WebUI X 而不是 WebUI</string> <string name="use_webuix_summary">使用支持更多 API 的 WebUI X 而不是 WebUI</string>
<string name="use_webuix_eruda">将 Eruda 注入 WebUI X</string> <string name="use_webuix_eruda">将 Eruda 注入 WebUI X</string>
<string name="use_webuix_eruda_summary">在 WebUI X 中注入调试控制台,使调试更容易,需要启用 WebView 调试</string> <string name="use_webuix_eruda_summary">在 WebUI X 中注入调试控制台,使调试更容易,需要启用 WebView 调试</string>
<!-- DPI设置相关字符串 -->
<string name="dpi_settings">DPI 设置</string>
<string name="app_dpi_title">应用DPI</string>
<string name="app_dpi_summary">仅调整当前应用的屏幕显示密度</string>
<string name="dpi_size_small"></string>
<string name="dpi_size_medium"></string>
<string name="dpi_size_large"></string>
<string name="dpi_size_extra_large">超大</string>
<string name="dpi_size_custom">自定义</string>
<string name="dpi_apply_settings">应用DPI设置</string>
<string name="dpi_confirm_title">确认更改DPI</string>
<string name="dpi_confirm_message">你确定要将应用DPI从 %1$d 更改为 %2$d 吗?</string>
<string name="dpi_confirm_summary">应用需要重启以应用新的DPI设置不会影响系统状态栏或其他应用</string>
<string name="dpi_applied_success">DPI 已设置为 %1$d重启应用后生效</string>
</resources> </resources>

View File

@@ -332,4 +332,18 @@
<string name="use_webuix_summary">Use WebUI X instead of WebUI which supports more API\'s</string> <string name="use_webuix_summary">Use WebUI X instead of WebUI which supports more API\'s</string>
<string name="use_webuix_eruda">Inject Eruda into WebUI X</string> <string name="use_webuix_eruda">Inject Eruda into WebUI X</string>
<string name="use_webuix_eruda_summary">Inject a debug console into WebUI X to make debugging easier. Requires web debugging to be on.</string> <string name="use_webuix_eruda_summary">Inject a debug console into WebUI X to make debugging easier. Requires web debugging to be on.</string>
<!-- DPI setting related strings -->
<string name="dpi_settings">DPI setting</string>
<string name="app_dpi_title">Applied DPI</string>
<string name="app_dpi_summary">Adjust the screen display density for the current application only</string>
<string name="dpi_size_small">Small </string>
<string name="dpi_size_medium">Medium </string>
<string name="dpi_size_large">Big</string>
<string name="dpi_size_extra_large">oversize</string>
<string name="dpi_size_custom">customizable</string>
<string name="dpi_apply_settings">Applying DPI settings</string>
<string name="dpi_confirm_title">Confirm DPI change</string>
<string name="dpi_confirm_message">Are you sure you want to change the application DPI from %1$d to %2$d?</string>
<string name="dpi_confirm_summary">Application needs to be restarted to apply the new DPI settings, does not affect the system status bar or other applications</string>
<string name="dpi_applied_success">DPI has been set to %1$d, effective after restarting the application</string>
</resources> </resources>