diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt index 8f32b3a34..071c39fd9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/call/CallController.kt @@ -229,14 +229,6 @@ class CallController( } // ---- Call initiation (caller side) ---- - - fun initiateCall( - peerPubKey: String, - callType: CallType, - ) { - initiateCallInternal(setOf(peerPubKey), callType) - } - fun initiateGroupCall( peerPubKeys: Set, callType: CallType, diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt index 10fe6ef71..755184458 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/ChatroomScreen.kt @@ -49,28 +49,17 @@ fun ChatroomScreen( nav: INav, ) { val context = LocalContext.current - val isGroupChat = roomId.users.size > 1 val isCallSupported = roomId.users.size <= 5 val startVoiceCall = rememberCallWithPermission(context) { ActiveCallHolder.set(accountViewModel.callManager, accountViewModel.callController, accountViewModel) - if (isGroupChat) { - accountViewModel.callController?.initiateGroupCall(roomId.users.toSet(), CallType.VOICE) - } else { - val peerPubKey = roomId.users.firstOrNull() ?: return@rememberCallWithPermission - accountViewModel.callController?.initiateCall(peerPubKey, CallType.VOICE) - } + accountViewModel.callController?.initiateGroupCall(roomId.users.toSet(), CallType.VOICE) CallActivity.launch(context) } val startVideoCall = rememberCallWithPermission(context, isVideo = true) { ActiveCallHolder.set(accountViewModel.callManager, accountViewModel.callController, accountViewModel) - if (isGroupChat) { - accountViewModel.callController?.initiateGroupCall(roomId.users.toSet(), CallType.VIDEO) - } else { - val peerPubKey = roomId.users.firstOrNull() ?: return@rememberCallWithPermission - accountViewModel.callController?.initiateCall(peerPubKey, CallType.VIDEO) - } + accountViewModel.callController?.initiateGroupCall(roomId.users.toSet(), CallType.VIDEO) CallActivity.launch(context) } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/ChatroomHeader.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/ChatroomHeader.kt index 09085a2d0..a73a8fb57 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/ChatroomHeader.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/header/ChatroomHeader.kt @@ -27,11 +27,6 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Call -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -52,7 +47,6 @@ fun ChatroomHeader( room: ChatroomKey, modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, - onCallClick: ((String) -> Unit)? = null, onClick: () -> Unit, ) { if (room.users.size == 1) { @@ -63,7 +57,6 @@ fun ChatroomHeader( modifier = modifier, accountViewModel = accountViewModel, onClick = onClick, - onCallClick = onCallClick?.let { callback -> { callback(baseUser.pubkeyHex) } }, ) } } @@ -83,7 +76,6 @@ fun UserChatroomHeader( modifier: Modifier = StdPadding, accountViewModel: AccountViewModel, onClick: () -> Unit, - onCallClick: (() -> Unit)? = null, ) { Column( Modifier @@ -108,20 +100,6 @@ fun UserChatroomHeader( ) { UsernameDisplay(baseUser, accountViewModel = accountViewModel) } - - if (onCallClick != null) { - IconButton( - onClick = onCallClick, - modifier = Modifier.size(40.dp), - ) { - Icon( - imageVector = Icons.Default.Call, - contentDescription = "Voice call", - tint = MaterialTheme.colorScheme.primary, - modifier = Modifier.size(20.dp), - ) - } - } } } } diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallAnswerEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallAnswerEvent.kt index f560dc5c6..553ee5ad8 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallAnswerEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallAnswerEvent.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.quartz.nipACWebRtcCalls.events import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate @@ -29,7 +28,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTagIds import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallIdTag import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.callId @Immutable @@ -40,9 +38,7 @@ class CallAnswerEvent( tags: Array>, content: String, sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - +) : WebRTCEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun sdpAnswer() = content /** All pubkeys referenced by `p` tags in this event. */ diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallHangupEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallHangupEvent.kt index e1e39a72e..6b5ae3673 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallHangupEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallHangupEvent.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.quartz.nipACWebRtcCalls.events import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate @@ -29,7 +28,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTagIds import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallIdTag import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.callId @Immutable @@ -40,9 +38,7 @@ class CallHangupEvent( tags: Array>, content: String, sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - +) : WebRTCEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun reason() = content.ifEmpty { null } /** All pubkeys referenced by `p` tags in this event. */ diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallIceCandidateEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallIceCandidateEvent.kt index 106b4cb9e..697198a66 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallIceCandidateEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallIceCandidateEvent.kt @@ -21,13 +21,11 @@ package com.vitorpamplona.quartz.nipACWebRtcCalls.events import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallIdTag import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.callId @Immutable @@ -38,9 +36,7 @@ class CallIceCandidateEvent( tags: Array>, content: String, sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - +) : WebRTCEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun candidateJson() = content fun candidateSdp(): String = CANDIDATE_REGEX.find(content)?.groupValues?.get(1) ?: "" diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallOfferEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallOfferEvent.kt index 0ca69678f..4356f8b31 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallOfferEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallOfferEvent.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.quartz.nipACWebRtcCalls.events import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate @@ -29,7 +28,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTagIds import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallIdTag import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallType import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallTypeTag import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.callId @@ -43,9 +41,7 @@ class CallOfferEvent( tags: Array>, content: String, sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - +) : WebRTCEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun callType() = tags.firstNotNullOfOrNull(CallTypeTag::parse) fun sdpOffer() = content diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallRejectEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallRejectEvent.kt index 858a45270..664bf923d 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallRejectEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallRejectEvent.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.quartz.nipACWebRtcCalls.events import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate @@ -29,7 +28,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTagIds import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallIdTag import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.callId @Immutable @@ -40,9 +38,7 @@ class CallRejectEvent( tags: Array>, content: String, sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - +) : WebRTCEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun reason() = content.ifEmpty { null } /** All pubkeys referenced by `p` tags in this event. */ diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallRenegotiateEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallRenegotiateEvent.kt index 852bc0300..df39efc94 100644 --- a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallRenegotiateEvent.kt +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/CallRenegotiateEvent.kt @@ -21,7 +21,6 @@ package com.vitorpamplona.quartz.nipACWebRtcCalls.events import androidx.compose.runtime.Immutable -import com.vitorpamplona.quartz.nip01Core.core.Event import com.vitorpamplona.quartz.nip01Core.core.HexKey import com.vitorpamplona.quartz.nip01Core.core.TagArrayBuilder import com.vitorpamplona.quartz.nip01Core.signers.eventTemplate @@ -29,7 +28,6 @@ import com.vitorpamplona.quartz.nip01Core.tags.people.PTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTag import com.vitorpamplona.quartz.nip01Core.tags.people.pTagIds import com.vitorpamplona.quartz.nip31Alts.alt -import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallIdTag import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.callId @Immutable @@ -40,9 +38,7 @@ class CallRenegotiateEvent( tags: Array>, content: String, sig: HexKey, -) : Event(id, pubKey, createdAt, KIND, tags, content, sig) { - fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) - +) : WebRTCEvent(id, pubKey, createdAt, KIND, tags, content, sig) { fun sdpOffer() = content /** All pubkeys referenced by `p` tags in this event. */ diff --git a/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/WebRTCEvent.kt b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/WebRTCEvent.kt new file mode 100644 index 000000000..009ebca09 --- /dev/null +++ b/quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nipACWebRtcCalls/events/WebRTCEvent.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2025 Vitor Pamplona + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the + * Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package com.vitorpamplona.quartz.nipACWebRtcCalls.events + +import androidx.compose.runtime.Immutable +import com.vitorpamplona.quartz.nip01Core.core.Event +import com.vitorpamplona.quartz.nip01Core.core.HexKey +import com.vitorpamplona.quartz.nip01Core.core.Kind +import com.vitorpamplona.quartz.nipACWebRtcCalls.tags.CallIdTag + +@Immutable +abstract class WebRTCEvent( + id: HexKey, + pubKey: HexKey, + createdAt: Long, + kind: Kind, + tags: Array>, + content: String, + sig: HexKey, +) : Event(id, pubKey, createdAt, kind, tags, content, sig) { + fun callId() = tags.firstNotNullOfOrNull(CallIdTag::parse) +}