diff --git a/buildSrc/src/main/kotlin/io/getstream/video/android/Configuration.kt b/buildSrc/src/main/kotlin/io/getstream/video/android/Configuration.kt index d425890f2e..39c5a85035 100644 --- a/buildSrc/src/main/kotlin/io/getstream/video/android/Configuration.kt +++ b/buildSrc/src/main/kotlin/io/getstream/video/android/Configuration.kt @@ -6,11 +6,11 @@ object Configuration { const val minSdk = 24 const val majorVersion = 0 const val minorVersion = 5 - const val patchVersion = 5 + const val patchVersion = 6 const val versionName = "$majorVersion.$minorVersion.$patchVersion" - const val versionCode = 19 + const val versionCode = 20 const val snapshotVersionName = "$majorVersion.$minorVersion.${patchVersion + 1}-SNAPSHOT" const val artifactGroup = "io.getstream" - const val streamVideoCallGooglePlayVersion = "1.0.7" + const val streamVideoCallGooglePlayVersion = "1.0.8" const val streamWebRtcVersionName = "1.1.1" } diff --git a/docusaurus/docs/Android/02-tutorials/01-video-calling.mdx b/docusaurus/docs/Android/02-tutorials/01-video-calling.mdx index 2df29c2583..f7cf69cb36 100644 --- a/docusaurus/docs/Android/02-tutorials/01-video-calling.mdx +++ b/docusaurus/docs/Android/02-tutorials/01-video-calling.mdx @@ -31,7 +31,7 @@ If you're new to android, note that there are 2 `build.gradle` files, you want t ```kotlin dependencies { // Stream Video Compose SDK - implementation("io.getstream:stream-video-android-ui-compose:0.5.5") + implementation("io.getstream:stream-video-android-ui-compose:0.5.6") // Optionally add Jetpack Compose if Android studio didn't automatically include them implementation(platform("androidx.compose:compose-bom:2023.08.00")) diff --git a/docusaurus/docs/Android/02-tutorials/02-audio-room.mdx b/docusaurus/docs/Android/02-tutorials/02-audio-room.mdx index da1bec4a09..cbf1678398 100644 --- a/docusaurus/docs/Android/02-tutorials/02-audio-room.mdx +++ b/docusaurus/docs/Android/02-tutorials/02-audio-room.mdx @@ -35,7 +35,7 @@ If you're new to android, note that there are 2 `build.gradle` files, you want t ```groovy dependencies { // Stream Video Compose SDK - implementation("io.getstream:stream-video-android-ui-compose:0.5.5") + implementation("io.getstream:stream-video-android-ui-compose:0.5.6") // Jetpack Compose (optional/ android studio typically adds them when you create a new project) implementation(platform("androidx.compose:compose-bom:2023.08.00")) diff --git a/docusaurus/docs/Android/02-tutorials/03-livestream.mdx b/docusaurus/docs/Android/02-tutorials/03-livestream.mdx index ced73749bb..2fbe9459b4 100644 --- a/docusaurus/docs/Android/02-tutorials/03-livestream.mdx +++ b/docusaurus/docs/Android/02-tutorials/03-livestream.mdx @@ -35,7 +35,7 @@ If you're new to android, note that there are 2 `build.gradle` files, you want t ```kotlin dependencies { // Stream Video Compose SDK - implementation("io.getstream:stream-video-android-ui-compose:0.5.5") + implementation("io.getstream:stream-video-android-ui-compose:0.5.6") // Jetpack Compose (optional/ android studio typically adds them when you create a new project) implementation(platform("androidx.compose:compose-bom:2023.08.00")) diff --git a/docusaurus/docs/Android/06-advanced/07-chat-with-video.mdx b/docusaurus/docs/Android/06-advanced/07-chat-with-video.mdx index 98f74a5c72..60440e7a7a 100644 --- a/docusaurus/docs/Android/06-advanced/07-chat-with-video.mdx +++ b/docusaurus/docs/Android/06-advanced/07-chat-with-video.mdx @@ -31,7 +31,7 @@ Let the project sync. It should have all the dependencies required for you to fi ```groovy dependencies { // Stream Video Compose SDK - implementation("io.getstream:stream-video-android-ui-compose:0.5.5") + implementation("io.getstream:stream-video-android-ui-compose:0.5.6") // Stream Chat implementation(libs.stream.chat.compose) diff --git a/stream-video-android-core/api/stream-video-android-core.api b/stream-video-android-core/api/stream-video-android-core.api index 4ac8c77f79..7fae4abb09 100644 --- a/stream-video-android-core/api/stream-video-android-core.api +++ b/stream-video-android-core/api/stream-video-android-core.api @@ -4116,7 +4116,6 @@ public final class io/getstream/video/android/core/notifications/NotificationCon public abstract interface class io/getstream/video/android/core/notifications/NotificationHandler : io/getstream/android/push/permissions/NotificationPermissionHandler { public static final field ACTION_ACCEPT_CALL Ljava/lang/String; - public static final field ACTION_DISMISS_NOTIFICATION Ljava/lang/String; public static final field ACTION_INCOMING_CALL Ljava/lang/String; public static final field ACTION_LEAVE_CALL Ljava/lang/String; public static final field ACTION_LIVE_CALL Ljava/lang/String; @@ -4128,8 +4127,6 @@ public abstract interface class io/getstream/video/android/core/notifications/No public static final field INCOMING_CALL_NOTIFICATION_ID I public static final field INTENT_EXTRA_CALL_CID Ljava/lang/String; public static final field INTENT_EXTRA_CALL_DISPLAY_NAME Ljava/lang/String; - public static final field INTENT_EXTRA_NEXT_ACTION Ljava/lang/String; - public static final field INTENT_EXTRA_NEXT_ACTION_BUNDLE Ljava/lang/String; public static final field INTENT_EXTRA_NOTIFICATION_ID Ljava/lang/String; public abstract fun getOngoingCallNotification (Lio/getstream/video/android/model/StreamCallId;)Landroid/app/Notification; public abstract fun getRingingCallNotification (Lio/getstream/video/android/core/RingingState;Lio/getstream/video/android/model/StreamCallId;Ljava/lang/String;)Landroid/app/Notification; @@ -4140,7 +4137,6 @@ public abstract interface class io/getstream/video/android/core/notifications/No public final class io/getstream/video/android/core/notifications/NotificationHandler$Companion { public static final field ACTION_ACCEPT_CALL Ljava/lang/String; - public static final field ACTION_DISMISS_NOTIFICATION Ljava/lang/String; public static final field ACTION_INCOMING_CALL Ljava/lang/String; public static final field ACTION_LEAVE_CALL Ljava/lang/String; public static final field ACTION_LIVE_CALL Ljava/lang/String; @@ -4151,8 +4147,6 @@ public final class io/getstream/video/android/core/notifications/NotificationHan public static final field INCOMING_CALL_NOTIFICATION_ID I public static final field INTENT_EXTRA_CALL_CID Ljava/lang/String; public static final field INTENT_EXTRA_CALL_DISPLAY_NAME Ljava/lang/String; - public static final field INTENT_EXTRA_NEXT_ACTION Ljava/lang/String; - public static final field INTENT_EXTRA_NEXT_ACTION_BUNDLE Ljava/lang/String; public static final field INTENT_EXTRA_NOTIFICATION_ID Ljava/lang/String; } diff --git a/stream-video-android-core/src/main/AndroidManifest.xml b/stream-video-android-core/src/main/AndroidManifest.xml index cac418ec93..3726bc57d7 100644 --- a/stream-video-android-core/src/main/AndroidManifest.xml +++ b/stream-video-android-core/src/main/AndroidManifest.xml @@ -76,13 +76,6 @@ - - - - - - diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt index d7cc089e4d..a3e148a546 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt @@ -1015,6 +1015,8 @@ public class Call( } suspend fun accept(): Result { + clientImpl.state.removeRingingCall() + clientImpl.state.maybeStopForegroundService() return clientImpl.accept(type, id) } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt index 1d8c8516ea..0fe0daf8eb 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt @@ -127,8 +127,11 @@ class ClientState(client: StreamVideo) { _ringingCall.value = null } - // Internal logic - private fun maybeStartForegroundService(call: Call, trigger: String) { + /** + * Start a foreground service that manages the call even when the UI is gone. + * This depends on the flag in [StreamVideoBuilder] called `runForegroundServiceForCalls` + */ + internal fun maybeStartForegroundService(call: Call, trigger: String) { if (clientImpl.runForegroundService) { val context = clientImpl.context val serviceIntent = CallService.buildStartIntent( @@ -140,7 +143,10 @@ class ClientState(client: StreamVideo) { } } - private fun maybeStopForegroundService() { + /** + * Stop the foreground service that manages the call even when the UI is gone. + */ + internal fun maybeStopForegroundService() { if (clientImpl.runForegroundService) { val context = clientImpl.context val serviceIntent = CallService.buildStopIntent(context) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/NotificationHandler.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/NotificationHandler.kt index 895fa83723..addfd5c2c4 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/NotificationHandler.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/NotificationHandler.kt @@ -38,7 +38,6 @@ public interface NotificationHandler : NotificationPermissionHandler { const val ACTION_INCOMING_CALL = "io.getstream.video.android.action.INCOMING_CALL" const val ACTION_OUTGOING_CALL = "io.getstream.video.android.action.OUTGOING_CALL" const val ACTION_ACCEPT_CALL = "io.getstream.video.android.action.ACCEPT_CALL" - const val ACTION_DISMISS_NOTIFICATION = "io.getstream.video.android.action.DISMISS_NOTIFICATION" const val ACTION_REJECT_CALL = "io.getstream.video.android.action.REJECT_CALL" const val ACTION_LEAVE_CALL = "io.getstream.video.android.action.LEAVE_CALL" const val ACTION_ONGOING_CALL = "io.getstream.video.android.action.ONGOING_CALL" @@ -47,10 +46,6 @@ public interface NotificationHandler : NotificationPermissionHandler { const val INTENT_EXTRA_NOTIFICATION_ID: String = "io.getstream.video.android.intent-extra.notification_id" - const val INTENT_EXTRA_NEXT_ACTION: String = - "io.getstream.video.android.intent-extra.next_action" - const val INTENT_EXTRA_NEXT_ACTION_BUNDLE: String = - "io.getstream.video.android.intent-extra.next_action_data" const val INCOMING_CALL_NOTIFICATION_ID = 24756 } } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/DefaultStreamIntentResolver.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/DefaultStreamIntentResolver.kt index 4cb71b8d4e..12de2ac5ba 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/DefaultStreamIntentResolver.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/DefaultStreamIntentResolver.kt @@ -24,11 +24,9 @@ import android.content.pm.ResolveInfo import io.getstream.log.taggedLogger import io.getstream.video.android.core.notifications.DefaultNotificationHandler import io.getstream.video.android.core.notifications.NotificationHandler -import io.getstream.video.android.core.notifications.NotificationHandler.Companion.ACTION_ACCEPT_CALL import io.getstream.video.android.core.notifications.NotificationHandler.Companion.ACTION_LIVE_CALL import io.getstream.video.android.core.notifications.NotificationHandler.Companion.ACTION_ONGOING_CALL import io.getstream.video.android.core.notifications.NotificationHandler.Companion.ACTION_REJECT_CALL -import io.getstream.video.android.core.notifications.NotificationHandler.Companion.INCOMING_CALL_NOTIFICATION_ID import io.getstream.video.android.core.notifications.NotificationHandler.Companion.INTENT_EXTRA_CALL_CID import io.getstream.video.android.model.StreamCallId @@ -96,7 +94,7 @@ internal class DefaultStreamIntentResolver(val context: Context) { notificationId: Int, ): PendingIntent? = searchActivityPendingIntent( - Intent(ACTION_LIVE_CALL), + Intent(NotificationHandler.ACTION_LIVE_CALL), callId, notificationId, ) @@ -109,32 +107,13 @@ internal class DefaultStreamIntentResolver(val context: Context) { */ internal fun searchAcceptCallPendingIntent( callId: StreamCallId, - ): PendingIntent? = searchDismissNotificationPendingIntent( - callId, + notificationId: Int = NotificationHandler.INCOMING_CALL_NOTIFICATION_ID, + ): PendingIntent? = searchActivityPendingIntent( - Intent(ACTION_ACCEPT_CALL), - callId, - INCOMING_CALL_NOTIFICATION_ID, - ), - ) - - /** - * Search for a broadcast that will dismiss a notification and will then proceed to call the [nextIntent]. - * - * @param callId the callID - * @param nextIntent the next action intent. - */ - internal fun searchDismissNotificationPendingIntent( - callId: StreamCallId, - nextIntent: PendingIntent? = null, - ): PendingIntent? { - val baseIntent = Intent(NotificationHandler.ACTION_DISMISS_NOTIFICATION) - baseIntent.putExtra(NotificationHandler.INTENT_EXTRA_NEXT_ACTION, nextIntent) - return searchBroadcastPendingIntent( - baseIntent, + Intent(NotificationHandler.ACTION_ACCEPT_CALL), callId, + notificationId, ) - } /** * Searches for a broadcast receiver that can consume the [ACTION_REJECT_CALL] intent to reject @@ -267,17 +246,16 @@ internal class DefaultStreamIntentResolver(val context: Context) { baseIntent: Intent, resolveInfo: ResolveInfo, callId: StreamCallId, - notificationId: Int = INCOMING_CALL_NOTIFICATION_ID, ): Intent { return Intent(baseIntent).apply { component = ComponentName( resolveInfo.activityInfo.applicationInfo.packageName, resolveInfo.activityInfo.name, ) - putExtra(INTENT_EXTRA_CALL_CID, callId) + putExtra(NotificationHandler.INTENT_EXTRA_CALL_CID, callId) putExtra( NotificationHandler.INTENT_EXTRA_NOTIFICATION_ID, - notificationId, + NotificationHandler.INCOMING_CALL_NOTIFICATION_ID, ) } } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/receivers/DismissNotificationBroadcastReceiver.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/receivers/DismissNotificationBroadcastReceiver.kt deleted file mode 100644 index fa863a425a..0000000000 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/receivers/DismissNotificationBroadcastReceiver.kt +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2014-2024 Stream.io Inc. All rights reserved. - * - * Licensed under the Stream License; - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://github.com/GetStream/stream-video-android/blob/main/LICENSE - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package io.getstream.video.android.core.notifications.internal.receivers - -import android.app.PendingIntent -import android.content.Context -import android.content.Intent -import android.os.Build -import androidx.core.app.NotificationManagerCompat -import io.getstream.log.taggedLogger -import io.getstream.video.android.core.Call -import io.getstream.video.android.core.notifications.NotificationHandler -import io.getstream.video.android.core.notifications.NotificationHandler.Companion.INTENT_EXTRA_NEXT_ACTION -import io.getstream.video.android.core.notifications.NotificationHandler.Companion.INTENT_EXTRA_NOTIFICATION_ID - -/** - * Used to dismiss a notification. Internal to stream. - */ -internal class DismissNotificationBroadcastReceiver : GenericCallActionBroadcastReceiver() { - - val logger by taggedLogger("DismissNotificationBroadcastReceiver") - override val action = NotificationHandler.ACTION_DISMISS_NOTIFICATION - - override fun onReceive(context: Context?, intent: Intent?) { - // Dismiss notification right away - val notificationId = intent?.getIntExtra(INTENT_EXTRA_NOTIFICATION_ID, 0) - if (context != null && notificationId != null) { - NotificationManagerCompat.from(context).cancel(notificationId) - } - // Proceed with processing see GenericCallActionBroadcastReceiver for details - super.onReceive(context, intent) - } - - override suspend fun onReceive(call: Call, context: Context, intent: Intent) { - val nextAction: PendingIntent? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - intent.getParcelableExtra(INTENT_EXTRA_NEXT_ACTION, PendingIntent::class.java) - } else { - intent.getParcelableExtra(INTENT_EXTRA_NEXT_ACTION) - } - if (nextAction == null) { - logger.w { "You dismissed a notification, but did not proceed further with the actions." } - } else { - // Send the pending intent - nextAction.send() - } - } -} diff --git a/stream-video-android-ui-compose/api/stream-video-android-ui-compose.api b/stream-video-android-ui-compose/api/stream-video-android-ui-compose.api index 3cde11ead0..a17726a284 100644 --- a/stream-video-android-ui-compose/api/stream-video-android-ui-compose.api +++ b/stream-video-android-ui-compose/api/stream-video-android-ui-compose.api @@ -356,8 +356,12 @@ public final class io/getstream/video/android/compose/theme/VideoThemeKt { public final class io/getstream/video/android/compose/ui/ComposableSingletons$StreamCallActivityComposeDelegateKt { public static final field INSTANCE Lio/getstream/video/android/compose/ui/ComposableSingletons$StreamCallActivityComposeDelegateKt; public static field lambda-1 Lkotlin/jvm/functions/Function2; + public static field lambda-2 Lkotlin/jvm/functions/Function2; + public static field lambda-3 Lkotlin/jvm/functions/Function2; public fun ()V public final fun getLambda-1$stream_video_android_ui_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda-2$stream_video_android_ui_compose_release ()Lkotlin/jvm/functions/Function2; + public final fun getLambda-3$stream_video_android_ui_compose_release ()Lkotlin/jvm/functions/Function2; } public class io/getstream/video/android/compose/ui/ComposeStreamCallActivity : io/getstream/video/android/ui/common/StreamCallActivity { @@ -374,8 +378,11 @@ public class io/getstream/video/android/compose/ui/StreamCallActivityComposeDele public fun DefaultCallContent (Lio/getstream/video/android/ui/common/StreamCallActivity;Lio/getstream/video/android/core/Call;Landroidx/compose/runtime/Composer;I)V public fun NoAnswerContent (Lio/getstream/video/android/ui/common/StreamCallActivity;Lio/getstream/video/android/core/Call;Landroidx/compose/runtime/Composer;I)V public fun NoPermissions (Lio/getstream/video/android/ui/common/StreamCallActivity;Ljava/util/List;Ljava/util/List;ZLandroidx/compose/runtime/Composer;II)V + public fun OnIncomingCallContent (Landroidx/compose/ui/Modifier;Lio/getstream/video/android/core/Call;ZZLkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function5;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V + public fun OnOutgoingCallContent (Landroidx/compose/ui/Modifier;Lio/getstream/video/android/core/Call;ZZLkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function5;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Landroidx/compose/runtime/Composer;I)V public fun RejectedContent (Lio/getstream/video/android/ui/common/StreamCallActivity;Lio/getstream/video/android/core/Call;Landroidx/compose/runtime/Composer;I)V public fun RootContent (Lio/getstream/video/android/ui/common/StreamCallActivity;Lio/getstream/video/android/core/Call;Landroidx/compose/runtime/Composer;I)V + public fun loadingContent (Lio/getstream/video/android/ui/common/StreamCallActivity;)V public fun setContent (Lio/getstream/video/android/ui/common/StreamCallActivity;Lio/getstream/video/android/core/Call;)V } @@ -1584,7 +1591,7 @@ public final class io/getstream/video/android/compose/ui/components/call/ringing } public final class io/getstream/video/android/compose/ui/components/call/ringing/RingingCallContentKt { - public static final fun RingingCallContent (Lio/getstream/video/android/core/Call;Landroidx/compose/ui/Modifier;ZZLkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function5;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Landroidx/compose/runtime/Composer;III)V + public static final fun RingingCallContent (Lio/getstream/video/android/core/Call;Landroidx/compose/ui/Modifier;ZZLkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function5;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function2;Lkotlin/jvm/functions/Function11;Lkotlin/jvm/functions/Function11;Landroidx/compose/runtime/Composer;III)V } public final class io/getstream/video/android/compose/ui/components/call/ringing/incomingcall/ComposableSingletons$IncomingCallContentKt { diff --git a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/StreamCallActivityComposeDelegate.kt b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/StreamCallActivityComposeDelegate.kt index c1516d7090..28c2316bb4 100644 --- a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/StreamCallActivityComposeDelegate.kt +++ b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/StreamCallActivityComposeDelegate.kt @@ -22,17 +22,24 @@ import android.net.Uri import android.provider.Settings import androidx.activity.compose.setContent import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxScope +import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size +import androidx.compose.material.CircularProgressIndicator import androidx.compose.material.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.lifecycle.compose.collectAsStateWithLifecycle @@ -46,12 +53,17 @@ import io.getstream.video.android.compose.ui.components.base.styling.StreamDialo import io.getstream.video.android.compose.ui.components.base.styling.StyleSize import io.getstream.video.android.compose.ui.components.call.activecall.CallContent import io.getstream.video.android.compose.ui.components.call.ringing.RingingCallContent +import io.getstream.video.android.compose.ui.components.call.ringing.incomingcall.IncomingCallContent +import io.getstream.video.android.compose.ui.components.call.ringing.outgoingcall.OutgoingCallContent import io.getstream.video.android.core.Call +import io.getstream.video.android.core.MemberState import io.getstream.video.android.core.RealtimeConnection +import io.getstream.video.android.core.call.state.CallAction import io.getstream.video.android.core.call.state.DeclineCall import io.getstream.video.android.core.call.state.LeaveCall import io.getstream.video.android.ui.common.StreamActivityUiDelegate import io.getstream.video.android.ui.common.StreamCallActivity +import io.getstream.video.android.ui.common.util.StreamCallActivityDelicateApi /** * A default implementation of the compose delegate for the call activity. @@ -68,6 +80,26 @@ public open class StreamCallActivityComposeDelegate : StreamActivityUiDelegate Unit)?, + detailsContent: @Composable ( + ColumnScope.( + participants: List, + topPadding: Dp, + ) -> Unit + )?, + controlsContent: @Composable (BoxScope.() -> Unit)?, + onBackPressed: () -> Unit, + onCallAction: (CallAction) -> Unit, + -> + OnOutgoingCallContent( + call = call, + isVideoType = isVideoType, + modifier = modifier, + isShowingHeader = isShowingHeader, + headerContent = headerContent, + detailsContent = detailsContent, + controlsContent = controlsContent, + onBackPressed = onBackPressed, + onCallAction = onCallAction, + ) + }, + onIncomingContent = { modifier: Modifier, + call: Call, + isVideoType: Boolean, isShowingHeader: Boolean, + headerContent: @Composable (ColumnScope.() -> Unit)?, + detailsContent: @Composable ( + ColumnScope.( + participants: List, + topPadding: Dp, + ) -> Unit + )?, + controlsContent: @Composable (BoxScope.() -> Unit)?, + onBackPressed: () -> Unit, + onCallAction: (CallAction) -> Unit, + -> + OnIncomingCallContent( + call = call, + isVideoType = isVideoType, + modifier = modifier, + isShowingHeader = isShowingHeader, + headerContent = headerContent, + detailsContent = detailsContent, + controlsContent = controlsContent, + onBackPressed = onBackPressed, + onCallAction = onCallAction, + ) + }, onAcceptedContent = { if (isVideoCall(call)) { DefaultCallContent(call = call) @@ -154,6 +240,66 @@ public open class StreamCallActivityComposeDelegate : StreamActivityUiDelegate Unit)?, + detailsContent: ( + @Composable ColumnScope.( + participants: List, + topPadding: Dp, + ) -> Unit + )?, + controlsContent: (@Composable BoxScope.() -> Unit)?, + onBackPressed: () -> Unit, + onCallAction: (CallAction) -> Unit, + ) { + OutgoingCallContent( + call = call, + isVideoType = isVideoType, + modifier = modifier, + isShowingHeader = isShowingHeader, + headerContent = headerContent, + detailsContent = detailsContent, + controlsContent = controlsContent, + onBackPressed = onBackPressed, + onCallAction = onCallAction, + ) + } + + @Composable + public open fun OnIncomingCallContent( + modifier: Modifier, + call: Call, + isVideoType: Boolean, + isShowingHeader: Boolean, + headerContent: (@Composable ColumnScope.() -> Unit)?, + detailsContent: ( + @Composable ColumnScope.( + participants: List, + topPadding: Dp, + ) -> Unit + )?, + controlsContent: (@Composable BoxScope.() -> Unit)?, + onBackPressed: () -> Unit, + onCallAction: (CallAction) -> Unit, + ) { + IncomingCallContent( + call = call, + isVideoType = isVideoType, + modifier = modifier, + isShowingHeader = isShowingHeader, + headerContent = headerContent, + detailsContent = detailsContent, + controlsContent = controlsContent, + onBackPressed = onBackPressed, + onCallAction = onCallAction, + ) + } + /** * Content when the call is not answered. * @@ -193,7 +339,8 @@ public open class StreamCallActivityComposeDelegate : StreamActivityUiDelegate Unit, onRejectedContent: @Composable () -> Unit = {}, onNoAnswerContent: @Composable () -> Unit = {}, + onIncomingContent: ( + @Composable ( + modifier: Modifier, + call: Call, + isVideoType: Boolean, + isShowingHeader: Boolean, + headerContent: (@Composable ColumnScope.() -> Unit)?, + detailsContent: ( + @Composable ColumnScope.( + participants: List, + topPadding: Dp, + ) -> Unit + )?, + controlsContent: (@Composable BoxScope.() -> Unit)?, + onBackPressed: () -> Unit, + onCallAction: (CallAction) -> Unit, + ) -> Unit + )? = null, + onOutgoingContent: ( + @Composable ( + modifier: Modifier, + call: Call, + isVideoType: Boolean, + isShowingHeader: Boolean, + headerContent: (@Composable ColumnScope.() -> Unit)?, + detailsContent: ( + @Composable ColumnScope.( + participants: List, + topPadding: Dp, + ) -> Unit + )?, + controlsContent: (@Composable BoxScope.() -> Unit)?, + onBackPressed: () -> Unit, + onCallAction: (CallAction) -> Unit, + ) -> Unit + )? = null, ) { val ringingState by call.state.ringingState.collectAsStateWithLifecycle() when (ringingState) { is RingingState.Incoming -> { - IncomingCallContent( + onIncomingContent?.invoke( + modifier, + call, + isVideoType, + isShowingHeader, + headerContent, + detailsContent, + controlsContent, + onBackPressed, + onCallAction, + ) ?: IncomingCallContent( call = call, isVideoType = isVideoType, modifier = modifier, @@ -93,7 +139,17 @@ public fun RingingCallContent( } is RingingState.Outgoing -> { - OutgoingCallContent( + onOutgoingContent?.invoke( + modifier, + call, + isVideoType, + isShowingHeader, + headerContent, + detailsContent, + controlsContent, + onBackPressed, + onCallAction, + ) ?: OutgoingCallContent( call = call, isVideoType = isVideoType, modifier = modifier, diff --git a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/ringing/outgoingcall/OutgoingCallContent.kt b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/ringing/outgoingcall/OutgoingCallContent.kt index b50a7b04fe..ced2713ad8 100644 --- a/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/ringing/outgoingcall/OutgoingCallContent.kt +++ b/stream-video-android-ui-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/ringing/outgoingcall/OutgoingCallContent.kt @@ -156,6 +156,7 @@ public fun OutgoingCallContent( modifier = Modifier .align(Alignment.BottomCenter) .padding(bottom = VideoTheme.dimens.componentHeightM), + isVideoCall = isVideoType, isCameraEnabled = isCameraEnabled, isMicrophoneEnabled = isMicrophoneEnabled, onCallAction = onCallAction, diff --git a/stream-video-android-ui-core/api/stream-video-android-ui-core.api b/stream-video-android-ui-core/api/stream-video-android-ui-core.api index 940e34bfbc..62566f372d 100644 --- a/stream-video-android-ui-core/api/stream-video-android-ui-core.api +++ b/stream-video-android-ui-core/api/stream-video-android-ui-core.api @@ -20,6 +20,7 @@ public final class io/getstream/video/android/ui/common/AbstractCallActivity$Com } public abstract interface class io/getstream/video/android/ui/common/StreamActivityUiDelegate { + public abstract fun loadingContent (Lio/getstream/video/android/ui/common/StreamCallActivity;)V public abstract fun setContent (Lio/getstream/video/android/ui/common/StreamCallActivity;Lio/getstream/video/android/core/Call;)V } diff --git a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamActivityUiDelegate.kt b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamActivityUiDelegate.kt index fb42d7681a..bb89753011 100644 --- a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamActivityUiDelegate.kt +++ b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamActivityUiDelegate.kt @@ -20,6 +20,12 @@ import io.getstream.video.android.core.Call public interface StreamActivityUiDelegate { + /** + * Called when the [setContent] cannot yet be invoked (missing [Call] for e.g.). + * Used to show some UI in the activity if the call is not yet loaded. + */ + public fun loadingContent(activity: T) + /** * Set the content for the activity, * diff --git a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt index f2680fb702..97b29921f6 100644 --- a/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt +++ b/stream-video-android-ui-core/src/main/kotlin/io/getstream/video/android/ui/common/StreamCallActivity.kt @@ -121,6 +121,8 @@ public abstract class StreamCallActivity : ComponentActivity() { // Platform restriction public final override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + val uiDelegate = uiDelegate() + uiDelegate.loadingContent(this) onPreCreate(savedInstanceState, null) logger.d { "Entered [onCreate(Bundle?)" } initializeCallOrFail( @@ -145,6 +147,8 @@ public abstract class StreamCallActivity : ComponentActivity() { persistentState: PersistableBundle?, ) { super.onCreate(savedInstanceState) + val uiDelegate = uiDelegate() + uiDelegate.loadingContent(this) onPreCreate(savedInstanceState, persistentState) logger.d { "Entered [onCreate(Bundle, PersistableBundle?)" } initializeCallOrFail(