Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements in StreamCallActivity and demo-app #1184

Merged
merged 3 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import io.getstream.chat.android.ui.common.state.messages.list.MessageItemState
import io.getstream.video.android.BuildConfig
import io.getstream.video.android.R
import io.getstream.video.android.compose.pip.rememberIsInPipMode
import io.getstream.video.android.compose.theme.VideoTheme
import io.getstream.video.android.compose.ui.components.base.StreamBadgeBox
import io.getstream.video.android.compose.ui.components.base.StreamDialogPositiveNegative
Expand Down Expand Up @@ -411,27 +412,32 @@ fun CallScreen(
},
)

if (participantsSize.size == 1 && !chatState.isVisible && orientation == Configuration.ORIENTATION_PORTRAIT) {
val context = LocalContext.current
val clipboardManager = remember(context) {
context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
}
val env = AppConfig.currentEnvironment.collectAsStateWithLifecycle()
Popup(
alignment = Alignment.BottomCenter,
offset = IntOffset(
0,
-(VideoTheme.dimens.componentHeightL + VideoTheme.dimens.spacingS).toPx()
.toInt(),
),
val isPictureInPictureMode = rememberIsInPipMode()
if (!isPictureInPictureMode) {
if (participantsSize.size == 1 &&
!chatState.isVisible &&
orientation == Configuration.ORIENTATION_PORTRAIT
) {
ShareCallWithOthers(
modifier = Modifier.fillMaxWidth(),
call = call,
clipboardManager = clipboardManager,
env = env,
context = context,
)
val clipboardManager = remember(context) {
context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
}
val env = AppConfig.currentEnvironment.collectAsStateWithLifecycle()
Popup(
alignment = Alignment.BottomCenter,
offset = IntOffset(
0,
-(VideoTheme.dimens.componentHeightL + VideoTheme.dimens.spacingS).toPx()
.toInt(),
),
) {
ShareCallWithOthers(
modifier = Modifier.fillMaxWidth(),
call = call,
clipboardManager = clipboardManager,
env = env,
context = context,
)
}
}
}

Expand All @@ -440,7 +446,13 @@ fun CallScreen(
}

if (showingLandscapeControls && orientation == Configuration.ORIENTATION_LANDSCAPE) {
LandscapeControls(call) {
LandscapeControls(call, onChat = {
showingLandscapeControls = false
scope.launch { chatState.show() }
}, onSettings = {
showingLandscapeControls = false
isShowingSettingMenu = true
}) {
showingLandscapeControls = !showingLandscapeControls
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.CallEnd
import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
Expand All @@ -38,6 +41,7 @@ import androidx.compose.ui.window.Popup
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import io.getstream.video.android.compose.theme.VideoTheme
import io.getstream.video.android.compose.ui.components.base.StreamButton
import io.getstream.video.android.compose.ui.components.call.controls.actions.ChatDialogAction
import io.getstream.video.android.compose.ui.components.call.controls.actions.FlipCameraAction
import io.getstream.video.android.compose.ui.components.call.controls.actions.ToggleCameraAction
import io.getstream.video.android.compose.ui.components.call.controls.actions.ToggleMicrophoneAction
Expand All @@ -48,7 +52,12 @@ import io.getstream.video.android.mock.previewCall
import io.getstream.video.android.tooling.extensions.toPx

@Composable
fun LandscapeControls(call: Call, onDismiss: () -> Unit) {
fun LandscapeControls(
call: Call,
onChat: () -> Unit,
onSettings: () -> Unit,
onDismiss: () -> Unit,
) {
val isCameraEnabled by call.camera.isEnabled.collectAsStateWithLifecycle()
val isMicrophoneEnabled by call.microphone.isEnabled.collectAsStateWithLifecycle()
val toggleCamera = {
Expand Down Expand Up @@ -76,6 +85,8 @@ fun LandscapeControls(call: Call, onDismiss: () -> Unit) {
camera = toggleCamera,
mic = toggleMicrophone,
onClick = onClick,
onChat = onChat,
onSettings = onSettings,
) {
onDismiss()
}
Expand All @@ -87,6 +98,8 @@ fun LandscapeControlsContent(
isCameraEnabled: Boolean,
isMicEnabled: Boolean,
call: Call,
onChat: () -> Unit,
onSettings: () -> Unit,
camera: () -> Unit,
mic: () -> Unit,
onClick: () -> Unit,
Expand All @@ -107,21 +120,36 @@ fun LandscapeControlsContent(
ReactionsMenu(call = call, reactionMapper = ReactionMapper.defaultReactionMapper()) {
onDismiss()
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
) {
ToggleCameraAction(isCameraEnabled = isCameraEnabled) {
camera()
}
ToggleMicrophoneAction(isMicrophoneEnabled = isMicEnabled) {
mic()
}
FlipCameraAction {
call.camera.flip()
}
Column {
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
) {
ToggleCameraAction(isCameraEnabled = isCameraEnabled) {
camera()
}
ToggleMicrophoneAction(isMicrophoneEnabled = isMicEnabled) {
mic()
}
FlipCameraAction {
call.camera.flip()
}

ChatDialogAction(
messageCount = 0,
onCallAction = { onChat() },
)
}
Spacer(modifier = Modifier.height(16.dp))
StreamButton(
modifier = Modifier.fillMaxWidth(),
style = VideoTheme.styles.buttonStyles.primaryIconButtonStyle(),
icon = Icons.Default.Settings,
text = "Settings",
onClick = onSettings,
)
StreamButton(
modifier = Modifier.fillMaxWidth(),
style = VideoTheme.styles.buttonStyles.alertButtonStyle(),
icon = Icons.Default.CallEnd,
text = "Leave call",
Expand All @@ -144,6 +172,8 @@ fun LandscapeControlsPreview() {
{},
{},
{},
{},
{},
) {
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ public abstract interface class io/getstream/video/android/compose/permission/Vi
public abstract fun launchPermissionRequest ()V
}

public final class io/getstream/video/android/compose/pip/PictureInPictureKt {
public static final fun isInPictureInPictureMode (Landroid/content/Context;)Z
public static final fun rememberIsInPipMode (Landroidx/compose/runtime/Composer;I)Z
}

public abstract interface class io/getstream/video/android/compose/state/ui/internal/CallParticipantInfoMode {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ import android.content.pm.ActivityInfo
import android.content.pm.PackageManager
import android.os.Build
import android.util.Rational
import androidx.activity.ComponentActivity
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.core.app.PictureInPictureModeChangedInfo
import androidx.core.util.Consumer
import io.getstream.video.android.core.Call

@Suppress("DEPRECATION")
Expand Down Expand Up @@ -58,12 +68,48 @@ internal fun enterPictureInPicture(context: Context, call: Call) {
}
}

internal val Context.isInPictureInPictureMode: Boolean
/**
* Remember if the current activity is in Picture-in-Picture mode.
* To be used in compose to decide weather the current mode is PiP or not.
*/
@Composable
public fun rememberIsInPipMode(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val activity = LocalContext.current.findComponentActivity()
var pipMode by remember { mutableStateOf(activity?.isInPictureInPictureMode) }
DisposableEffect(activity) {
val observer = Consumer<PictureInPictureModeChangedInfo> { info ->
pipMode = info.isInPictureInPictureMode
}
activity?.addOnPictureInPictureModeChangedListener(
observer,
)
onDispose { activity?.removeOnPictureInPictureModeChangedListener(observer) }
}
return pipMode ?: false
} else {
return false
}
}

/**
* Used in other parts of the app to check if the current context is in Picture-in-Picture mode.
*/
public val Context.isInPictureInPictureMode: Boolean
get() {
val currentActivity = findActivity()
return currentActivity?.isInPictureInPictureMode == true
}

internal fun Context.findComponentActivity(): ComponentActivity? {
var context = this
while (context is ContextWrapper) {
if (context is ComponentActivity) return context
context = context.baseContext
}
return null
}

internal fun Context.findActivity(): Activity? {
var context = this
while (context is ContextWrapper) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import io.getstream.video.android.compose.lifecycle.MediaPiPLifecycle
import io.getstream.video.android.compose.permission.VideoPermissionsState
import io.getstream.video.android.compose.permission.rememberMicrophonePermissionState
import io.getstream.video.android.compose.pip.enterPictureInPicture
import io.getstream.video.android.compose.pip.isInPictureInPictureMode
import io.getstream.video.android.compose.pip.rememberIsInPipMode
import io.getstream.video.android.compose.theme.VideoTheme
import io.getstream.video.android.core.Call
import io.getstream.video.android.core.ParticipantState
Expand Down Expand Up @@ -122,7 +122,7 @@ public fun AudioRoomContent(
) {
val context = LocalContext.current
val orientation = LocalConfiguration.current.orientation
val isInPictureInPicture = context.isInPictureInPictureMode
val isInPictureInPicture = rememberIsInPipMode()

DefaultPermissionHandler(videoPermission = permissions)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import io.getstream.video.android.compose.lifecycle.MediaPiPLifecycle
import io.getstream.video.android.compose.permission.VideoPermissionsState
import io.getstream.video.android.compose.permission.rememberCallPermissionsState
import io.getstream.video.android.compose.pip.enterPictureInPicture
import io.getstream.video.android.compose.pip.isInPictureInPictureMode
import io.getstream.video.android.compose.pip.rememberIsInPipMode
import io.getstream.video.android.compose.theme.VideoTheme
import io.getstream.video.android.compose.ui.components.call.CallAppBar
import io.getstream.video.android.compose.ui.components.call.activecall.internal.DefaultPermissionHandler
Expand Down Expand Up @@ -151,7 +151,7 @@ public fun CallContent(
) {
val context = LocalContext.current
val orientation = LocalConfiguration.current.orientation
val isInPictureInPicture = context.isInPictureInPictureMode
val isInPictureInPicture = rememberIsInPipMode()

DefaultPermissionHandler(videoPermission = permissions)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,17 @@ public final class io/getstream/video/android/ui/common/StreamCallActivity$Compa

public final class io/getstream/video/android/ui/common/StreamCallActivityConfiguration {
public fun <init> ()V
public fun <init> (ZZZLandroid/os/Bundle;)V
public synthetic fun <init> (ZZZLandroid/os/Bundle;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (ZZZZLandroid/os/Bundle;)V
public synthetic fun <init> (ZZZZLandroid/os/Bundle;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Z
public final fun component2 ()Z
public final fun component3 ()Z
public final fun component4 ()Landroid/os/Bundle;
public final fun copy (ZZZLandroid/os/Bundle;)Lio/getstream/video/android/ui/common/StreamCallActivityConfiguration;
public static synthetic fun copy$default (Lio/getstream/video/android/ui/common/StreamCallActivityConfiguration;ZZZLandroid/os/Bundle;ILjava/lang/Object;)Lio/getstream/video/android/ui/common/StreamCallActivityConfiguration;
public final fun component4 ()Z
public final fun component5 ()Landroid/os/Bundle;
public final fun copy (ZZZZLandroid/os/Bundle;)Lio/getstream/video/android/ui/common/StreamCallActivityConfiguration;
public static synthetic fun copy$default (Lio/getstream/video/android/ui/common/StreamCallActivityConfiguration;ZZZZLandroid/os/Bundle;ILjava/lang/Object;)Lio/getstream/video/android/ui/common/StreamCallActivityConfiguration;
public fun equals (Ljava/lang/Object;)Z
public final fun getCanKeepScreenOn ()Z
public final fun getCanSkiPermissionRationale ()Z
public final fun getCloseScreenOnCallEnded ()Z
public final fun getCloseScreenOnError ()Z
Expand Down
Loading
Loading