From dac5f98052fe5858f0b1ae1d7051680a35bcf300 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 12 Oct 2026 07:22:43 +0200 Subject: [PATCH] Select local preview from the verified source snapshot --- .../com/utun/chat/ui/screens/StreamScreen.kt | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/StreamScreen.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/StreamScreen.kt index bad5e58b..0ae7010c 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/StreamScreen.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/StreamScreen.kt @@ -31,7 +31,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.withContext import org.json.JSONArray -private data class LiveSource(val id: Long, val name: String, val epoch: String) +private data class LiveSource(val id: Long, val name: String, val epoch: String, val self: Boolean) /** Выход с экрана закрывает только reader; foreground publisher останавливает явная кнопка/notification. */ @OptIn(ExperimentalMaterial3Api::class) @@ -43,6 +43,7 @@ fun StreamScreen(channelId: String, channelName: String, onBack: () -> Unit) { val local = state?.takeIf { it.group == group } var sources by remember(group) { mutableStateOf>(emptyList()) } var selected by remember(group) { mutableStateOf(null) } + var previewedSession by remember(group) { mutableStateOf(null) } var audio by remember { mutableStateOf(true) } var camera by remember { mutableStateOf("") } val cameras = remember { @@ -64,15 +65,17 @@ fun StreamScreen(channelId: String, channelName: String, onBack: () -> Unit) { val json = JSONArray(NativeLib.streamSources(group)) (0 until json.length()).map { i -> val member = json.getJSONObject(i) - LiveSource(member.getString("id").toULong().toLong(), member.getString("name"), member.getString("epoch")) + LiveSource(member.getString("id").toULong().toLong(), member.getString("name"), member.getString("epoch"), member.optInt("self") == 1) } } catch (e: Exception) { LogManager.addLog("WARN", "stream", "stream list: ${e.message}"); emptyList() } } else sources = emptyList() delay(1000) } } - LaunchedEffect(local?.id, local?.phase) { - if (local?.phase == StreamPhase.LIVE) selected = LiveSource(NativeLib.getMyNodeId(), channelName, local.id.toString()) + LaunchedEffect(sources, local?.id, local?.phase) { + if (local?.phase == StreamPhase.LIVE && previewedSession != local.id) sources.firstOrNull { it.self }?.let { + selected = it; previewedSession = local.id + } } Scaffold(topBar = { @@ -112,7 +115,7 @@ fun StreamScreen(channelId: String, channelName: String, onBack: () -> Unit) { TextButton(onClick = { selected = source }) { Text(stringResource(R.string.stream_watch, source.name.ifEmpty { source.id.toULong().toString() })) } } selected?.let { source -> - key(group, source.id, source.epoch) { LiveStreamView(group, source.id) } + key(group, source.id, source.epoch) { LiveStreamView(group, source.id, source.self) } TextButton(onClick = { selected = null }) { Text(stringResource(R.string.stream_close_view)) } } } @@ -120,8 +123,8 @@ fun StreamScreen(channelId: String, channelName: String, onBack: () -> Unit) { } @Composable -private fun LiveStreamView(group: Long, source: Long) { - val engine = remember(group, source) { StreamPlayerEngine(group, source) } +private fun LiveStreamView(group: Long, source: Long, localPreview: Boolean) { + val engine = remember(group, source, localPreview) { StreamPlayerEngine(group, source, localPreview) } val aspect by engine.aspect.collectAsState() val status by engine.status.collectAsState() var surface by remember { mutableStateOf(null) }