From 39bca58515a507c017cdb1a7cb888a2890ebc841 Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 20 Oct 2026 20:11:49 +0200 Subject: [PATCH] Open Android stream controls from own multiview tile --- .../utun/chat/ui/screens/StreamGridScreen.kt | 14 ++++++---- .../com/utun/chat/ui/screens/StreamScreen.kt | 28 +++++++++++++++++-- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/StreamGridScreen.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/StreamGridScreen.kt index 1f69f989..112f6258 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/StreamGridScreen.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/StreamGridScreen.kt @@ -50,7 +50,8 @@ private class GridStream(val source: StreamSource) { * Пустой каталог оставляет экран открытым; временный сбой каталога сохраняет действующие readers. */ @OptIn(ExperimentalMaterial3Api::class) @Composable -internal fun StreamGridScreen(group: Long, title: String, sources: List, unavailable: Boolean, onClose: () -> Unit) { +internal fun StreamGridScreen(group: Long, title: String, sources: List, unavailable: Boolean, + ownPreviewVisible: Boolean, onOwnStream: () -> Unit, onClose: () -> Unit) { val tiles = remember(group) { mutableStateListOf() } var expanded by remember(group) { mutableStateOf(null) } val focused = expanded?.takeIf { it in tiles } @@ -106,7 +107,7 @@ internal fun StreamGridScreen(group: Long, title: String, sources: List @@ -179,7 +182,8 @@ private fun StreamGridTile(group: Long, tile: GridStream, visible: Boolean, expa } } Box(Modifier.matchParentSize().clickable(interactionSource = remember { MutableInteractionSource() }, indication = null, - role = Role.Button, onClickLabel = stringResource(if (expanded) R.string.collapse else R.string.expand), onClick = onClick) + role = Role.Button, onClickLabel = stringResource(if (tile.source.self) R.string.stream_manage + else if (expanded) R.string.collapse else R.string.expand), onClick = onClick) .semantics { contentDescription = tile.source.displayName }) } } 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 3484cf85..b82c3239 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 @@ -11,6 +11,7 @@ import android.os.Handler import android.os.Looper import android.os.SystemClock import android.view.TextureView +import androidx.activity.compose.BackHandler import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.* @@ -27,6 +28,7 @@ import androidx.compose.material.icons.filled.ScreenRotation import androidx.compose.material.icons.filled.Stop import androidx.compose.material3.* import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.ui.Modifier import androidx.compose.ui.Alignment import androidx.compose.ui.geometry.CornerRadius @@ -75,10 +77,24 @@ import kotlin.math.roundToInt fun StreamScreen(channelId: String, channelName: String, sources: List, selected: StreamSource?, sourcesFailed: Boolean, onSelect: (StreamSource?) -> Unit, viewAll: Boolean = false, onBack: () -> Unit) { - val context = LocalContext.current val group = remember(channelId) { channelId.toULongOrNull()?.toLong() ?: 0L } if (viewAll) { - StreamGridScreen(group, channelName, sources, sourcesFailed) { onSelect(null); onBack() } + var manageOwn by rememberSaveable(group) { mutableStateOf(false) } + LaunchedEffect(manageOwn) { + LogManager.addLog("INFO", "stream", "multiview controls group=$group open=$manageOwn " + + "publisher=${StreamController.state.value?.id} readersPreserved=true") + } + Box(Modifier.fillMaxSize()) { + StreamGridScreen(group, channelName, sources, sourcesFailed, ownPreviewVisible = !manageOwn, onOwnStream = { + val publisher = StreamController.state.value + if (publisher?.ongoing == true && publisher.group == group) manageOwn = true + else LogManager.addLog("WARN", "stream", "multiview controls stale group=$group publisher=${publisher?.id} phase=${publisher?.phase}") + }, onClose = { onSelect(null); onBack() }) + if (manageOwn) { + BackHandler { manageOwn = false } + StreamPublishScreen(group, channelName) { manageOwn = false } + } + } return } if (selected != null && !selected.self) { @@ -87,6 +103,14 @@ fun StreamScreen(channelId: String, channelName: String, sources: List Unit) { + val context = LocalContext.current val displayDegrees = StreamDisplayDegrees() val state by StreamController.state.collectAsState() val local = state?.takeIf { it.group == group }