Expose watch-all streams from Android chat and preserve catalogue on transient errors
This commit is contained in:
1 parent
9e5b2ad435
commit
5f0325e817
3 files changed
+24
-15
No files matched your search
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -228,11 +228,17 @@ class ChatViewModel : ViewModel() {
|
||||
val streamSourcesFailed: StateFlow<Boolean> = _streamSourcesFailed
|
||||
private val _streamSelection = MutableStateFlow<StreamSource?>(null)
|
||||
val streamSelection: StateFlow<StreamSource?> = _streamSelection
|
||||
private val _streamViewAll = MutableStateFlow(false)
|
||||
val streamViewAll: StateFlow<Boolean> = _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
|
||||
|
||||
Reference in new issue
Block a user