refactor(ui): 統一介面風格並優化佈局

- Home:重新整理資訊卡,將 StringBuilder 替換為 Composables;修正填充和 HtmlText 參數錯誤。
- Manager:為 TabRow 添加動畫指示器並統一頁面間距。
- Settings:為 KeyStore 對話框添加垂直滾動功能,以防止在小螢幕上出現裁剪。
- Repo:改善「即將推出」的 UI,增添圖標。
This commit is contained in:
NkBe 2025-12-11 22:38:14 +08:00
parent f215471400
commit f14f65d078
No known key found for this signature in database
GPG Key ID: 525137026FF031DF
9 changed files with 257 additions and 169 deletions

2
core

@ -1 +1 @@
Subproject commit f8c4b6c5a52e6fe07d288d96f3765fd18aaa928c Subproject commit 34f12244c931941420d011fbffb1858c8c045c1f

View File

@ -15,9 +15,9 @@ enum class BottomBarDestination(
val iconSelected: ImageVector, val iconSelected: ImageVector,
val iconNotSelected: ImageVector val iconNotSelected: ImageVector
) { ) {
Repo(RepoScreenDestination, R.string.screen_repo, Icons.Filled.GetApp, Icons.Outlined.GetApp), Home(HomeScreenDestination, R.string.screen_home, Icons.Filled.Home, Icons.Outlined.Home),
Manage(ManageScreenDestination, R.string.screen_manage, Icons.Filled.Dashboard, Icons.Outlined.Dashboard), Manage(ManageScreenDestination, R.string.screen_manage, Icons.Filled.Dashboard, Icons.Outlined.Dashboard),
Home(HomeScreenDestination, R.string.app_name, Icons.Filled.Home, Icons.Outlined.Home), Repo(RepoScreenDestination, R.string.screen_repo, Icons.Filled.GetApp, Icons.Outlined.GetApp),
Logs(LogsScreenDestination, R.string.screen_logs, Icons.Filled.Assignment, Icons.Outlined.Assignment), Logs(LogsScreenDestination, R.string.screen_logs, Icons.Filled.Assignment, Icons.Outlined.Assignment),
Settings(SettingsScreenDestination, R.string.screen_settings, Icons.Filled.Settings, Icons.Outlined.Settings); Settings(SettingsScreenDestination, R.string.screen_settings, Icons.Filled.Settings, Icons.Outlined.Settings);
} }

View File

@ -13,23 +13,19 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.CheckCircle import androidx.compose.material.icons.outlined.CheckCircle
import androidx.compose.material.icons.outlined.ContentCopy
import androidx.compose.material.icons.outlined.Info
import androidx.compose.material.icons.outlined.Warning import androidx.compose.material.icons.outlined.Warning
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.*
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootNavGraph import com.ramcosta.composedestinations.annotation.RootNavGraph
@ -50,7 +46,6 @@ import rikka.shizuku.Shizuku
@Destination @Destination
@Composable @Composable
fun HomeScreen(navigator: DestinationsNavigator) { fun HomeScreen(navigator: DestinationsNavigator) {
// Install from intent
var isIntentLaunched by rememberSaveable { mutableStateOf(false) } var isIntentLaunched by rememberSaveable { mutableStateOf(false) }
val activity = LocalContext.current as Activity val activity = LocalContext.current as Activity
val intent = activity.intent val intent = activity.intent
@ -76,14 +71,15 @@ fun HomeScreen(navigator: DestinationsNavigator) {
Column( Column(
modifier = Modifier modifier = Modifier
.padding(innerPadding) .padding(innerPadding)
.padding(horizontal = 16.dp) .fillMaxSize()
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState())
.padding(horizontal = 16.dp, vertical = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
ShizukuCard() ShizukuCard()
InfoCard() InfoCard()
SupportCard() SupportCard()
Spacer(Modifier) Spacer(Modifier.height(16.dp))
} }
} }
} }
@ -92,7 +88,6 @@ private val listener: (Int, Int) -> Unit = { _, grantResult ->
ShizukuApi.isPermissionGranted = grantResult == PackageManager.PERMISSION_GRANTED ShizukuApi.isPermissionGranted = grantResult == PackageManager.PERMISSION_GRANTED
} }
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun ShizukuCard() { private fun ShizukuCard() {
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
@ -104,11 +99,21 @@ private fun ShizukuCard() {
} }
} }
ElevatedCard( val containerColor = if (ShizukuApi.isPermissionGranted) {
colors = CardDefaults.elevatedCardColors(containerColor = run { MaterialTheme.colorScheme.secondaryContainer
if (ShizukuApi.isPermissionGranted) MaterialTheme.colorScheme.secondaryContainer } else {
else MaterialTheme.colorScheme.errorContainer MaterialTheme.colorScheme.errorContainer
}) }
val contentColor = if (ShizukuApi.isPermissionGranted) {
MaterialTheme.colorScheme.onSecondaryContainer
} else {
MaterialTheme.colorScheme.onErrorContainer
}
Card(
colors = CardDefaults.cardColors(containerColor = containerColor),
modifier = Modifier.clip(CardDefaults.shape)
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
@ -118,126 +123,148 @@ private fun ShizukuCard() {
Shizuku.requestPermission(114514) Shizuku.requestPermission(114514)
} }
} }
.padding(24.dp), .padding(16.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
if (ShizukuApi.isPermissionGranted) { Icon(
Icon(Icons.Outlined.CheckCircle, stringResource(R.string.shizuku_available)) imageVector = if (ShizukuApi.isPermissionGranted) Icons.Outlined.CheckCircle else Icons.Outlined.Warning,
Column(Modifier.padding(start = 20.dp)) { contentDescription = null,
Text( tint = contentColor,
text = stringResource(R.string.shizuku_available), modifier = Modifier.size(40.dp)
fontFamily = FontFamily.Serif, )
style = MaterialTheme.typography.titleMedium Spacer(modifier = Modifier.width(16.dp))
) Column {
Spacer(Modifier.height(4.dp)) Text(
Text( text = stringResource(if (ShizukuApi.isPermissionGranted) R.string.shizuku_available else R.string.shizuku_unavailable),
text = "API " + Shizuku.getVersion(), style = MaterialTheme.typography.titleMedium,
style = MaterialTheme.typography.bodyMedium fontWeight = FontWeight.Bold,
) color = contentColor
} )
} else { Text(
Icon(Icons.Outlined.Warning, stringResource(R.string.shizuku_unavailable)) text = if (ShizukuApi.isPermissionGranted) "API ${Shizuku.getVersion()}" else stringResource(R.string.home_shizuku_warning),
Column(Modifier.padding(start = 20.dp)) { style = MaterialTheme.typography.bodyMedium,
Text( color = contentColor.copy(alpha = 0.8f)
text = stringResource(R.string.shizuku_unavailable), )
fontFamily = FontFamily.Serif,
style = MaterialTheme.typography.titleMedium
)
Spacer(Modifier.height(4.dp))
Text(
text = stringResource(R.string.home_shizuku_warning),
style = MaterialTheme.typography.bodyMedium
)
}
} }
} }
} }
} }
private val apiVersion = if (Build.VERSION.PREVIEW_SDK_INT != 0) {
"${Build.VERSION.CODENAME} Preview (API ${Build.VERSION.PREVIEW_SDK_INT})"
} else {
"${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})"
}
private val device = buildString {
append(Build.MANUFACTURER[0].uppercaseChar().toString() + Build.MANUFACTURER.substring(1))
if (Build.BRAND != Build.MANUFACTURER) {
append(" " + Build.BRAND[0].uppercaseChar() + Build.BRAND.substring(1))
}
append(" " + Build.MODEL + " ")
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
private fun InfoCard() { private fun InfoCard() {
val context = LocalContext.current val context = LocalContext.current
val snackbarHost = LocalSnackbarHost.current val snackbarHost = LocalSnackbarHost.current
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val apiVersion = if (Build.VERSION.PREVIEW_SDK_INT != 0) {
"${Build.VERSION.CODENAME} Preview (API ${Build.VERSION.PREVIEW_SDK_INT})"
} else {
"${Build.VERSION.RELEASE} (API ${Build.VERSION.SDK_INT})"
}
val deviceName = buildString {
append(Build.MANUFACTURER.replaceFirstChar { it.uppercase() })
if (Build.BRAND != Build.MANUFACTURER) {
append(" " + Build.BRAND.replaceFirstChar { it.uppercase() })
}
append(" " + Build.MODEL)
}
val infoList = listOf(
stringResource(R.string.home_api_version) to "${LSPConfig.instance.API_CODE}",
stringResource(R.string.home_npatch_version) to "${LSPConfig.instance.VERSION_NAME} (${LSPConfig.instance.VERSION_CODE})",
stringResource(R.string.home_framework_version) to "${LSPConfig.instance.CORE_VERSION_NAME} (${LSPConfig.instance.CORE_VERSION_CODE})",
stringResource(R.string.home_system_version) to apiVersion,
stringResource(R.string.home_device) to deviceName,
stringResource(R.string.home_system_abi) to Build.SUPPORTED_ABIS[0]
)
val copySuccessMessage = stringResource(R.string.home_info_copied)
ElevatedCard { ElevatedCard {
Column( Column(
modifier = Modifier modifier = Modifier.fillMaxWidth()
.fillMaxWidth()
.padding(start = 24.dp, top = 24.dp, end = 24.dp, bottom = 16.dp)
) { ) {
val contents = StringBuilder() Row(
val infoCardContent: @Composable (Pair<String, String>) -> Unit = { texts -> modifier = Modifier
contents.appendLine(texts.first).appendLine(texts.second).appendLine() .padding(horizontal = 16.dp, vertical = 12.dp)
Text(text = texts.first, style = MaterialTheme.typography.bodyLarge) .fillMaxWidth(),
Text(text = texts.second, style = MaterialTheme.typography.bodyMedium) horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = stringResource(R.string.home_device_info),
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold,
color = MaterialTheme.colorScheme.primary
)
IconButton(onClick = {
val contentString = infoList.joinToString("\n") { "${it.first}: ${it.second}" }
val cm = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
cm.setPrimaryClip(ClipData.newPlainText("NPatch Info", contentString))
scope.launch { snackbarHost.showSnackbar(copySuccessMessage) }
}) {
Icon(Icons.Outlined.ContentCopy, contentDescription = "Copy")
}
} }
infoCardContent(stringResource(R.string.home_api_version) to "${LSPConfig.instance.API_CODE}") HorizontalDivider(modifier = Modifier.padding(horizontal = 16.dp), color = MaterialTheme.colorScheme.outlineVariant.copy(alpha = 0.5f))
Spacer(Modifier.height(24.dp)) Column(modifier = Modifier.padding(vertical = 8.dp)) {
infoCardContent(stringResource(R.string.home_npatch_version) to LSPConfig.instance.VERSION_NAME + " (${LSPConfig.instance.VERSION_CODE})") infoList.forEach { (label, value) ->
InfoRow(label, value)
Spacer(Modifier.height(24.dp)) }
infoCardContent(stringResource(R.string.home_framework_version) to LSPConfig.instance.CORE_VERSION_NAME + " (${LSPConfig.instance.CORE_VERSION_CODE})") }
Spacer(Modifier.height(24.dp))
infoCardContent(stringResource(R.string.home_system_version) to apiVersion)
Spacer(Modifier.height(24.dp))
infoCardContent(stringResource(R.string.home_device) to device)
Spacer(Modifier.height(24.dp))
infoCardContent(stringResource(R.string.home_system_abi) to Build.SUPPORTED_ABIS[0])
val copiedMessage = stringResource(R.string.home_info_copied)
TextButton(
modifier = Modifier.align(Alignment.End),
onClick = {
val cm = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
cm.setPrimaryClip(ClipData.newPlainText("NPatch", contents.toString()))
scope.launch { snackbarHost.showSnackbar(copiedMessage) }
},
content = { Text(stringResource(android.R.string.copy)) }
)
} }
} }
} }
@OptIn(ExperimentalMaterial3Api::class) @Composable
@Preview private fun InfoRow(label: String, value: String) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 6.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = label,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Text(
text = value,
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.onSurface
)
}
}
@Composable @Composable
private fun SupportCard() { private fun SupportCard() {
ElevatedCard { ElevatedCard {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(24.dp) .padding(16.dp)
) { ) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(Icons.Outlined.Info, contentDescription = null, tint = MaterialTheme.colorScheme.primary)
Spacer(Modifier.width(8.dp))
Text(
text = stringResource(R.string.home_support),
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.SemiBold
)
}
Spacer(Modifier.height(8.dp))
Text( Text(
text = stringResource(R.string.home_support),
fontWeight = FontWeight.SemiBold,
style = MaterialTheme.typography.titleMedium
)
Text(
modifier = Modifier.padding(vertical = 8.dp),
text = stringResource(R.string.home_description), text = stringResource(R.string.home_description),
style = MaterialTheme.typography.bodyMedium style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
) )
Spacer(Modifier.height(12.dp))
HtmlText( HtmlText(
stringResource( stringResource(
R.string.home_view_source_code, R.string.home_view_source_code,
@ -247,4 +274,4 @@ private fun SupportCard() {
) )
} }
} }
} }

View File

@ -1,13 +1,15 @@
package org.lsposed.npatch.ui.page package org.lsposed.npatch.ui.page
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.material3.TabRowDefaults.tabIndicatorOffset
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.ExperimentalPagerApi
import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.HorizontalPager
@ -32,41 +34,54 @@ fun ManageScreen(
) { ) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
val pagerState = rememberPagerState() val pagerState = rememberPagerState()
val tabTitles = listOf(stringResource(R.string.apps), stringResource(R.string.modules))
Scaffold( Scaffold(
topBar = { CenterTopBar(stringResource(BottomBarDestination.Manage.label)) }, topBar = { CenterTopBar(stringResource(BottomBarDestination.Manage.label)) },
floatingActionButton = { if (pagerState.currentPage == 0) AppManageFab(navigator) } floatingActionButton = {
if (pagerState.currentPage == 0) AppManageFab(navigator)
}
) { innerPadding -> ) { innerPadding ->
Box(Modifier.padding(innerPadding)) { Column(
Column { modifier = Modifier
TabRow( .padding(innerPadding)
contentColor = MaterialTheme.colorScheme.secondary, .fillMaxSize()
selectedTabIndex = pagerState.currentPage ) {
) { TabRow(
Tab( selectedTabIndex = pagerState.currentPage,
selected = pagerState.currentPage == 0, containerColor = MaterialTheme.colorScheme.surface,
onClick = { scope.launch { pagerState.animateScrollToPage(0) } } contentColor = MaterialTheme.colorScheme.primary,
) { indicator = { tabPositions ->
Text( TabRowDefaults.Indicator(
modifier = Modifier.padding(vertical = 16.dp), Modifier.tabIndicatorOffset(tabPositions[pagerState.currentPage])
text = stringResource(R.string.apps) )
)
}
Tab(
selected = pagerState.currentPage == 1,
onClick = { scope.launch { pagerState.animateScrollToPage(1) } }
) {
Text(
modifier = Modifier.padding(vertical = 16.dp),
text = stringResource(R.string.modules)
)
}
} }
) {
tabTitles.forEachIndexed { index, title ->
val selected = pagerState.currentPage == index
Tab(
selected = selected,
onClick = { scope.launch { pagerState.animateScrollToPage(index) } },
text = {
Text(
text = title,
style = MaterialTheme.typography.titleSmall,
fontWeight = if (selected) FontWeight.Bold else FontWeight.Normal,
modifier = Modifier.padding(vertical = 12.dp)
)
},
)
}
}
HorizontalPager(count = 2, state = pagerState) { page -> HorizontalPager(
when (page) { count = tabTitles.size,
0 -> AppManageBody(navigator, resultRecipient) state = pagerState,
1 -> ModuleManageBody() modifier = Modifier.weight(1f)
} ) { page ->
when (page) {
0 -> AppManageBody(navigator, resultRecipient)
1 -> ModuleManageBody()
} }
} }
} }

View File

@ -1,15 +1,17 @@
package org.lsposed.npatch.ui.page package org.lsposed.npatch.ui.page
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material.icons.outlined.Construction
import androidx.compose.material3.Scaffold import androidx.compose.material3.*
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.annotation.Destination
import org.lsposed.npatch.R
import org.lsposed.npatch.ui.component.CenterTopBar import org.lsposed.npatch.ui.component.CenterTopBar
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@ -19,12 +21,34 @@ fun RepoScreen() {
Scaffold( Scaffold(
topBar = { CenterTopBar(stringResource(BottomBarDestination.Repo.label)) } topBar = { CenterTopBar(stringResource(BottomBarDestination.Repo.label)) }
) { innerPadding -> ) { innerPadding ->
Text( Column(
modifier = Modifier modifier = Modifier
.padding(innerPadding) .padding(innerPadding)
.fillMaxSize(), .fillMaxSize()
text = "This page is not yet implemented", .padding(32.dp),
textAlign = TextAlign.Center horizontalAlignment = Alignment.CenterHorizontally,
) verticalArrangement = Arrangement.Center
) {
Icon(
imageVector = Icons.Outlined.Construction,
contentDescription = null,
modifier = Modifier.size(72.dp),
tint = MaterialTheme.colorScheme.primary.copy(alpha = 0.6f)
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = stringResource(R.string.coming_soon),
style = MaterialTheme.typography.headlineSmall,
color = MaterialTheme.colorScheme.onBackground
)
Spacer(modifier = Modifier.height(8.dp))
Text(
text = "This page is not yet implemented",
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
} }
} }

View File

@ -8,9 +8,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.PressInteraction import androidx.compose.foundation.interaction.PressInteraction
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@ -52,7 +50,9 @@ fun SettingsScreen() {
Column( Column(
modifier = Modifier modifier = Modifier
.padding(innerPadding) .padding(innerPadding)
.fillMaxSize()
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.padding(vertical = 16.dp)
) { ) {
KeyStore() KeyStore()
DetailPatchLogs() DetailPatchLogs()
@ -122,7 +122,6 @@ private fun KeyStore() {
onDismissRequest = { expanded = false; showDialog = false }, onDismissRequest = { expanded = false; showDialog = false },
confirmButton = { confirmButton = {
TextButton( TextButton(
content = { Text(stringResource(android.R.string.ok)) },
onClick = { onClick = {
wrongKeystore = false wrongKeystore = false
wrongPassword = false wrongPassword = false
@ -159,25 +158,31 @@ private fun KeyStore() {
scope.launch { MyKeyStore.setCustom(password, alias, aliasPassword) } scope.launch { MyKeyStore.setCustom(password, alias, aliasPassword) }
expanded = false expanded = false
showDialog = false showDialog = false
}) }
) {
Text(stringResource(android.R.string.ok))
}
}, },
dismissButton = { dismissButton = {
TextButton( TextButton(onClick = { expanded = false; showDialog = false }) {
content = { Text(stringResource(android.R.string.cancel)) }, Text(stringResource(android.R.string.cancel))
onClick = { expanded = false; showDialog = false } }
)
}, },
title = { title = {
Text( Text(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
text = stringResource(R.string.settings_keystore_dialog_title), text = stringResource(R.string.settings_keystore_dialog_title),
textAlign = TextAlign.Center textAlign = TextAlign.Center,
style = MaterialTheme.typography.titleLarge
) )
}, },
text = { text = {
Column( Column(
modifier = Modifier.fillMaxWidth(), modifier = Modifier
horizontalAlignment = Alignment.CenterHorizontally .fillMaxWidth()
.verticalScroll(rememberScrollState()),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
val interactionSource = remember { MutableInteractionSource() } val interactionSource = remember { MutableInteractionSource() }
LaunchedEffect(interactionSource) { LaunchedEffect(interactionSource) {
@ -188,6 +193,7 @@ private fun KeyStore() {
} }
} }
// Error Message Handling
val wrongText = when { val wrongText = when {
wrongAliasPassword -> stringResource(R.string.settings_keystore_wrong_alias_password) wrongAliasPassword -> stringResource(R.string.settings_keystore_wrong_alias_password)
wrongAliasName -> stringResource(R.string.settings_keystore_wrong_alias) wrongAliasName -> stringResource(R.string.settings_keystore_wrong_alias)
@ -195,10 +201,13 @@ private fun KeyStore() {
wrongKeystore -> stringResource(R.string.settings_keystore_wrong_keystore) wrongKeystore -> stringResource(R.string.settings_keystore_wrong_keystore)
else -> null else -> null
} }
Text( Text(
modifier = Modifier.padding(bottom = 8.dp), modifier = Modifier.padding(bottom = 8.dp),
text = wrongText ?: stringResource(R.string.settings_keystore_desc), text = wrongText ?: stringResource(R.string.settings_keystore_desc),
color = if (wrongText != null) MaterialTheme.colorScheme.error else Color.Unspecified color = if (wrongText != null) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurfaceVariant,
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center
) )
OutlinedTextField( OutlinedTextField(
@ -209,28 +218,32 @@ private fun KeyStore() {
placeholder = { Text(stringResource(R.string.settings_keystore_file)) }, placeholder = { Text(stringResource(R.string.settings_keystore_file)) },
singleLine = true, singleLine = true,
isError = wrongKeystore, isError = wrongKeystore,
interactionSource = interactionSource interactionSource = interactionSource,
modifier = Modifier.fillMaxWidth()
) )
OutlinedTextField( OutlinedTextField(
value = password, value = password,
onValueChange = { password = it }, onValueChange = { password = it },
label = { Text(stringResource(R.string.settings_keystore_password)) }, label = { Text(stringResource(R.string.settings_keystore_password)) },
singleLine = true, singleLine = true,
isError = wrongPassword isError = wrongPassword,
modifier = Modifier.fillMaxWidth()
) )
OutlinedTextField( OutlinedTextField(
value = alias, value = alias,
onValueChange = { alias = it }, onValueChange = { alias = it },
label = { Text(stringResource(R.string.settings_keystore_alias)) }, label = { Text(stringResource(R.string.settings_keystore_alias)) },
singleLine = true, singleLine = true,
isError = wrongAliasName isError = wrongAliasName,
modifier = Modifier.fillMaxWidth()
) )
OutlinedTextField( OutlinedTextField(
value = aliasPassword, value = aliasPassword,
onValueChange = { aliasPassword = it }, onValueChange = { aliasPassword = it },
label = { Text(stringResource(R.string.settings_keystore_alias_password)) }, label = { Text(stringResource(R.string.settings_keystore_alias_password)) },
singleLine = true, singleLine = true,
isError = wrongAliasPassword isError = wrongAliasPassword,
modifier = Modifier.fillMaxWidth()
) )
} }
} }

View File

@ -10,6 +10,7 @@
<string name="modules">模块</string> <string name="modules">模块</string>
<string name="shizuku_available">Shizuku 服务可用</string> <string name="shizuku_available">Shizuku 服务可用</string>
<string name="shizuku_unavailable">Shizuku 服务未连接</string> <string name="shizuku_unavailable">Shizuku 服务未连接</string>
<string name="screen_home">主页</string>
<string name="screen_repo">仓库</string> <string name="screen_repo">仓库</string>
<string name="screen_logs">日志</string> <string name="screen_logs">日志</string>
<string name="off">关闭</string> <string name="off">关闭</string>
@ -21,6 +22,8 @@
<string name="home_framework_version">框架版本</string> <string name="home_framework_version">框架版本</string>
<string name="home_system_version">系统版本</string> <string name="home_system_version">系统版本</string>
<string name="home_device">设备</string> <string name="home_device">设备</string>
<string name="home_device_info">设备信息</string>
<string name="coming_soon">敬请期待</string>
<string name="home_system_abi">系统架构</string> <string name="home_system_abi">系统架构</string>
<string name="home_info_copied">已复制到剪贴板</string> <string name="home_info_copied">已复制到剪贴板</string>
<string name="home_support">支持</string> <string name="home_support">支持</string>

View File

@ -10,6 +10,7 @@
<string name="modules">模組</string> <string name="modules">模組</string>
<string name="shizuku_available">Shizuku 服務可用</string> <string name="shizuku_available">Shizuku 服務可用</string>
<string name="shizuku_unavailable">Shizuku 服務未連線</string> <string name="shizuku_unavailable">Shizuku 服務未連線</string>
<string name="screen_home">首頁</string>
<string name="screen_repo">倉庫</string> <string name="screen_repo">倉庫</string>
<string name="screen_logs">日誌</string> <string name="screen_logs">日誌</string>
<string name="off">關閉</string> <string name="off">關閉</string>
@ -21,6 +22,8 @@
<string name="home_framework_version">框架版本</string> <string name="home_framework_version">框架版本</string>
<string name="home_system_version">系統版本</string> <string name="home_system_version">系統版本</string>
<string name="home_device">裝置</string> <string name="home_device">裝置</string>
<string name="home_device_info">設備資訊</string>
<string name="coming_soon">敬請期待</string>
<string name="home_system_abi">系統架構</string> <string name="home_system_abi">系統架構</string>
<string name="home_info_copied">已複製到剪貼簿</string> <string name="home_info_copied">已複製到剪貼簿</string>
<string name="home_support">支援</string> <string name="home_support">支援</string>

View File

@ -9,6 +9,7 @@
<string name="modules">Modules</string> <string name="modules">Modules</string>
<string name="shizuku_available">Shizuku service available</string> <string name="shizuku_available">Shizuku service available</string>
<string name="shizuku_unavailable">Shizuku service not connected</string> <string name="shizuku_unavailable">Shizuku service not connected</string>
<string name="screen_home">Home</string>
<string name="screen_repo">Repo</string> <string name="screen_repo">Repo</string>
<string name="screen_logs">Logs</string> <string name="screen_logs">Logs</string>
<string name="off">Off</string> <string name="off">Off</string>
@ -21,6 +22,8 @@
<string name="home_framework_version">Framework Version</string> <string name="home_framework_version">Framework Version</string>
<string name="home_system_version">System Version</string> <string name="home_system_version">System Version</string>
<string name="home_device">Device</string> <string name="home_device">Device</string>
<string name="home_device_info">Equipment Information</string>
<string name="coming_soon">Stay tuned</string>
<string name="home_system_abi">System ABI</string> <string name="home_system_abi">System ABI</string>
<string name="home_info_copied">Copied to clipboard</string> <string name="home_info_copied">Copied to clipboard</string>
<string name="home_support">Support</string> <string name="home_support">Support</string>