diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/MainActivity.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/MainActivity.kt index 608d3eb9..a2875089 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/MainActivity.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/MainActivity.kt @@ -332,7 +332,7 @@ class MainActivity : AppCompatActivity() { Screen.MemberList -> screen = Screen.Chat Screen.VideoRecord -> screen = if (videoTarget is ConversationTarget.Pm) Screen.Dm else Screen.Chat Screen.PhotoRecord -> screen = Screen.Chat - Screen.Streams -> screen = Screen.Chat + Screen.Streams -> { vm.selectStream(null); screen = Screen.Chat } Screen.Chat -> screen = Screen.ChannelList Screen.Dm -> { vm.closeDm(); screen = Screen.ChannelList } Screen.Call -> screen = screenBeforeCall ?: Screen.ChannelList @@ -421,6 +421,7 @@ class MainActivity : AppCompatActivity() { onBack = { screen = Screen.ChannelList }, onStreams = { vm.selectStream(null); screen = Screen.Streams }, onWatchStream = { vm.selectStream(it); screen = Screen.Streams }, + onWatchAllStreams = { vm.watchAllStreams(); screen = Screen.Streams }, onPlayVideo = { msg -> videoMessage = msg }, onViewPhoto = { msg -> photoMessage = msg }, onRecordVideo = { @@ -441,8 +442,9 @@ class MainActivity : AppCompatActivity() { vm.currentChannel.collectAsState().value?.let { channel -> val sources by vm.streamSources.collectAsState() val selected by vm.streamSelection.collectAsState() + val viewAll by vm.streamViewAll.collectAsState() val failed by vm.streamSourcesFailed.collectAsState() - StreamScreen(channel.id, channel.name, sources, selected, failed, vm::selectStream) { + StreamScreen(channel.id, channel.name, sources, selected, failed, vm::selectStream, viewAll, vm::watchAllStreams) { vm.selectStream(null); screen = Screen.Chat } } diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/ChatScreen.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/ChatScreen.kt index e1d8397a..bb8bfae6 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/ChatScreen.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/ChatScreen.kt @@ -92,7 +92,8 @@ fun ChatScreen( onRecordVideo: () -> Unit = {}, onCapturePhoto: () -> Unit = {}, onStreams: () -> Unit = {}, - onWatchStream: (StreamSource) -> Unit = {} + onWatchStream: (StreamSource) -> Unit = {}, + onWatchAllStreams: () -> Unit = {} ) { val listState = rememberLazyListState() val context = LocalContext.current @@ -103,11 +104,14 @@ fun ChatScreen( var menu by remember(channel.id) { mutableStateOf(false) } val streams by viewModel.streamSources.collectAsState() var chooseStream by remember(channel.id) { mutableStateOf(false) } - if (chooseStream && streams.size > 1) AlertDialog( + if (chooseStream) AlertDialog( onDismissRequest = { chooseStream = false }, title = { Text(stringResource(R.string.stream_choose_source)) }, text = { Column(Modifier.heightIn(max = 360.dp).verticalScroll(rememberScrollState())) { + TextButton(onClick = { chooseStream = false; onWatchAllStreams() }) { + Text(stringResource(R.string.stream_watch_all)) + } streams.forEach { source -> TextButton(onClick = { chooseStream = false; onWatchStream(source) }) { Text("${source.displayName} · ${source.id.toULong()}") @@ -117,7 +121,6 @@ fun ChatScreen( }, confirmButton = { TextButton(onClick = { chooseStream = false }) { Text(stringResource(R.string.cancel)) } } ) - LaunchedEffect(streams) { if (streams.size <= 1) chooseStream = false } /* рация */ val radioActive by viewModel.radioActive.collectAsState() @@ -192,9 +195,7 @@ fun ChatScreen( IconButton(onClick = onBack) { Icon(Icons.AutoMirrored.Filled.ArrowBack, stringResource(R.string.back)) } }, actions = { - if (streams.isNotEmpty()) IconButton(onClick = { - if (streams.size == 1) onWatchStream(streams.single()) else chooseStream = true - }) { + IconButton(onClick = { chooseStream = true }) { BadgedBox(badge = { if (streams.size > 1) Badge { Text(streams.size.toString()) } }) { Icon(Icons.Filled.LiveTv, stringResource(R.string.stream_available, streams.size), tint = Color(0xFFE53935)) } diff --git a/tools/chatgui-android/app/src/main/java/com/utun/chat/viewmodel/ChatViewModel.kt b/tools/chatgui-android/app/src/main/java/com/utun/chat/viewmodel/ChatViewModel.kt index a21b0dfd..bc1ce29a 100644 --- a/tools/chatgui-android/app/src/main/java/com/utun/chat/viewmodel/ChatViewModel.kt +++ b/tools/chatgui-android/app/src/main/java/com/utun/chat/viewmodel/ChatViewModel.kt @@ -228,11 +228,17 @@ class ChatViewModel : ViewModel() { val streamSourcesFailed: StateFlow = _streamSourcesFailed private val _streamSelection = MutableStateFlow(null) val streamSelection: StateFlow = _streamSelection + private val _streamViewAll = MutableStateFlow(false) + val streamViewAll: StateFlow = _streamViewAll fun selectStream(source: StreamSource?) { - _streamSelection.value = source + _streamSelection.value = source; _streamViewAll.value = false LogManager.addLog("INFO", "stream", "selected channel=${_currentChannel.value?.id} source=${source?.id} epoch=${source?.epoch}") } + fun watchAllStreams() { + _streamSelection.value = null; _streamViewAll.value = true + LogManager.addLog("INFO", "stream", "watch all active streams channel=${_currentChannel.value?.id}") + } private fun watchStreams() { if (!NativeLib.isReady()) return @@ -379,7 +385,7 @@ class ChatViewModel : ViewModel() { } viewModelScope.launch { CallController.state.collect { call -> - if (call?.preparing == true || CallController.blocksMedia()) _streamSelection.value = null + if (call?.preparing == true || CallController.blocksMedia()) selectStream(null) } } viewModelScope.launch { @@ -596,7 +602,7 @@ class ChatViewModel : ViewModel() { 4 -> { if (repo != null) { LogManager.addLog("INFO", "VM", "CHANNEL_UPDATED — refreshChannels"); refreshChannels() } else { LogManager.addLog("WARN", "VM", "CHANNEL_UPDATED skipped — repo is NULL") } } 12 -> { LogManager.addLog("INFO", "VM", "service started"); watchStreams() } 13 -> { - _streamSources.value = emptyList(); _streamSourcesFailed.value = false; _streamSelection.value = null + _streamSources.value = emptyList(); _streamSourcesFailed.value = false; selectStream(null) for (id in submissions.keys.toList()) submissionResult(id, false) _radioTalkState.value = RadioTalkState() _radioTalking.value = null @@ -715,10 +721,10 @@ class ChatViewModel : ViewModel() { if (_currentChannel.value?.id?.toULongOrNull()?.toLong() != group || !_foreground.value) return try { _streamSourcesFailed.value = data[8].toInt() == 0 - _streamSources.value = StreamSource.parse(String(data, 9, data.size - 9, Charsets.UTF_8)) + if (!_streamSourcesFailed.value) _streamSources.value = StreamSource.parse(String(data, 9, data.size - 9, Charsets.UTF_8)) LogManager.addLog("INFO", "stream", "sources group=$group count=${_streamSources.value.size} valid=${!_streamSourcesFailed.value}") } catch (e: Exception) { - _streamSources.value = emptyList(); _streamSourcesFailed.value = true + _streamSourcesFailed.value = true LogManager.addLog("ERROR", "stream", "source snapshot parse group=$group: ${e.message}") } } @@ -1341,7 +1347,7 @@ class ChatViewModel : ViewModel() { fun selectChannel(channel: Channel) { val r = repo ?: return if (_currentChannel.value?.id != channel.id) { - _streamSources.value = emptyList(); _streamSourcesFailed.value = false; _streamSelection.value = null + _streamSources.value = emptyList(); _streamSourcesFailed.value = false; selectStream(null) _historyAnchor.value = "" _messageJump.value = null pendingLatestJump = null @@ -1923,7 +1929,7 @@ class ChatViewModel : ViewModel() { _channels.value = emptyList() _messages.value = emptyList() _currentChannel.value = null - _streamSources.value = emptyList(); _streamSelection.value = null; _streamSourcesFailed.value = false + _streamSources.value = emptyList(); selectStream(null); _streamSourcesFailed.value = false _generatingKeys.value = false _localSockets.value = emptyList() _channelOwner.value = false