| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- 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))
- }
- }
- }
- }
|