|
|
|
|
@ -72,7 +72,7 @@ fun SettingsScreen(vm: ChatViewModel, onBack: () -> Unit, onExit: () -> Unit = {
|
|
|
|
|
var dirty by rememberSaveable { mutableStateOf(false) } |
|
|
|
|
|
|
|
|
|
var tabIndex by rememberSaveable { mutableStateOf(0) } |
|
|
|
|
val tabs = listOf(R.string.settings, R.string.audio, R.string.storage, R.string.radio) |
|
|
|
|
val tabs = listOf(R.string.settings, R.string.audio, R.string.storage, R.string.radio, R.string.dev) |
|
|
|
|
|
|
|
|
|
val handleBack = { |
|
|
|
|
if (dirty && NativeLib.isReady()) { |
|
|
|
|
@ -101,25 +101,52 @@ fun SettingsScreen(vm: ChatViewModel, onBack: () -> Unit, onExit: () -> Unit = {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
when (tabIndex) { |
|
|
|
|
0 -> GeneralSettingsTab(vm, dirty, onDirty = { dirty = it }, onExit) |
|
|
|
|
0 -> GeneralSettingsTab(onDirty = { dirty = it }) |
|
|
|
|
1 -> AudioSettingsTab(vm) |
|
|
|
|
2 -> StorageSettingsTab() |
|
|
|
|
3 -> RadioSettingsTab() |
|
|
|
|
4 -> DeveloperSettingsTab(vm, onDirty = { dirty = it }, onExit) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* ── General Settings Tab ── */ |
|
|
|
|
/* Основные настройки профиля и приложения. */ |
|
|
|
|
|
|
|
|
|
@Composable |
|
|
|
|
private fun GeneralSettingsTab(onDirty: (Boolean) -> Unit) { |
|
|
|
|
val provider = ChatApplication.instance.configProvider |
|
|
|
|
val scope = rememberCoroutineScope() |
|
|
|
|
var nodeName by remember { mutableStateOf("") } |
|
|
|
|
|
|
|
|
|
LaunchedEffect(Unit) { |
|
|
|
|
nodeName = provider.getString("node.name") ?: provider.getDeviceName() |
|
|
|
|
LogManager.addLog("INFO", "SETTINGS", "General settings opened") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
LazyColumn( |
|
|
|
|
modifier = Modifier.fillMaxSize(), |
|
|
|
|
contentPadding = PaddingValues(16.dp), |
|
|
|
|
verticalArrangement = Arrangement.spacedBy(12.dp) |
|
|
|
|
) { |
|
|
|
|
item(key = "language") { LanguageSetting() } |
|
|
|
|
item(key = "battery") { BatteryOptimizationSetting(source = "settings") } |
|
|
|
|
item(key = "node-name") { |
|
|
|
|
OutlinedTextField(nodeName, { v -> onDirty(true); nodeName = v; scope.launch { provider.setValue("node.name", v) } }, |
|
|
|
|
label = { Text(stringResource(R.string.node_name)) }, singleLine = true, modifier = Modifier.heightIn(min = 40.dp)) |
|
|
|
|
} |
|
|
|
|
item(key = "profile-avatar") { ProfileAvatarControls() } |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Настройки разработчика: сеть, ключи, standby, диагностика и управление сервисом. */ |
|
|
|
|
|
|
|
|
|
@OptIn(ExperimentalMaterial3Api::class) |
|
|
|
|
@Composable |
|
|
|
|
private fun GeneralSettingsTab(vm: ChatViewModel, dirty: Boolean, onDirty: (Boolean) -> Unit, |
|
|
|
|
onExit: () -> Unit) { |
|
|
|
|
private fun DeveloperSettingsTab(vm: ChatViewModel, onDirty: (Boolean) -> Unit, onExit: () -> Unit) { |
|
|
|
|
val provider = ChatApplication.instance.configProvider |
|
|
|
|
val scope = rememberCoroutineScope() |
|
|
|
|
|
|
|
|
|
var nodeName by remember { mutableStateOf("") } |
|
|
|
|
var listenPort by remember { mutableStateOf("12345") } |
|
|
|
|
var controlPort by remember { mutableStateOf("9999") } |
|
|
|
|
var controlBindIp by remember { mutableStateOf("127.0.0.1") } |
|
|
|
|
@ -152,7 +179,6 @@ private fun GeneralSettingsTab(vm: ChatViewModel, dirty: Boolean, onDirty: (Bool
|
|
|
|
|
var startOnBootError by remember { mutableStateOf(false) } |
|
|
|
|
|
|
|
|
|
LaunchedEffect(Unit) { |
|
|
|
|
nodeName = provider.getString("node.name") ?: provider.getDeviceName() |
|
|
|
|
listenPort = provider.getInt("node.listen_port").toString() |
|
|
|
|
controlPort = provider.getInt("control.port").toString() |
|
|
|
|
controlBindIp = provider.getString("control.bind_ip") ?: "127.0.0.1" |
|
|
|
|
@ -206,7 +232,7 @@ private fun GeneralSettingsTab(vm: ChatViewModel, dirty: Boolean, onDirty: (Bool
|
|
|
|
|
val openedAt = remember { android.os.SystemClock.uptimeMillis() } |
|
|
|
|
LaunchedEffect(Unit) { |
|
|
|
|
withFrameNanos { } |
|
|
|
|
LogManager.addLog("INFO", "SETTINGS", "General settings displayed: elapsedMs=${android.os.SystemClock.uptimeMillis() - openedAt} " + |
|
|
|
|
LogManager.addLog("INFO", "SETTINGS", "Dev settings displayed: elapsedMs=${android.os.SystemClock.uptimeMillis() - openedAt} " + |
|
|
|
|
"visibleItems=${listState.layoutInfo.visibleItemsInfo.size} totalItems=${listState.layoutInfo.totalItemsCount}") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -217,15 +243,8 @@ private fun GeneralSettingsTab(vm: ChatViewModel, dirty: Boolean, onDirty: (Bool
|
|
|
|
|
contentPadding = PaddingValues(16.dp), |
|
|
|
|
verticalArrangement = Arrangement.spacedBy(12.dp) |
|
|
|
|
) { |
|
|
|
|
item(key = "language") { LanguageSetting() } |
|
|
|
|
item(key = "battery") { BatteryOptimizationSetting(source = "settings") } |
|
|
|
|
|
|
|
|
|
/* Node */ |
|
|
|
|
item(key = "node-title") { Text(stringResource(R.string.node), style = MaterialTheme.typography.titleMedium) } |
|
|
|
|
item(key = "node-name") { |
|
|
|
|
OutlinedTextField(nodeName, { v -> onDirty(true); nodeName = v; scope.launch { provider.setValue("node.name", v) } }, |
|
|
|
|
label = { Text(stringResource(R.string.node_name)) }, singleLine = true, modifier = Modifier.heightIn(min = 40.dp)) |
|
|
|
|
} |
|
|
|
|
item(key = "listen-port") { |
|
|
|
|
OutlinedTextField(listenPort, { v -> onDirty(true); listenPort = v; scope.launch { provider.setValue("node.listen_port", v) } }, |
|
|
|
|
label = { Text(stringResource(R.string.listen_port)) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), |
|
|
|
|
@ -256,8 +275,6 @@ private fun GeneralSettingsTab(vm: ChatViewModel, dirty: Boolean, onDirty: (Bool
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
item(key = "profile-avatar") { ProfileAvatarControls() } |
|
|
|
|
|
|
|
|
|
/* Keys */ |
|
|
|
|
item(key = "keys-title") { Text(stringResource(R.string.keys), style = MaterialTheme.typography.titleMedium) } |
|
|
|
|
item(key = "public-key") { OutlinedTextField(pubKey, {}, label = { Text(stringResource(R.string.public_key)) }, readOnly = true, singleLine = true) } |
|
|
|
|
|