topo_group_connect: infinite auto-connect cycle with pause + connecting nodes notification

- client_activity: desktop/server now ACTIVE by default, only mobile starts STANDBY
- topo_group_connect: endless Phase1→2→3→1 cycle until connected
- Pause between failed Phase2/3 attempts: 1s active, 30s standby
- on_down always triggers cycle_restart when active_conn_count=0
- re-init destroys previous state and starts fresh
- CHAT_EVT_CONNECTING_NODES event notifies GUI of current connecting nodes
- Android: ConfigProvider default mode='auto', PTT fix, UDP log timer fix
This commit is contained in:
evgeny committed 2026-08-12 18:05:44 +03:00
1 parent 5d02a6d419
commit 54ad03185b
10 files changed
+159 -63

No files matched your search

@@ -191,7 +191,7 @@ class ConfigProvider(private val context: Context) {
/* ── Connection mode ── */
fun getConnectionMode(): String = runBlocking {
context.dataStore.data.first()[connectionModeKey] ?: "manual"
context.dataStore.data.first()[connectionModeKey] ?: "auto"
}
suspend fun setConnectionMode(mode: String) {
@@ -378,41 +378,40 @@ fun InputBar(
modifier = Modifier
.size(48.dp)
.background(pttBg, RoundedCornerShape(4.dp))
.pointerInput(hasMicPerm) {
awaitPointerEventScope {
while (true) {
val down = awaitPointerEvent()
val ch = down.changes.firstOrNull() ?: continue
if (!ch.pressed) continue
ch.consume()
if (!hasMicPerm) {
permLauncher.launch(Manifest.permission.RECORD_AUDIO)
continue
}
onPttPressed()
var locked = false
var totalDragY = 0f
var lastY = ch.position.y
.then(if (!hasMicPerm) {
Modifier.clickable { permLauncher.launch(Manifest.permission.RECORD_AUDIO) }
} else {
Modifier.pointerInput(Unit) {
awaitPointerEventScope {
while (true) {
val event = awaitPointerEvent()
val change = event.changes.firstOrNull() ?: break
if (change.pressed) {
val dy = change.position.y - lastY
lastY = change.position.y
totalDragY += dy
if (totalDragY < -lockThresholdPx && !locked) { locked = true; onPttLock() }
change.consume()
} else {
change.consume(); break
val down = awaitPointerEvent()
val ch = down.changes.firstOrNull() ?: continue
if (!ch.pressed) continue
ch.consume()
onPttPressed()
var locked = false
var totalDragY = 0f
var lastY = ch.position.y
while (true) {
val event = awaitPointerEvent()
val change = event.changes.firstOrNull() ?: break
if (change.pressed) {
val dy = change.position.y - lastY
lastY = change.position.y
totalDragY += dy
if (totalDragY < -lockThresholdPx && !locked) { locked = true; onPttLock() }
change.consume()
} else {
change.consume(); break
}
}
onPttReleased()
}
onPttReleased()
}
}
},
}),
contentAlignment = Alignment.Center
) {
Text("\uD83C\uDFA4", fontSize = 20.sp, color = if (isRecording) Color.White else Color.Unspecified)
@@ -209,10 +209,10 @@ private fun GeneralSettingsTab(vm: ChatViewModel, dirty: Boolean, onDirty: (Bool
/* ── Connection Mode ── */
Text("Network Interfaces", style = MaterialTheme.typography.titleMedium)
Row(verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(8.dp)) {
FilterChip(selected = connectionMode == "manual", onClick = { if (connectionMode != "manual") switchMode("manual") },
label = { Text("Manual") })
FilterChip(selected = connectionMode == "auto", onClick = { if (connectionMode != "auto") switchMode("auto") },
label = { Text("Auto") })
FilterChip(selected = connectionMode == "manual", onClick = { if (connectionMode != "manual") switchMode("manual") },
label = { Text("Manual") })
}
if (connectionMode == "auto") {