package com.hzliuzhi.applet.container.ui import android.content.Intent import android.provider.Settings import android.util.Patterns import android.widget.Toast import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.Send import androidx.compose.material.icons.filled.Info import androidx.compose.material.icons.filled.QrCode import androidx.compose.material3.Card import androidx.compose.material3.Icon import androidx.compose.material3.MaterialTheme import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Surface import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect 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.graphics.Color import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextDecoration import androidx.compose.ui.unit.dp import androidx.core.net.toUri import androidx.lifecycle.compose.LocalLifecycleOwner import com.hzliuzhi.applet.core.store.SettingStore import com.hzliuzhi.applet.scanner.ScanResult import com.hzliuzhi.applet.scanner.Scanner @Composable fun LauncherScreen( modifier: Modifier = Modifier, start: (String) -> String?, ) { val context = LocalContext.current var text by remember { mutableStateOf("") } var storeEnabled by remember { mutableStateOf(true) } Column( modifier = modifier .fillMaxSize() .padding(24.dp), verticalArrangement = Arrangement.Center ) { LauncherInputField( value = text, onValueChange = { text = it }, onDone = { start(text)?.also { SettingStore.getInstance(context).screen = if (storeEnabled) it else null } }, ) Spacer(modifier = Modifier.height(24.dp)) StorageCard( enabled = storeEnabled, enabledChange = { storeEnabled = it } ) } } @Composable fun LauncherInputField( value: String, onValueChange: (String) -> Unit, onDone: () -> Unit, modifier: Modifier = Modifier, ) { val context = LocalContext.current val scanner = Scanner.getInstance(context) val owner = LocalLifecycleOwner.current DisposableEffect(owner, scanner) { val observer: (ScanResult?) -> Unit = { result -> result?.code?.also { onValueChange(it) } } scanner.observe(owner, observer) onDispose { scanner.removeObserver(observer) } } val isUrl = remember(value) { Patterns.WEB_URL.matcher(value).matches() } val keyboardController = LocalSoftwareKeyboardController.current fun done() { if (isUrl) { keyboardController?.hide() onDone() } else Toast.makeText(context, "请输入合法的网址", Toast.LENGTH_SHORT).show() } OutlinedTextField( value = value, onValueChange = onValueChange, label = { Text("请输入URL") }, singleLine = true, isError = value.isNotBlank() && !isUrl, modifier = modifier.fillMaxWidth(), keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Uri, imeAction = ImeAction.Done ), keyboardActions = KeyboardActions(onDone = { done() }), trailingIcon = { if (value.isBlank()) { Icon( imageVector = Icons.Filled.QrCode, contentDescription = "扫码", modifier = Modifier.clickable { scanner.start() keyboardController?.hide() } ) } else { Icon( imageVector = Icons.AutoMirrored.Filled.Send, contentDescription = "完成", modifier = Modifier.clickable { done() } ) } } ) } @Composable fun StorageCard( enabled: Boolean, enabledChange: (Boolean) -> Unit, ) { val context = LocalContext.current val appName = runCatching { val info = context.applicationInfo info.labelRes.takeIf { it != 0 }?.let { context.getString(it) } ?: info.nonLocalizedLabel?.toString() }.getOrNull() ?: "本App" Card( modifier = Modifier.fillMaxWidth(), shape = MaterialTheme.shapes.medium, ) { Column( modifier = Modifier.padding(start = 12.dp, end = 12.dp) ) { // 头部:标题+开关 Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically ) { Text( text = "存储数据", style = MaterialTheme.typography.titleMedium, modifier = Modifier.weight(1f) ) Switch( checked = enabled, onCheckedChange = enabledChange ) } if (enabled) { Spacer(modifier = Modifier.height(8.dp)) Row(verticalAlignment = Alignment.CenterVertically) { Icon( imageVector = Icons.Default.Info, contentDescription = null, tint = MaterialTheme.colorScheme.secondary ) Spacer(modifier = Modifier.width(8.dp)) Text( text = "如需清除缓存,请在", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.secondary ) Text( text = "设置中操作", style = MaterialTheme.typography.bodyMedium.copy(color = Color(0xFF1976D2), textDecoration = TextDecoration.Underline), modifier = Modifier .clickable { val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { data = ("package:" + context.packageName).toUri() } context.startActivity(intent) } ) } Spacer(modifier = Modifier.height(12.dp)) Text( text = "清除数据:", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.primary ) Spacer(modifier = Modifier.height(8.dp)) Column { val steps = listOf( "打开系统设置", "找到应用管理", "选择$appName", "进入存储与缓存", "点击清除全部数据(存储空间)" ) steps.forEachIndexed { idx, step -> Row(verticalAlignment = Alignment.CenterVertically) { Surface( shape = MaterialTheme.shapes.small, color = MaterialTheme.colorScheme.primary.copy(alpha = 0.1f), modifier = Modifier.size(24.dp) ) { Box(contentAlignment = Alignment.Center) { Text("${idx + 1}", style = MaterialTheme.typography.labelMedium) } } Spacer(modifier = Modifier.width(8.dp)) Text(step, style = MaterialTheme.typography.bodySmall) } if (idx < steps.lastIndex) Spacer(modifier = Modifier.height(6.dp)) } } Spacer(modifier = Modifier.height(8.dp)) } } } }