Skip to content

Commit bd3ec59

Browse files
Spotlight view (#892)
Add spotlight feature. Minor design update
1 parent cdd61d0 commit bd3ec59

File tree

25 files changed

+1296
-135
lines changed

25 files changed

+1296
-135
lines changed

docusaurus/docs/Android/04-ui-components/05-participants/02-participants-grid.mdx

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,47 @@
1-
# ParticipantsGrid
1+
# ParticipantsLayout
22

3-
The `ParticipantsGrid` component is one of our most versatile and complex UI components, designed to render a list of participants in a call. It handles different UI layouts based on the number of participants and different screen orientations. Additionally, it can also render screen sharing content when there is an active session.
3+
The `ParticipantsLayout` component is one of our most versatile and complex UI components, designed to render a list of participants in a call. It handles different UI layouts based on the number of participants and different screen orientations. Additionally, it can also render screen sharing content when there is an active session.
44

55
Before jumping into how to use the component and how to customize it, let's review what some of these features mean.
66

7-
What you can do with the `ParticipantsGrid` are:
7+
What you can do with the `ParticipantsLayout` are:
88

9-
- Displays a grid list of the remote/local participants.
10-
- Supports landscape configuration.
11-
- Renders [Screensharing](../04-call/05-screen-share-content.mdx).
9+
- Displays a list of the remote/local participants.
10+
- There are two available layouts, Grid and [Spotlight](04-participants-spotlight.mdx)
11+
- There is also a dynamic option where the layout will switch automatically based on any pinned participants.
12+
- All the layout variants are supported in portrait and in landscape mode
13+
- Renders [Screensharing](../04-call/05-screen-share-content.mdx) on demand, regardless of selected layout.
1214

1315
### Flexible Layout
1416

15-
The `ParticipantsGrid` changes the UI layout based on the number of participants. In calls with fewer than four people, the local participant video is rendered in a floating item, using the [FloatingParticipantVideo](03-floating-participant-video.mdx). In calls with four or more people, it's rendered with other participants in a grid.
17+
The `ParticipantsLayout` changes the UI layout based on the number of participants. In calls with fewer than four people, the local participant video is rendered in a floating item, using the [FloatingParticipantVideo](03-floating-participant-video.mdx). In calls with six or more people, it's rendered with other participants in a grid.
1618

1719
Additionally, the participants are rendered in the following way:
1820

19-
* **One participant**: Rendered as the only single item in the "grid", taking up the full component space.
21+
* **One participant**: Rendered as the only single item in the layout, taking up the full component space.
2022
* **Two participants** (1 remote + local): The remote participant is rendered within the full component space while the local participant is a floating item.
21-
* **Three participants** (2 remote + local): Remote participants are in a vertical split-screen, while the local participant is a floating item.
22-
* **Four or more participants**: (4 or more remote): Participants are rendered as a grid of items, in a paginated way. Up to 6 participants per page, with the sorted participant.
23+
* **Three to four participants** (2-3 remote + local): Remote participants are in a vertical split-screen, while the local participant is a floating item.
24+
* **Five or more** (4 remote + local): Participants are rendered as a grid of items, in a paginated way. Up to 6 participants per page, with the sorted participant.
2325

2426
Sorted participants gives you the list of participants sorted by:
25-
2627
* anyone who is pinned
27-
* dominant speaker
2828
* if you are screensharing
29-
* last speaking at
29+
30+
If the participants are not visible on the screen they are also sorted by:
31+
* is dominant speaker
32+
* has video enabled
33+
* has audio enabled
3034
* all other video participants by when they joined
31-
* audio only participants by when they joined
3235

3336
### Orientation
3437

3538
The component handles both Landscape and Portrait orientations by rendering different UI. In Portrait mode, the video layout is optimized for standard mobile device rendering, while the landscape mode offers more screen real estate to render video by adding a transparent app bar and pushing the call controls to the side. This is helpful when you need to pay attention to details of the video content of other participants.
3639

3740
Additionally, both of these orientations work for screen sharing and adjust the UI accordingly.
3841

39-
| Portrait ParticipantsGrid | Landscape ParticipantsGrid |
42+
| Portrait ParticipantsLayout | Landscape ParticipantsLayout |
4043
| ------- | ------------------------------------------------------------ |
41-
| ![Portrait ParticipantsGrid](../../assets/compose_single_participant.png) | ![Landscape ParticipantsGrid](../../assets/compose_call_landscape.png) |
44+
| ![Portrait ParticipantsLayout](../../assets/compose_single_participant.png) | ![Landscape ParticipantsLayout](../../assets/compose_call_landscape.png) |
4245

4346
### Screen Sharing
4447

@@ -50,19 +53,19 @@ Users can then focus on the shared content more or choose to enter the full scre
5053
| ------- | ------------------------------------------------------------ |
5154
| ![Portrait Screensharing](../../assets/compose_screensharing.png) | ![Landscape Screensharing](../../assets/compose_screensharing_landscape.png) |
5255

53-
Now that you've learned a lot about the `ParticipantsGrid` internal works, let's see how to use the component to add it to your UI.
56+
Now that you've learned a lot about the `ParticipantsLayout` internal works, let's see how to use the component to add it to your UI.
5457

5558
## Usage
5659

5760
To use the component in your UI, once you have the required state, you can render `CallParticipants` like so:
5861

5962
```kotlin
6063
@Composable
61-
public fun MyParticipantsGridScreen() {
64+
public fun MyParticipantsLayoutScreen() {
6265
Scaffold(
6366
topBar = { /* Custom top bar */ },
6467
) { padding ->
65-
ParticipantsGrid(
68+
ParticipantsLayout(
6669
modifier = Modifier.fillMaxSize(),
6770
call = call
6871
)
@@ -107,7 +110,7 @@ In terms of UI customization, you can very easily customize each participant vid
107110

108111
```kotlin
109112
@Composable
110-
public fun ParticipantsGrid(
113+
public fun ParticipantsLayout(
111114
modifier: Modifier = Modifier.fillMaxSize(),
112115
call = call,
113116
style = RegularVideoRendererStyle(
@@ -125,7 +128,7 @@ With these options, you have more than enough space to customize how the compone
125128
You can also custom the entire video renderer by implementing your own video renderer:
126129

127130
```kotlin
128-
ParticipantsGrid(
131+
ParticipantsLayout(
129132
call = call,
130133
modifier = Modifier.fillMaxSize(),
131134
videoRenderer = { modifier, call, participant, style ->
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# ParticipantsSpotlight
2+
3+
The `ParticipantsSpotlight` is a Composable component that allows you to highlight one participant and this one participant takes much of the screen, while the rest are rendered
4+
either as a horizontal or vertical list depending on orientation.
5+
6+
Let's see how to use the `ParticipantsSpotlight`.
7+
8+
## Usage
9+
10+
To use the `ParticipantsSpotlight` component in your app you can use it direcyly as a component or you can configure the [ParticipantsLayout](02-participants-grid.mdx) to display the spotlight.
11+
12+
### Use it directly
13+
```kotlin
14+
ParticipantsSpotlight(call = call)
15+
```
16+
The only mandatory parameter is `call` which represents the call for which the participants are being displayed.
17+
18+
### Use it via [ParticipantsLayout](02-participants-grid.mdx)
19+
20+
If you are using the `ParticipantsLayout` you can use an enum value `LayoutType` with one of three options.
21+
22+
Those are:
23+
```kotlin
24+
//Automatically choose between Grid and Spotlight based on pinned participants and dominant speaker.
25+
DYNAMIC
26+
27+
//Force a spotlight view, showing the dominant speaker or the first speaker in the list.
28+
SPOTLIGHT
29+
30+
//Always show a grid layout, regardless of pinned participants.
31+
GRID
32+
```
33+
34+
Here is how it looks in action:
35+
```kotlin
36+
ParticipantsLayout(
37+
layoutType = LayoutType.SPOTLIGHT,
38+
call = call
39+
)
40+
```
41+
42+
The [ParticipantsLayout](02-participants-grid.mdx) internally displays the `ParticipantSpotlight` in two cases.
43+
1. You have set the `layoutType` to `LayoutType.SPOTLIGHT` in which case a participant is always spotlighted. The participant shown in the spotlight is chosen based on the following order:
44+
1. is pinned
45+
2. is dominantSpeaker
46+
3. is first in the participants list
47+
2. You have set the `LayoutType` to `LayoutType.DYNAMIC` in which case if there is a "pinned" participant, the spotlight view will be chosen in favor of grid.
48+
49+
*Note*: `ParticipantLayout` will always prioritize screensharing regardless of the `LayoutType` if there is a [screensharing session](../04-call/05-screen-share-content.mdx).s
50+
51+
52+
Using this component, you'll likely see something similar to the following UI:
53+
54+
![Spotlight portrait](../../assets/spotlight_portrait.png)
55+
56+
![Spotlight landscape](../../assets/spotlight_landscape.png)
57+
58+
59+
Let's see how to customize this component.
60+
61+
## Customization
62+
63+
This is a very simple component so it doesn't have replaceable slots, but it still offers ways to customize its appearance.
64+
65+
- `modifier`: Modifier for styling.
66+
- `isZoomable`: Decide if this spotlight video renderer is zoomable or not.
67+
- `style`: Defined properties for styling a single video call track.
68+
- `videoRenderer`: A single video renderer renders each individual participant.
69+
70+
If you're looking for guides on how to override and customize this UI, we have various [UI Cookbook](../../05-ui-cookbook/01-overview.mdx) recipes for you and we cover a portion of customization within the [Video Android SDK Tutorial](../../02-tutorials/01-video-calling.mdx).
189 KB
Loading
56.6 KB
Loading

dogfooding/src/main/kotlin/io/getstream/video/android/ui/call/CallScreen.kt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,15 @@ import io.getstream.video.android.compose.ui.components.call.activecall.CallCont
5454
import io.getstream.video.android.compose.ui.components.call.controls.ControlActions
5555
import io.getstream.video.android.compose.ui.components.call.controls.actions.CancelCallAction
5656
import io.getstream.video.android.compose.ui.components.call.controls.actions.ChatDialogAction
57+
import io.getstream.video.android.compose.ui.components.call.controls.actions.DefaultOnCallActionHandler
5758
import io.getstream.video.android.compose.ui.components.call.controls.actions.FlipCameraAction
5859
import io.getstream.video.android.compose.ui.components.call.controls.actions.SettingsAction
5960
import io.getstream.video.android.compose.ui.components.call.controls.actions.ToggleCameraAction
6061
import io.getstream.video.android.compose.ui.components.call.controls.actions.ToggleMicrophoneAction
62+
import io.getstream.video.android.compose.ui.components.call.renderer.LayoutType
6163
import io.getstream.video.android.core.Call
6264
import io.getstream.video.android.core.RealtimeConnection
65+
import io.getstream.video.android.core.call.state.ChooseLayout
6366
import io.getstream.video.android.mock.StreamMockUtils
6467
import io.getstream.video.android.mock.mockCall
6568
import kotlinx.coroutines.delay
@@ -77,8 +80,10 @@ fun CallScreen(
7780
val isMicrophoneEnabled by call.microphone.isEnabled.collectAsState()
7881
val speakingWhileMuted by call.state.speakingWhileMuted.collectAsState()
7982
var isShowingSettingMenu by remember { mutableStateOf(false) }
83+
var isShowingLayoutChooseMenu by remember { mutableStateOf(false) }
8084
var isShowingReactionsMenu by remember { mutableStateOf(false) }
8185
var isShowingAvailableDeviceMenu by remember { mutableStateOf(false) }
86+
var layout by remember { mutableStateOf(LayoutType.DYNAMIC) }
8287
var unreadCount by remember { mutableIntStateOf(0) }
8388
val chatState = rememberModalBottomSheetState(
8489
initialValue = ModalBottomSheetValue.Hidden,
@@ -113,8 +118,18 @@ fun CallScreen(
113118
CallContent(
114119
modifier = Modifier.background(color = VideoTheme.colors.appBackground),
115120
call = call,
121+
layout = layout,
116122
enableInPictureInPicture = true,
117123
enableDiagnostics = BuildConfig.DEBUG,
124+
onCallAction = {
125+
when (it) {
126+
ChooseLayout -> isShowingLayoutChooseMenu = true
127+
else -> DefaultOnCallActionHandler.onCallAction(
128+
call,
129+
it,
130+
)
131+
}
132+
},
118133
onBackPressed = {
119134
if (chatState.currentValue == ModalBottomSheetValue.Expanded) {
120135
scope.launch { chatState.hide() }
@@ -263,6 +278,17 @@ fun CallScreen(
263278
)
264279
}
265280

281+
if (isShowingLayoutChooseMenu) {
282+
LayoutChooser(
283+
onLayoutChoice = {
284+
layout = it
285+
isShowingLayoutChooseMenu = false
286+
},
287+
current = layout,
288+
onDismiss = { isShowingLayoutChooseMenu = false },
289+
)
290+
}
291+
266292
if (isShowingAvailableDeviceMenu) {
267293
AvailableDeviceMenu(
268294
call = call,

0 commit comments

Comments
 (0)