From 336adc4948331932e8f9c018291003b55ac5cbaf Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 1 Apr 2026 23:47:35 +0000 Subject: [PATCH] feat: wire incoming call navigation and accept button - Add ObserveIncomingCalls composable in AppNavigation that watches callManager.state and navigates to ActiveCall screen when an IncomingCall is detected - Wire the accept button in CallScreen to call callController.acceptIncomingCall(sdpOffer), which sets the remote SDP, creates a WebRTC answer, and sends it back gift-wrapped - Pass CallController to CallScreen for accept functionality https://claude.ai/code/session_017hZm7yu7CzmcQgZGSaqSXS --- .../amethyst/ui/call/CallScreen.kt | 4 +++- .../amethyst/ui/navigation/AppNavigation.kt | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallScreen.kt index 337b16430..b3f1e687e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/call/CallScreen.kt @@ -55,6 +55,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import com.vitorpamplona.amethyst.commons.call.CallManager import com.vitorpamplona.amethyst.commons.call.CallState +import com.vitorpamplona.amethyst.service.call.CallController import com.vitorpamplona.amethyst.ui.note.ClickableUserPicture import com.vitorpamplona.amethyst.ui.note.UsernameDisplay import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel @@ -66,6 +67,7 @@ import kotlinx.coroutines.launch @Composable fun CallScreen( callManager: CallManager, + callController: CallController?, accountViewModel: AccountViewModel, onCallEnded: () -> Unit, ) { @@ -91,7 +93,7 @@ fun CallScreen( callerPubKey = state.callerPubKey, callType = state.callType, accountViewModel = accountViewModel, - onAccept = { /* handled by caller */ }, + onAccept = { callController?.acceptIncomingCall(state.sdpOffer) }, onReject = { scope.launch { callManager.rejectCall() } }, ) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt index a7827efc0..c78c9c0c3 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt @@ -28,6 +28,7 @@ import androidx.compose.animation.fadeOut import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -39,6 +40,7 @@ import androidx.core.util.Consumer import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.commons.call.CallState import com.vitorpamplona.amethyst.service.crashreports.DisplayCrashMessages import com.vitorpamplona.amethyst.service.relayClient.notifyCommand.compose.DisplayNotifyMessages import com.vitorpamplona.amethyst.ui.actions.NewUserMetadataScreen @@ -48,6 +50,7 @@ import com.vitorpamplona.amethyst.ui.call.CallScreen import com.vitorpamplona.amethyst.ui.components.getActivity import com.vitorpamplona.amethyst.ui.components.toasts.DisplayErrorMessages import com.vitorpamplona.amethyst.ui.navigation.composableFromEnd +import com.vitorpamplona.amethyst.ui.navigation.navs.INav import com.vitorpamplona.amethyst.ui.navigation.navs.Nav import com.vitorpamplona.amethyst.ui.navigation.navs.rememberNav import com.vitorpamplona.amethyst.ui.navigation.routes.Route @@ -162,6 +165,23 @@ fun AppNavigation( DisplayNotifyMessages(accountViewModel, nav) DisplayCrashMessages(accountViewModel, nav) DisplayBroadcastProgress(accountViewModel) + + ObserveIncomingCalls(accountViewModel, nav) +} + +@Composable +private fun ObserveIncomingCalls( + accountViewModel: AccountViewModel, + nav: INav, +) { + val callState by accountViewModel.callManager.state.collectAsState() + + LaunchedEffect(callState) { + val state = callState + if (state is CallState.IncomingCall) { + nav.nav(Route.ActiveCall(state.callId, state.callerPubKey)) + } + } } @Composable @@ -263,6 +283,7 @@ fun BuildNavigation( composableFromEndArgs { CallScreen( callManager = accountViewModel.callManager, + callController = accountViewModel.callController, accountViewModel = accountViewModel, onCallEnded = { nav.popBack() }, )