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

View File

@ -284,6 +284,7 @@ class NodeRuntime(context: Context) {
val manualHost: StateFlow<String> = prefs.manualHost val manualHost: StateFlow<String> = prefs.manualHost
val manualPort: StateFlow<Int> = prefs.manualPort val manualPort: StateFlow<Int> = prefs.manualPort
val manualTls: StateFlow<Boolean> = prefs.manualTls val manualTls: StateFlow<Boolean> = prefs.manualTls
val manualPassword: StateFlow<String> = prefs.manualPassword
val lastDiscoveredStableId: StateFlow<String> = prefs.lastDiscoveredStableId val lastDiscoveredStableId: StateFlow<String> = prefs.lastDiscoveredStableId
val canvasDebugStatusEnabled: StateFlow<Boolean> = prefs.canvasDebugStatusEnabled val canvasDebugStatusEnabled: StateFlow<Boolean> = prefs.canvasDebugStatusEnabled
@ -428,6 +429,10 @@ class NodeRuntime(context: Context) {
prefs.setManualTls(value) prefs.setManualTls(value)
} }
fun setManualPassword(value: String) {
prefs.setManualPassword(value)
}
fun setCanvasDebugStatusEnabled(value: Boolean) { fun setCanvasDebugStatusEnabled(value: Boolean) {
prefs.setCanvasDebugStatusEnabled(value) prefs.setCanvasDebugStatusEnabled(value)
} }
@ -563,7 +568,12 @@ class NodeRuntime(context: Context) {
nodeStatusText = "Connecting…" nodeStatusText = "Connecting…"
updateStatus() updateStatus()
val token = prefs.loadGatewayToken() 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) val tls = resolveTlsParams(endpoint)
operatorSession.connect(endpoint, token, password, buildOperatorConnectOptions(), tls) operatorSession.connect(endpoint, token, password, buildOperatorConnectOptions(), tls)
nodeSession.connect(endpoint, token, password, buildNodeConnectOptions(), 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)) MutableStateFlow(readBoolWithMigration("gateway.manual.tls", null, true))
val manualTls: StateFlow<Boolean> = _manualTls val manualTls: StateFlow<Boolean> = _manualTls
private val _manualPassword =
MutableStateFlow(prefs.getString("gateway.manual.password", null)?.trim() ?: "")
val manualPassword: StateFlow<String> = _manualPassword
private val _lastDiscoveredStableId = private val _lastDiscoveredStableId =
MutableStateFlow( MutableStateFlow(
readStringWithMigration( readStringWithMigration(
@ -150,6 +154,12 @@ class SecurePrefs(context: Context) {
_manualTls.value = value _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) { fun setCanvasDebugStatusEnabled(value: Boolean) {
prefs.edit { putBoolean("canvas.debugStatusEnabled", value) } prefs.edit { putBoolean("canvas.debugStatusEnabled", value) }
_canvasDebugStatusEnabled.value = 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.LocalContext
import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.input.ImeAction 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.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
@ -82,6 +83,7 @@ fun SettingsSheet(viewModel: MainViewModel) {
val manualHost by viewModel.manualHost.collectAsState() val manualHost by viewModel.manualHost.collectAsState()
val manualPort by viewModel.manualPort.collectAsState() val manualPort by viewModel.manualPort.collectAsState()
val manualTls by viewModel.manualTls.collectAsState() val manualTls by viewModel.manualTls.collectAsState()
val manualPassword by viewModel.manualPassword.collectAsState()
val canvasDebugStatusEnabled by viewModel.canvasDebugStatusEnabled.collectAsState() val canvasDebugStatusEnabled by viewModel.canvasDebugStatusEnabled.collectAsState()
val statusText by viewModel.statusText.collectAsState() val statusText by viewModel.statusText.collectAsState()
val serverName by viewModel.serverName.collectAsState() val serverName by viewModel.serverName.collectAsState()
@ -403,6 +405,15 @@ fun SettingsSheet(viewModel: MainViewModel) {
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = manualEnabled, enabled = manualEnabled,
) )
OutlinedTextField(
value = manualPassword,
onValueChange = viewModel::setManualPassword,
label = { Text("Password") },
modifier = Modifier.fillMaxWidth(),
enabled = manualEnabled,
visualTransformation = PasswordVisualTransformation(),
singleLine = true,
)
ListItem( ListItem(
headlineContent = { Text("Require TLS") }, headlineContent = { Text("Require TLS") },
supportingContent = { Text("Pin the gateway certificate on first connect.") }, supportingContent = { Text("Pin the gateway certificate on first connect.") },