Add password field to Android manual gateway settings

This commit is contained in:
Dave Finkelstein 2026-01-25 21:01:53 +00:00
parent a187cd47f7
commit 9aa1f2ad56
4 changed files with 37 additions and 1 deletions

View File

@ -51,6 +51,7 @@ class MainViewModel(app: Application) : AndroidViewModel(app) {
val manualHost: StateFlow<String> = runtime.manualHost
val manualPort: StateFlow<Int> = runtime.manualPort
val manualTls: StateFlow<Boolean> = runtime.manualTls
val manualPassword: StateFlow<String> = runtime.manualPassword
val canvasDebugStatusEnabled: StateFlow<Boolean> = runtime.canvasDebugStatusEnabled
val chatSessionKey: StateFlow<String> = runtime.chatSessionKey
@ -104,6 +105,10 @@ class MainViewModel(app: Application) : AndroidViewModel(app) {
runtime.setManualTls(value)
}
fun setManualPassword(value: String) {
runtime.setManualPassword(value)
}
fun setCanvasDebugStatusEnabled(value: Boolean) {
runtime.setCanvasDebugStatusEnabled(value)
}

View File

@ -284,6 +284,7 @@ class NodeRuntime(context: Context) {
val manualHost: StateFlow<String> = prefs.manualHost
val manualPort: StateFlow<Int> = prefs.manualPort
val manualTls: StateFlow<Boolean> = prefs.manualTls
val manualPassword: StateFlow<String> = prefs.manualPassword
val lastDiscoveredStableId: StateFlow<String> = prefs.lastDiscoveredStableId
val canvasDebugStatusEnabled: StateFlow<Boolean> = prefs.canvasDebugStatusEnabled
@ -428,6 +429,10 @@ class NodeRuntime(context: Context) {
prefs.setManualTls(value)
}
fun setManualPassword(value: String) {
prefs.setManualPassword(value)
}
fun setCanvasDebugStatusEnabled(value: Boolean) {
prefs.setCanvasDebugStatusEnabled(value)
}
@ -563,7 +568,12 @@ class NodeRuntime(context: Context) {
nodeStatusText = "Connecting…"
updateStatus()
val token = prefs.loadGatewayToken()
val password = prefs.loadGatewayPassword()
// For manual endpoints, use the manual password if set; otherwise fall back to stored password.
val password = if (endpoint.stableId.startsWith("manual|")) {
manualPassword.value.takeIf { it.isNotEmpty() } ?: prefs.loadGatewayPassword()
} else {
prefs.loadGatewayPassword()
}
val tls = resolveTlsParams(endpoint)
operatorSession.connect(endpoint, token, password, buildOperatorConnectOptions(), tls)
nodeSession.connect(endpoint, token, password, buildNodeConnectOptions(), tls)

View File

@ -74,6 +74,10 @@ class SecurePrefs(context: Context) {
MutableStateFlow(readBoolWithMigration("gateway.manual.tls", null, true))
val manualTls: StateFlow<Boolean> = _manualTls
private val _manualPassword =
MutableStateFlow(prefs.getString("gateway.manual.password", null)?.trim() ?: "")
val manualPassword: StateFlow<String> = _manualPassword
private val _lastDiscoveredStableId =
MutableStateFlow(
readStringWithMigration(
@ -150,6 +154,12 @@ class SecurePrefs(context: Context) {
_manualTls.value = value
}
fun setManualPassword(value: String) {
val trimmed = value.trim()
prefs.edit { putString("gateway.manual.password", trimmed) }
_manualPassword.value = trimmed
}
fun setCanvasDebugStatusEnabled(value: Boolean) {
prefs.edit { putBoolean("canvas.debugStatusEnabled", value) }
_canvasDebugStatusEnabled.value = value

View File

@ -55,6 +55,7 @@ import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat
@ -82,6 +83,7 @@ fun SettingsSheet(viewModel: MainViewModel) {
val manualHost by viewModel.manualHost.collectAsState()
val manualPort by viewModel.manualPort.collectAsState()
val manualTls by viewModel.manualTls.collectAsState()
val manualPassword by viewModel.manualPassword.collectAsState()
val canvasDebugStatusEnabled by viewModel.canvasDebugStatusEnabled.collectAsState()
val statusText by viewModel.statusText.collectAsState()
val serverName by viewModel.serverName.collectAsState()
@ -403,6 +405,15 @@ fun SettingsSheet(viewModel: MainViewModel) {
modifier = Modifier.fillMaxWidth(),
enabled = manualEnabled,
)
OutlinedTextField(
value = manualPassword,
onValueChange = viewModel::setManualPassword,
label = { Text("Password") },
modifier = Modifier.fillMaxWidth(),
enabled = manualEnabled,
visualTransformation = PasswordVisualTransformation(),
singleLine = true,
)
ListItem(
headlineContent = { Text("Require TLS") },
supportingContent = { Text("Pin the gateway certificate on first connect.") },