fix: add event dedup, back button handling, and wake lock for calls
- Deduplicate signaling events via processedEventIds set in CallManager to prevent duplicate processing from multiple relays - BackHandler on CallScreen calls hangup() before navigating back - KeepScreenOn composable adds FLAG_KEEP_SCREEN_ON during calls and clears it on dispose https://claude.ai/code/session_017hZm7yu7CzmcQgZGSaqSXS
This commit is contained in:
@@ -20,6 +20,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.vitorpamplona.amethyst.ui.call
|
package com.vitorpamplona.amethyst.ui.call
|
||||||
|
|
||||||
|
import android.view.WindowManager
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@@ -40,6 +42,7 @@ import androidx.compose.material3.IconButton
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
@@ -50,6 +53,7 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
@@ -73,7 +77,13 @@ fun CallScreen(
|
|||||||
) {
|
) {
|
||||||
val callState by callManager.state.collectAsState()
|
val callState by callManager.state.collectAsState()
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val context = androidx.compose.ui.platform.LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
BackHandler(enabled = callState !is CallState.Idle && callState !is CallState.Ended) {
|
||||||
|
scope.launch { callManager.hangup() }
|
||||||
|
}
|
||||||
|
|
||||||
|
KeepScreenOn()
|
||||||
|
|
||||||
when (val state = callState) {
|
when (val state = callState) {
|
||||||
is CallState.Idle -> {
|
is CallState.Idle -> {
|
||||||
@@ -363,3 +373,15 @@ private fun formatDuration(seconds: Long): String {
|
|||||||
val secs = seconds % 60
|
val secs = seconds % 60
|
||||||
return "%02d:%02d".format(mins, secs)
|
return "%02d:%02d".format(mins, secs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun KeepScreenOn() {
|
||||||
|
val context = LocalContext.current
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
val window = (context as? android.app.Activity)?.window
|
||||||
|
window?.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
onDispose {
|
||||||
|
window?.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ class CallManager(
|
|||||||
|
|
||||||
private var timeoutJob: Job? = null
|
private var timeoutJob: Job? = null
|
||||||
private var resetJob: Job? = null
|
private var resetJob: Job? = null
|
||||||
|
private val processedEventIds = mutableSetOf<String>()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val CALL_TIMEOUT_MS = 60_000L // 60 seconds ringing timeout
|
const val CALL_TIMEOUT_MS = 60_000L // 60 seconds ringing timeout
|
||||||
@@ -198,6 +199,7 @@ class CallManager(
|
|||||||
|
|
||||||
fun onSignalingEvent(event: Event) {
|
fun onSignalingEvent(event: Event) {
|
||||||
if (isEventTooOld(event)) return
|
if (isEventTooOld(event)) return
|
||||||
|
if (!processedEventIds.add(event.id)) return
|
||||||
|
|
||||||
when (event) {
|
when (event) {
|
||||||
is CallOfferEvent -> onIncomingCallEvent(event)
|
is CallOfferEvent -> onIncomingCallEvent(event)
|
||||||
@@ -234,6 +236,7 @@ class CallManager(
|
|||||||
cancelTimeout()
|
cancelTimeout()
|
||||||
resetJob?.cancel()
|
resetJob?.cancel()
|
||||||
resetJob = null
|
resetJob = null
|
||||||
|
processedEventIds.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transitionToEnded(
|
private fun transitionToEnded(
|
||||||
|
|||||||
Reference in New Issue
Block a user