From b26b410058edf52936b1215b3778d999e9549853 Mon Sep 17 00:00:00 2001 From: Daniel Novak Date: Mon, 25 Sep 2023 13:25:11 +0200 Subject: [PATCH] Refactor user fields in ParticipantInfo + Add custom data docs --- README.md | 2 +- .../Android/06-advanced/11-custom-data.mdx | 31 +++++++++++++++++ .../video/android/ui/join/CallJoinScreen.kt | 8 ++--- .../video/android/ui/lobby/CallLobbyScreen.kt | 3 +- .../api/stream-video-android-compose.api | 4 +-- .../ui/components/audio/ParticipantAudio.kt | 9 +++-- .../ui/components/avatar/UserAvatar.kt | 17 +++++++--- .../components/avatar/UserAvatarBackground.kt | 13 ++++--- .../ui/components/call/lobby/CallLobby.kt | 12 +++---- .../call/renderer/ParticipantVideo.kt | 10 +++--- .../participants/CallParticipantsInfoMenu.kt | 4 +-- .../internal/CallParticipantsList.kt | 7 ++-- .../participants/internal/InviteUserList.kt | 30 ++++++++-------- .../internal/ParticipantAvatars.kt | 9 +++-- .../video/android/compose/AvatarTest.kt | 7 +++- .../compose/ParticipantsPortraitTest.kt | 2 +- .../api/stream-video-android-core.api | 18 +++++----- .../io/getstream/video/android/core/Call.kt | 11 ++++-- .../getstream/video/android/core/CallState.kt | 5 ++- .../video/android/core/ParticipantState.kt | 34 ++++++++----------- .../video/android/core/call/RtcSession.kt | 6 ++-- .../android/core/call/state/CallAction.kt | 4 +-- .../android/core/socket/CoordinatorSocket.kt | 1 + .../video/android/core/utils/DomainUtils.kt | 16 --------- .../video/android/core/CallStateTest.kt | 12 +++---- .../getstream/video/android/core/EventTest.kt | 4 +-- .../video/android/mock/StreamMockUtils.kt | 4 +-- .../api/stream-video-android-xml.api | 2 +- .../android/xml/widget/avatar/AvatarView.kt | 6 ++-- .../widget/participant/CallParticipantView.kt | 10 +++--- 30 files changed, 171 insertions(+), 130 deletions(-) create mode 100644 docusaurus/docs/Android/06-advanced/11-custom-data.mdx diff --git a/README.md b/README.md index e9da92fb36..e7ea91a887 100644 --- a/README.md +++ b/README.md @@ -128,12 +128,12 @@ Video roadmap and changelog is available [here](https://github.com/GetStream/pro - [X] Implement Chat overlay for Dogfooding (Jaewoong) - [X] Migrate Stream Chat SDK v6 stable (Jaewoong) - [X] Add Dogfooding instructions + directs Google Play (Jaewoong) +- [X] Support participant.custom field which was previously ignored. ParticipantState line 216 (Daniel) - [ ] Default livestream player UI + docs (Jaewoong/ Daniel) - [ ] Reaction dialog API for Compose (Jaewoong) - [ ] Android SDK development.md cleanup (Daniel) - [ ] Upgrade to more recent versions of webrtc (Kanat) - [ ] Review foreground service vs backend for audio rooms etc. (Daniel) -- [ ] Support participant.custom field which was previously ignored. ParticipantState line 216 (Daniel) - [ ] Logging is too verbose (rtc is very noisy), clean it up to focus on the essential for info and higher (Daniel) ### 0.5.0 milestone diff --git a/docusaurus/docs/Android/06-advanced/11-custom-data.mdx b/docusaurus/docs/Android/06-advanced/11-custom-data.mdx new file mode 100644 index 0000000000..389770b113 --- /dev/null +++ b/docusaurus/docs/Android/06-advanced/11-custom-data.mdx @@ -0,0 +1,31 @@ +--- +title: Custom Data +description: How can you use custom data in your applications? +--- + +Custom data is additional information that can be added to the default data of Stream. It is a dictionary of key-value pairs that can be attached to users, events, and pretty much almost every domain model in the Stream SDK. + +On Android, custom data is represented as `Map` where the `Any` value can be a String, Integer, Double, Long, Boolean, List, Map or null. The values inside the lists and maps can also only contain the listed types. Custom classes are not supported and we recommend to convert your custom object to a JSON String. + +## Adding Custom Data + +Adding extra data can be done through the Server-Side SDKs or through the Client SDKs. In the Android Stream Video SDK, you can add extra data when creating/updating a user, event, reaction and other models. +As a simple example, let's see how you can add a new custom field to a Video Reaction. + +```kotlin +call.sendReaction( + type = "default", + emoji = ":fireworks:", + custom = mapOf(Pair("yourCustomKey", "customStringValue")) +) +``` + +## Reading Custom Data + +All of the most important domain models in the SDK have an `customData` property that you can read the additional information added by your app. + +The following code snippet shows how to get an email from a user's custom data. + +```Kotlin +val email = user.custom["email"] +``` \ No newline at end of file diff --git a/dogfooding/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt b/dogfooding/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt index 9569050184..40fc853563 100644 --- a/dogfooding/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt +++ b/dogfooding/src/main/kotlin/io/getstream/video/android/ui/join/CallJoinScreen.kt @@ -152,13 +152,11 @@ private fun CallJoinHeader( .padding(24.dp), verticalAlignment = Alignment.CenterVertically, ) { - val name = - user?.name?.ifBlank { user?.id }?.ifBlank { user!!.custom["email"] }.orEmpty() - - if (user != null) { + user?.let { UserAvatar( modifier = Modifier.size(24.dp), - user = user!!, + userName = it.userNameOrId, + userImage = it.image, ) Spacer(modifier = Modifier.width(8.dp)) diff --git a/dogfooding/src/main/kotlin/io/getstream/video/android/ui/lobby/CallLobbyScreen.kt b/dogfooding/src/main/kotlin/io/getstream/video/android/ui/lobby/CallLobbyScreen.kt index 7ee968a110..a9d5ddd3d4 100644 --- a/dogfooding/src/main/kotlin/io/getstream/video/android/ui/lobby/CallLobbyScreen.kt +++ b/dogfooding/src/main/kotlin/io/getstream/video/android/ui/lobby/CallLobbyScreen.kt @@ -135,7 +135,8 @@ private fun CallLobbyHeader( if (userValue != null) { UserAvatar( modifier = Modifier.size(32.dp), - user = userValue, + userName = userValue.userNameOrId, + userImage = userValue.image, ) Spacer(modifier = Modifier.width(4.dp)) diff --git a/stream-video-android-compose/api/stream-video-android-compose.api b/stream-video-android-compose/api/stream-video-android-compose.api index 45e16b3a97..6ea6aa3c3a 100644 --- a/stream-video-android-compose/api/stream-video-android-compose.api +++ b/stream-video-android-compose/api/stream-video-android-compose.api @@ -566,11 +566,11 @@ public final class io/getstream/video/android/compose/ui/components/avatar/Onlin } public final class io/getstream/video/android/compose/ui/components/avatar/UserAvatarBackgroundKt { - public static final fun UserAvatarBackground-1fnCaGY (Lio/getstream/video/android/model/User;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;FFLandroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/layout/ContentScale;Ljava/lang/String;JJIILjava/lang/Integer;Landroidx/compose/runtime/Composer;III)V + public static final fun UserAvatarBackground-GIi8pss (Ljava/lang/String;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;FFLandroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/layout/ContentScale;Ljava/lang/String;JJIILjava/lang/Integer;Landroidx/compose/runtime/Composer;III)V } public final class io/getstream/video/android/compose/ui/components/avatar/UserAvatarKt { - public static final fun UserAvatar-ts-XYlQ (Lio/getstream/video/android/model/User;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/layout/ContentScale;Ljava/lang/String;JILjava/lang/Integer;JZLio/getstream/video/android/compose/ui/components/avatar/OnlineIndicatorAlignment;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;III)V + public static final fun UserAvatar-8W8krDU (Ljava/lang/String;Ljava/lang/String;Landroidx/compose/ui/Modifier;Landroidx/compose/ui/graphics/Shape;Landroidx/compose/ui/text/TextStyle;Landroidx/compose/ui/layout/ContentScale;Ljava/lang/String;JILjava/lang/Integer;JZLio/getstream/video/android/compose/ui/components/avatar/OnlineIndicatorAlignment;Lkotlin/jvm/functions/Function3;Lkotlin/jvm/functions/Function0;Landroidx/compose/runtime/Composer;III)V } public final class io/getstream/video/android/compose/ui/components/background/CallBackgroundKt { diff --git a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/ParticipantAudio.kt b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/ParticipantAudio.kt index bd62ed65d3..66cfea58ae 100644 --- a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/ParticipantAudio.kt +++ b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/audio/ParticipantAudio.kt @@ -74,8 +74,8 @@ public fun ParticipantAudio( }, roleBadgeContent: @Composable RowScope.(ParticipantState) -> Unit = {}, ) { - val user by participant.user.collectAsStateWithLifecycle() val nameOrId by participant.userNameOrId.collectAsStateWithLifecycle() + val userImage by participant.image.collectAsStateWithLifecycle() val isSpeaking by participant.speaking.collectAsStateWithLifecycle() val audioEnabled by participant.audioEnabled.collectAsStateWithLifecycle() @@ -86,7 +86,8 @@ public fun ParticipantAudio( ) { Box(modifier = Modifier.size(VideoTheme.dimens.audioAvatarSize)) { UserAvatar( - user = user, + userName = nameOrId, + userImage = userImage, modifier = Modifier .fillMaxSize() .padding(VideoTheme.dimens.audioAvatarPadding), @@ -130,9 +131,11 @@ public fun ParticipantAudio( roleBadgeContent.invoke(this, participant) } + val roles by participant.roles.collectAsStateWithLifecycle() + Text( modifier = Modifier.fillMaxWidth(), - text = user.role, + text = roles.firstOrNull().orEmpty(), fontSize = 11.sp, color = VideoTheme.colors.textHighEmphasis, textAlign = TextAlign.Center, diff --git a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/avatar/UserAvatar.kt b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/avatar/UserAvatar.kt index e3b4f52738..ed3191adda 100644 --- a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/avatar/UserAvatar.kt +++ b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/avatar/UserAvatar.kt @@ -22,6 +22,7 @@ import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape import androidx.compose.ui.layout.ContentScale @@ -31,6 +32,7 @@ import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.DpOffset import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import io.getstream.video.android.compose.R import io.getstream.video.android.compose.theme.VideoTheme import io.getstream.video.android.mock.StreamMockUtils @@ -59,7 +61,8 @@ import io.getstream.video.android.model.User */ @Composable public fun UserAvatar( - user: User, + userName: String?, + userImage: String?, modifier: Modifier = Modifier, shape: Shape = VideoTheme.shapes.avatar, textStyle: TextStyle = VideoTheme.typography.title3Bold, @@ -79,8 +82,8 @@ public fun UserAvatar( Box(modifier = modifier) { Avatar( modifier = Modifier.fillMaxSize(), - imageUrl = user.image, - initials = user.name.ifBlank { user.id }, + imageUrl = userImage, + initials = userName, textStyle = textStyle, shape = shape, contentScale = contentScale, @@ -111,8 +114,14 @@ internal fun BoxScope.DefaultOnlineIndicator(onlineIndicatorAlignment: OnlineInd private fun UserAvatarPreview() { StreamMockUtils.initializeStreamVideo(LocalContext.current) VideoTheme { + val participant = mockParticipantList[0] + val userId by participant.userId.collectAsStateWithLifecycle() + val userImage by participant.image.collectAsStateWithLifecycle() + val userName by participant.userNameOrId.collectAsStateWithLifecycle() + UserAvatar( - user = mockParticipantList[0].initialUser, + userImage = userImage, + userName = userName, modifier = Modifier.size(82.dp), isShowingOnlineIndicator = true, previewPlaceholder = io.getstream.video.android.ui.common.R.drawable.stream_video_call_sample, diff --git a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/avatar/UserAvatarBackground.kt b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/avatar/UserAvatarBackground.kt index 50b4c340ff..a6ea9b8e57 100644 --- a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/avatar/UserAvatarBackground.kt +++ b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/avatar/UserAvatarBackground.kt @@ -38,7 +38,6 @@ import io.getstream.video.android.compose.theme.VideoTheme import io.getstream.video.android.compose.ui.components.background.ParticipantImageBackground import io.getstream.video.android.mock.StreamMockUtils import io.getstream.video.android.mock.mockUsers -import io.getstream.video.android.model.User /** * A background that displays a user avatar and a background that reflects the avatar. @@ -59,7 +58,8 @@ import io.getstream.video.android.model.User */ @Composable public fun UserAvatarBackground( - user: User, + userName: String?, + userImage: String?, modifier: Modifier = Modifier, shape: Shape = VideoTheme.shapes.avatar, avatarSize: Dp = 72.dp, @@ -76,7 +76,7 @@ public fun UserAvatarBackground( Box(modifier = modifier) { ParticipantImageBackground( modifier = Modifier.fillMaxSize(), - userImage = user.image, + userImage = userImage, blurRadius = blurRadius, ) @@ -85,7 +85,8 @@ public fun UserAvatarBackground( .size(avatarSize) .align(Alignment.Center) .shadow(elevation = avatarShadowElevation, shape = CircleShape), - user = user, + userName = userName, + userImage = userImage, shape = shape, textStyle = textStyle, contentScale = contentScale, @@ -103,8 +104,10 @@ public fun UserAvatarBackground( private fun UserAvatarBackgroundPreview() { StreamMockUtils.initializeStreamVideo(LocalContext.current) VideoTheme { + val user = mockUsers[0] UserAvatarBackground( - user = mockUsers[0], + userName = user.name.ifBlank { user.id }, + userImage = user.image, modifier = Modifier.fillMaxSize(), previewPlaceholder = io.getstream.video.android.ui.common.R.drawable.stream_video_call_sample, ) diff --git a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/lobby/CallLobby.kt b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/lobby/CallLobby.kt index c195472b43..06dd0bdce3 100644 --- a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/lobby/CallLobby.kt +++ b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/lobby/CallLobby.kt @@ -30,7 +30,6 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip @@ -42,7 +41,6 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.lifecycle.compose.collectAsStateWithLifecycle import io.getstream.video.android.compose.lifecycle.MediaPiPLifecycle import io.getstream.video.android.compose.permission.VideoPermissionsState import io.getstream.video.android.compose.permission.rememberCallPermissionsState @@ -132,8 +130,6 @@ public fun CallLobby( ) }, ) { - val participant = remember(user) { ParticipantState(initialUser = user, call = call) } - DefaultPermissionHandler(videoPermission = permissions) MediaPiPLifecycle(call = call) @@ -153,11 +149,10 @@ public fun CallLobby( onDisabledContent.invoke() } - val userNameOrId by participant.userNameOrId.collectAsStateWithLifecycle() - val nameLabel = if (participant.isLocal) { + val nameLabel = if (user.id == StreamVideo.instance().user.id) { stringResource(id = R.string.stream_video_myself) } else { - userNameOrId + user.userNameOrId } ParticipantLabel( @@ -220,7 +215,8 @@ private fun OnDisabledContent(user: User) { modifier = Modifier .size(VideoTheme.dimens.callAvatarSize) .align(Alignment.Center), - user = user, + userImage = user.image, + userName = user.name.ifBlank { user.id }, ) } } diff --git a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/renderer/ParticipantVideo.kt b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/renderer/ParticipantVideo.kt index ff548402ae..0bb1ea0767 100644 --- a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/renderer/ParticipantVideo.kt +++ b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/renderer/ParticipantVideo.kt @@ -108,8 +108,9 @@ public fun ParticipantVideo( ) }, videoFallbackContent: @Composable (Call) -> Unit = { - val user by participant.user.collectAsStateWithLifecycle() - UserAvatarBackground(user = user) + val userName by participant.userNameOrId.collectAsStateWithLifecycle() + val userImage by participant.image.collectAsStateWithLifecycle() + UserAvatarBackground(userName = userName, userImage = userImage) }, reactionContent: @Composable BoxScope.(ParticipantState) -> Unit = { DefaultReaction( @@ -184,8 +185,9 @@ public fun ParticipantVideoRenderer( call: Call, participant: ParticipantState, videoFallbackContent: @Composable (Call) -> Unit = { - val user by participant.user.collectAsStateWithLifecycle() - UserAvatarBackground(user = user) + val userName by participant.userNameOrId.collectAsStateWithLifecycle() + val userImage by participant.image.collectAsStateWithLifecycle() + UserAvatarBackground(userName = userName, userImage = userImage) }, ) { if (LocalInspectionMode.current) { diff --git a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/CallParticipantsInfoMenu.kt b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/CallParticipantsInfoMenu.kt index a95f1fc143..db5815ad7c 100644 --- a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/CallParticipantsInfoMenu.kt +++ b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/CallParticipantsInfoMenu.kt @@ -38,12 +38,12 @@ import io.getstream.video.android.compose.theme.VideoTheme import io.getstream.video.android.compose.ui.components.participants.internal.CallParticipantsList import io.getstream.video.android.compose.ui.components.participants.internal.InviteUserList import io.getstream.video.android.core.Call +import io.getstream.video.android.core.ParticipantState import io.getstream.video.android.core.call.state.CallAction import io.getstream.video.android.core.call.state.InviteUsersToCall import io.getstream.video.android.core.call.state.ToggleMicrophone import io.getstream.video.android.mock.StreamMockUtils import io.getstream.video.android.mock.mockCall -import io.getstream.video.android.model.User /** * Represents a menu that shows information on the current call participants, while allowing the user @@ -65,7 +65,7 @@ public fun CallParticipantsInfoMenu( val audioEnabled = me?.audioEnabled?.collectAsStateWithLifecycle() var infoStateMode by remember { mutableStateOf(ParticipantListMode) } - var selectedUsers: List = remember { mutableStateListOf() } + var selectedUsers: List = remember { mutableStateListOf() } val onBackPressed: () -> Unit = { when (infoStateMode) { diff --git a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/CallParticipantsList.kt b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/CallParticipantsList.kt index af1b380ffc..d612e58038 100644 --- a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/CallParticipantsList.kt +++ b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/CallParticipantsList.kt @@ -119,14 +119,15 @@ private fun CallParticipantInfoItem( ) { Spacer(modifier = Modifier.width(8.dp)) - val user by participant.user.collectAsStateWithLifecycle() + val userName by participant.userNameOrId.collectAsStateWithLifecycle() + val userImage by participant.image.collectAsStateWithLifecycle() UserAvatar( modifier = Modifier.size(VideoTheme.dimens.participantsInfoAvatarSize), - user = user, + userName = userName, + userImage = userImage, isShowingOnlineIndicator = true, ) - val userName by participant.userNameOrId.collectAsStateWithLifecycle() Text( modifier = Modifier .padding(start = 8.dp) diff --git a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/InviteUserList.kt b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/InviteUserList.kt index 029586d3de..724bdd7c26 100644 --- a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/InviteUserList.kt +++ b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/InviteUserList.kt @@ -28,17 +28,19 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import io.getstream.video.android.compose.theme.VideoTheme import io.getstream.video.android.compose.ui.components.avatar.UserAvatar +import io.getstream.video.android.core.ParticipantState import io.getstream.video.android.mock.StreamMockUtils import io.getstream.video.android.mock.mockParticipantList -import io.getstream.video.android.model.User import io.getstream.video.android.ui.common.R /** @@ -50,9 +52,9 @@ import io.getstream.video.android.ui.common.R */ @Composable internal fun InviteUserList( - users: List, - onUserSelected: (User) -> Unit, - onUserUnSelected: (User) -> Unit, + users: List, + onUserSelected: (ParticipantState) -> Unit, + onUserUnSelected: (ParticipantState) -> Unit, modifier: Modifier = Modifier, ) { LazyColumn( @@ -78,10 +80,10 @@ internal fun InviteUserList( */ @Composable internal fun InviteUserItem( - user: User, + user: ParticipantState, isSelected: Boolean, - onUserSelected: (User) -> Unit, - onUserUnSelected: (User) -> Unit, + onUserSelected: (ParticipantState) -> Unit, + onUserUnSelected: (ParticipantState) -> Unit, ) { Row( modifier = Modifier @@ -98,20 +100,18 @@ internal fun InviteUserItem( ) { Spacer(modifier = Modifier.width(8.dp)) + val userName by user.userNameOrId.collectAsStateWithLifecycle() + val userImage by user.image.collectAsStateWithLifecycle() + UserAvatar( modifier = Modifier.size(VideoTheme.dimens.participantsInfoAvatarSize), - user = user, + userName = userName, + userImage = userImage, isShowingOnlineIndicator = true, ) Spacer(modifier = Modifier.width(8.dp)) - val userName = when { - user.name.isNotBlank() -> user.name - user.id.isNotBlank() -> user.id - else -> "Unknown" - } - Text( modifier = Modifier.weight(1f), text = userName, @@ -139,7 +139,7 @@ private fun InviteUserListPreview() { StreamMockUtils.initializeStreamVideo(LocalContext.current) VideoTheme { InviteUserList( - mockParticipantList.map { it.initialUser }, + mockParticipantList, onUserSelected = {}, onUserUnSelected = {}, ) diff --git a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/ParticipantAvatars.kt b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/ParticipantAvatars.kt index 5b47de9285..4dc496b4d3 100644 --- a/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/ParticipantAvatars.kt +++ b/stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/participants/internal/ParticipantAvatars.kt @@ -49,7 +49,8 @@ public fun ParticipantAvatars( UserAvatar( modifier = Modifier.size(VideoTheme.dimens.singleAvatarSize), - user = participant.user, + userName = participant.user.userNameOrId, + userImage = participant.user.image, ) } else { Column(horizontalAlignment = Alignment.CenterHorizontally) { @@ -57,7 +58,8 @@ public fun ParticipantAvatars( items(participants.take(2)) { participant -> UserAvatar( modifier = Modifier.size(VideoTheme.dimens.callAvatarSize), - user = participant.user, + userName = participant.user.userNameOrId, + userImage = participant.user.image, ) } } @@ -65,7 +67,8 @@ public fun ParticipantAvatars( if (participants.size >= 3) { UserAvatar( modifier = Modifier.size(VideoTheme.dimens.callAvatarSize), - user = participants[2].user, + userName = participants[2].user.userNameOrId, + userImage = participants[2].user.image, ) } } diff --git a/stream-video-android-compose/src/test/kotlin/io/getstream/video/android/compose/AvatarTest.kt b/stream-video-android-compose/src/test/kotlin/io/getstream/video/android/compose/AvatarTest.kt index 13cce55403..b870a7017f 100644 --- a/stream-video-android-compose/src/test/kotlin/io/getstream/video/android/compose/AvatarTest.kt +++ b/stream-video-android-compose/src/test/kotlin/io/getstream/video/android/compose/AvatarTest.kt @@ -17,8 +17,10 @@ package io.getstream.video.android.compose import androidx.compose.foundation.layout.size +import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import app.cash.paparazzi.DeviceConfig import app.cash.paparazzi.Paparazzi import io.getstream.video.android.compose.base.BaseComposeTest @@ -48,8 +50,11 @@ internal class AvatarTest : BaseComposeTest() { @Test fun `snapshot UserAvatar composable`() { snapshot { + val name by mockParticipant.name.collectAsStateWithLifecycle() + val image by mockParticipant.image.collectAsStateWithLifecycle() UserAvatar( - user = mockParticipant.initialUser, + userImage = image, + userName = name, modifier = Modifier.size(82.dp), isShowingOnlineIndicator = true, ) diff --git a/stream-video-android-compose/src/test/kotlin/io/getstream/video/android/compose/ParticipantsPortraitTest.kt b/stream-video-android-compose/src/test/kotlin/io/getstream/video/android/compose/ParticipantsPortraitTest.kt index 39ed6da980..173209bc6f 100644 --- a/stream-video-android-compose/src/test/kotlin/io/getstream/video/android/compose/ParticipantsPortraitTest.kt +++ b/stream-video-android-compose/src/test/kotlin/io/getstream/video/android/compose/ParticipantsPortraitTest.kt @@ -76,7 +76,7 @@ internal class ParticipantsPortraitTest : BaseComposeTest() { fun `snapshot InviteUserList composable`() { snapshotWithDarkMode { InviteUserList( - mockParticipantList.map { it.initialUser }, + mockParticipantList, onUserSelected = {}, onUserUnSelected = {}, ) 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 f62ef59174..451e7de67b 100644 --- a/stream-video-android-core/api/stream-video-android-core.api +++ b/stream-video-android-core/api/stream-video-android-core.api @@ -123,8 +123,8 @@ public final class io/getstream/video/android/core/CallState { public final fun getMe ()Lkotlinx/coroutines/flow/StateFlow; public final fun getMember (Ljava/lang/String;)Lio/getstream/video/android/core/MemberState; public final fun getMembers ()Lkotlinx/coroutines/flow/StateFlow; - public final fun getOrCreateParticipant (Ljava/lang/String;Ljava/lang/String;Lio/getstream/video/android/model/User;Z)Lio/getstream/video/android/core/ParticipantState; - public static synthetic fun getOrCreateParticipant$default (Lio/getstream/video/android/core/CallState;Ljava/lang/String;Ljava/lang/String;Lio/getstream/video/android/model/User;ZILjava/lang/Object;)Lio/getstream/video/android/core/ParticipantState; + public final fun getOrCreateParticipant (Ljava/lang/String;Ljava/lang/String;Z)Lio/getstream/video/android/core/ParticipantState; + public static synthetic fun getOrCreateParticipant$default (Lio/getstream/video/android/core/CallState;Ljava/lang/String;Ljava/lang/String;ZILjava/lang/Object;)Lio/getstream/video/android/core/ParticipantState; public final fun getOwnCapabilities ()Lkotlinx/coroutines/flow/StateFlow; public final fun getParticipantBySessionId (Ljava/lang/String;)Lio/getstream/video/android/core/ParticipantState; public final fun getParticipantCounts ()Lkotlinx/coroutines/flow/StateFlow; @@ -449,15 +449,14 @@ public final class io/getstream/video/android/core/MicrophoneManager { } public final class io/getstream/video/android/core/ParticipantState { - public fun (Ljava/lang/String;Lio/getstream/video/android/core/Call;Lio/getstream/video/android/model/User;Ljava/lang/String;)V - public synthetic fun (Ljava/lang/String;Lio/getstream/video/android/core/Call;Lio/getstream/video/android/model/User;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Lio/getstream/video/android/core/Call;Ljava/lang/String;Ljava/lang/String;)V + public synthetic fun (Ljava/lang/String;Lio/getstream/video/android/core/Call;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Lio/getstream/video/android/core/Call; - public final fun component3 ()Lio/getstream/video/android/model/User; public final fun component4 ()Ljava/lang/String; public final fun consumeReaction (Lio/getstream/video/android/core/model/Reaction;)V - public final fun copy (Ljava/lang/String;Lio/getstream/video/android/core/Call;Lio/getstream/video/android/model/User;Ljava/lang/String;)Lio/getstream/video/android/core/ParticipantState; - public static synthetic fun copy$default (Lio/getstream/video/android/core/ParticipantState;Ljava/lang/String;Lio/getstream/video/android/core/Call;Lio/getstream/video/android/model/User;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/ParticipantState; + public final fun copy (Ljava/lang/String;Lio/getstream/video/android/core/Call;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/ParticipantState; + public static synthetic fun copy$default (Lio/getstream/video/android/core/ParticipantState;Ljava/lang/String;Lio/getstream/video/android/core/Call;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/ParticipantState; public fun equals (Ljava/lang/Object;)Z public final fun getAudio ()Lkotlinx/coroutines/flow/StateFlow; public final fun getAudioEnabled ()Lkotlinx/coroutines/flow/StateFlow; @@ -466,9 +465,10 @@ public final class io/getstream/video/android/core/ParticipantState { public final fun getAudioTrack ()Lkotlinx/coroutines/flow/StateFlow; public final fun getCall ()Lio/getstream/video/android/core/Call; public final fun getDominantSpeaker ()Lkotlinx/coroutines/flow/StateFlow; - public final fun getInitialUser ()Lio/getstream/video/android/model/User; + public final fun getImage ()Lkotlinx/coroutines/flow/StateFlow; public final fun getJoinedAt ()Lkotlinx/coroutines/flow/StateFlow; public final fun getLastSpeakingAt ()Lkotlinx/coroutines/flow/StateFlow; + public final fun getName ()Lkotlinx/coroutines/flow/StateFlow; public final fun getNetworkQuality ()Lkotlinx/coroutines/flow/StateFlow; public final fun getReactions ()Lkotlinx/coroutines/flow/StateFlow; public final fun getRoles ()Lkotlinx/coroutines/flow/StateFlow; @@ -477,7 +477,7 @@ public final class io/getstream/video/android/core/ParticipantState { public final fun getScreenSharingTrack ()Lkotlinx/coroutines/flow/StateFlow; public final fun getSessionId ()Ljava/lang/String; public final fun getSpeaking ()Lkotlinx/coroutines/flow/StateFlow; - public final fun getUser ()Lkotlinx/coroutines/flow/StateFlow; + public final fun getUserId ()Lkotlinx/coroutines/flow/StateFlow; public final fun getUserNameOrId ()Lkotlinx/coroutines/flow/StateFlow; public final fun getVideo ()Lkotlinx/coroutines/flow/StateFlow; public final fun getVideoEnabled ()Lkotlinx/coroutines/flow/StateFlow; 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 0701639010..9272a6bd23 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 @@ -1012,7 +1012,14 @@ public data class CreateCallOptions( val startsAt: OffsetDateTime? = null, val team: String? = null, ) { - fun memberRequestsFromIds(): List? { - return memberIds?.map { MemberRequest(userId = it) } ?: members + fun memberRequestsFromIds(): List { + val memberRequestList: MutableList = mutableListOf() + if (memberIds != null) { + memberRequestList.addAll(memberIds.map { MemberRequest(userId = it) }) + } + if (members != null) { + memberRequestList.addAll(members) + } + return memberRequestList } } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt index 73ccf1e60d..b04be15011 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt @@ -467,7 +467,7 @@ public class CallState( } private val userToSessionIdMap = participants.mapState { participants -> - participants.associate { it.user.value.id to it.sessionId } + participants.associate { it.userId.value to it.sessionId } } internal val _hasPermissionMap = mutableMapOf>() @@ -941,7 +941,6 @@ public class CallState( fun getOrCreateParticipant( sessionId: String, userId: String, - user: User? = null, updateFlow: Boolean = false, ): ParticipantState { val participantMap = _participants.value.toSortedMap() @@ -951,7 +950,7 @@ public class CallState( ParticipantState( sessionId = sessionId, call = call, - initialUser = user ?: User(userId), + initialUserId = userId, ) } if (updateFlow) { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ParticipantState.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ParticipantState.kt index 66f3078713..fc76970740 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ParticipantState.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ParticipantState.kt @@ -26,7 +26,6 @@ import io.getstream.video.android.core.model.Reaction import io.getstream.video.android.core.model.VideoTrack import io.getstream.video.android.core.utils.combineStates import io.getstream.video.android.core.utils.mapState -import io.getstream.video.android.model.User import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import org.openapitools.client.models.MuteUsersResponse @@ -48,7 +47,7 @@ public data class ParticipantState( /** The call object */ val call: Call, /** The current version of the user, this is the start for participant.user stateflow */ - val initialUser: User, + private val initialUserId: String, /** A prefix to identify tracks, internal */ @InternalStreamVideoApi var trackLookupPrefix: String = "", @@ -84,12 +83,17 @@ public data class ParticipantState( internal val _screenSharingTrack = MutableStateFlow(null) val screenSharingTrack: StateFlow = _screenSharingTrack - /** The user, automatically updates when we receive user events. */ - internal val _user: MutableStateFlow = MutableStateFlow(initialUser) - val user: StateFlow = _user + internal val _name = MutableStateFlow("") + val name: StateFlow = _name + + internal val _image = MutableStateFlow("") + val image: StateFlow = _image + + internal val _userId = MutableStateFlow(initialUserId) + val userId: StateFlow = _userId // Could also be a property on the user - val userNameOrId: StateFlow = _user.mapState { it.name.ifEmpty { it.id } } + val userNameOrId: StateFlow = _name.mapState { it.ifEmpty { _userId.value } } /** * When you joined the call @@ -156,15 +160,15 @@ public data class ParticipantState( suspend fun muteAudio(): Result { // how do i mute another user? - return call.muteUser(user.value.id, audio = true, video = false, screenShare = false) + return call.muteUser(_userId.value, audio = true, video = false, screenShare = false) } suspend fun muteVideo(): Result { - return call.muteUser(user.value.id, audio = false, video = true, screenShare = false) + return call.muteUser(_userId.value, audio = false, video = true, screenShare = false) } suspend fun muteScreenshare(): Result { - return call.muteUser(user.value.id, audio = false, video = false, screenShare = true) + return call.muteUser(_userId.value, audio = false, video = false, screenShare = true) } suspend fun pin() { @@ -209,16 +213,8 @@ public data class ParticipantState( participant.published_tracks.contains(TrackType.TRACK_TYPE_SCREEN_SHARE) _roles.value = participant.roles - val custom = participant.custom ?: emptyMap() - - val currentUser = _user.value - _user.value = currentUser.copy( - name = participant.name, - image = participant.image, - role = participant.roles.firstOrNull().orEmpty(), - // TODO: set the custom field - // custom = custom - ) + _name.value = participant.name + _image.value = participant.image } public fun consumeReaction(reaction: Reaction) { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt index 15054be56c..eaff9564c5 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt @@ -898,7 +898,7 @@ public class RtcSession internal constructor( otherParticipants.forEach { participant -> if (participant.videoEnabled.value) { val track = TrackSubscriptionDetails( - user_id = participant.user.value.id, + user_id = participant.userId.value, track_type = TrackType.TRACK_TYPE_VIDEO, dimension = defaultVideoDimension, session_id = participant.sessionId, @@ -907,7 +907,7 @@ public class RtcSession internal constructor( } if (participant.screenSharingEnabled.value) { val track = TrackSubscriptionDetails( - user_id = participant.user.value.id, + user_id = participant.userId.value, track_type = TrackType.TRACK_TYPE_SCREEN_SHARE, dimension = defaultVideoDimension, session_id = participant.sessionId, @@ -931,7 +931,7 @@ public class RtcSession internal constructor( "[visibleTracks] $sessionId subscribing ${participant.sessionId} to : ${display.key}" } TrackSubscriptionDetails( - user_id = participant.user.value.id, + user_id = participant.userId.value, track_type = display.key, dimension = display.value.dimensions, session_id = participant.sessionId, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/state/CallAction.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/state/CallAction.kt index a6d8571acb..e57953a2ce 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/state/CallAction.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/state/CallAction.kt @@ -17,7 +17,7 @@ package io.getstream.video.android.core.call.state import com.twilio.audioswitch.AudioDevice -import io.getstream.video.android.model.User +import io.getstream.video.android.core.ParticipantState /** * Represents various actions users can take while in a call. @@ -96,7 +96,7 @@ public data object Reaction : CallAction * Action to invite other users to a call. */ public data class InviteUsersToCall( - val users: List, + val users: List, ) : CallAction /** diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/CoordinatorSocket.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/CoordinatorSocket.kt index 943e2f0fee..dde19f0ab7 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/CoordinatorSocket.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/CoordinatorSocket.kt @@ -68,6 +68,7 @@ public class CoordinatorSocket( id = user.id, name = user.name, image = user.image, + custom = user.custom, ), ) val message = adapter.toJson(authRequest) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/utils/DomainUtils.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/utils/DomainUtils.kt index 14f4297885..bbcc657c4e 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/utils/DomainUtils.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/utils/DomainUtils.kt @@ -17,7 +17,6 @@ package io.getstream.video.android.core.utils import io.getstream.video.android.core.MemberState -import io.getstream.video.android.core.ParticipantState import io.getstream.video.android.core.internal.InternalStreamVideoApi import io.getstream.video.android.core.model.CallData import io.getstream.video.android.core.model.CallRecordingData @@ -56,21 +55,6 @@ internal fun MemberResponse.toCallUser(): CallUser { ) } -@JvmSynthetic -@InternalStreamVideoApi -public fun ParticipantState.toCallUser(): CallUser { - return CallUser( - id = initialUser.id, - name = initialUser.name, - imageUrl = initialUser.image, - teams = initialUser.teams, - role = initialUser.role, - state = null, - createdAt = null, - updatedAt = null, - ) -} - @JvmSynthetic @InternalStreamVideoApi public fun MemberState.toCallUser(): CallUser { diff --git a/stream-video-android-core/src/test/kotlin/io/getstream/video/android/core/CallStateTest.kt b/stream-video-android-core/src/test/kotlin/io/getstream/video/android/core/CallStateTest.kt index acf438069c..25e0912827 100644 --- a/stream-video-android-core/src/test/kotlin/io/getstream/video/android/core/CallStateTest.kt +++ b/stream-video-android-core/src/test/kotlin/io/getstream/video/android/core/CallStateTest.kt @@ -131,23 +131,23 @@ class CallStateTest : IntegrationTestBase() { ) call.state.updateParticipant( - ParticipantState("4", call, User("4")).apply { _lastSpeakingAt.value = nowUtc }, + ParticipantState("4", call,"4").apply { _lastSpeakingAt.value = nowUtc }, ) call.state.updateParticipant( - ParticipantState("5", call, User("5")).apply { _videoEnabled.value = true }, + ParticipantState("5", call,"5").apply { _videoEnabled.value = true }, ) call.state.updateParticipant( - ParticipantState("6", call, User("6")).apply { _joinedAt.value = nowUtc }, + ParticipantState("6", call, "6").apply { _joinedAt.value = nowUtc }, ) call.state.updateParticipant( - ParticipantState("1", call, User("1")), + ParticipantState("1", call, "1"), ) call.state.updateParticipant( - ParticipantState("2", call, User("2")).apply { _dominantSpeaker.value = true }, + ParticipantState("2", call, "2").apply { _dominantSpeaker.value = true }, ) call.state.updateParticipant( - ParticipantState("3", call, User("3")).apply { _screenSharingEnabled.value = true }, + ParticipantState("3", call, "3").apply { _screenSharingEnabled.value = true }, ) val participants = call.state.participants.value diff --git a/stream-video-android-core/src/test/kotlin/io/getstream/video/android/core/EventTest.kt b/stream-video-android-core/src/test/kotlin/io/getstream/video/android/core/EventTest.kt index a5257de092..3d18aa35a8 100644 --- a/stream-video-android-core/src/test/kotlin/io/getstream/video/android/core/EventTest.kt +++ b/stream-video-android-core/src/test/kotlin/io/getstream/video/android/core/EventTest.kt @@ -80,7 +80,7 @@ class EventTest : IntegrationTestBase(connectCoordinatorWS = false) { // ensure we update call data and capabilities assertThat( - call.state.activeSpeakers.value.map { it.initialUser.id }, + call.state.activeSpeakers.value.map { it.userId }, ).containsExactly("thierry") } @@ -90,7 +90,7 @@ class EventTest : IntegrationTestBase(connectCoordinatorWS = false) { clientImpl.fireEvent(event, call.cid) // ensure we update call data and capabilities - assertThat(call.state.dominantSpeaker.value?.user?.value?.id).isEqualTo("jaewoong") + assertThat(call.state.dominantSpeaker.value?.userId?.value).isEqualTo("jaewoong") } @Test diff --git a/stream-video-android-mock/src/main/kotlin/io/getstream/video/android/mock/StreamMockUtils.kt b/stream-video-android-mock/src/main/kotlin/io/getstream/video/android/mock/StreamMockUtils.kt index 07db12edca..5d87ba1ee1 100644 --- a/stream-video-android-mock/src/main/kotlin/io/getstream/video/android/mock/StreamMockUtils.kt +++ b/stream-video-android-mock/src/main/kotlin/io/getstream/video/android/mock/StreamMockUtils.kt @@ -61,7 +61,7 @@ public val mockCall: Call = Call( UUID.randomUUID().toString() } ParticipantState( - initialUser = user, + initialUserId = user.id, sessionId = sessionId, call = this, ) @@ -130,7 +130,7 @@ public val mockParticipantList: List } participants.add( ParticipantState( - initialUser = user, + initialUserId = user.id, sessionId = sessionId, call = mockCall, ).also { mockCall.state.updateParticipant(it) }, diff --git a/stream-video-android-xml/api/stream-video-android-xml.api b/stream-video-android-xml/api/stream-video-android-xml.api index 34ba7647c4..b6b1791b25 100644 --- a/stream-video-android-xml/api/stream-video-android-xml.api +++ b/stream-video-android-xml/api/stream-video-android-xml.api @@ -382,8 +382,8 @@ public final class io/getstream/video/android/xml/widget/avatar/AvatarView : com public fun (Landroid/content/Context;Landroid/util/AttributeSet;)V public fun (Landroid/content/Context;Landroid/util/AttributeSet;I)V public final fun setData (Lio/getstream/video/android/core/model/CallUser;)V - public final fun setData (Lio/getstream/video/android/model/User;)V public final fun setData (Ljava/lang/String;)V + public final fun setData (Ljava/lang/String;Ljava/lang/String;)V } public final class io/getstream/video/android/xml/widget/call/CallView : io/getstream/video/android/xml/widget/view/CallConstraintLayout { diff --git a/stream-video-android-xml/src/main/kotlin/io/getstream/video/android/xml/widget/avatar/AvatarView.kt b/stream-video-android-xml/src/main/kotlin/io/getstream/video/android/xml/widget/avatar/AvatarView.kt index 04e6fbe8ad..4375992008 100644 --- a/stream-video-android-xml/src/main/kotlin/io/getstream/video/android/xml/widget/avatar/AvatarView.kt +++ b/stream-video-android-xml/src/main/kotlin/io/getstream/video/android/xml/widget/avatar/AvatarView.kt @@ -65,12 +65,12 @@ public class AvatarView : ShapeableImageView { * * @param user The [User] for which we want to show the avatar. */ - public fun setData(user: User) { + public fun setData(initials: String, userImage: String?) { load( - data = user.image, + data = userImage, placeholderDrawable = AvatarPlaceholderDrawable( context = context, - initials = user.name.ifEmpty { user.id }.initials(), + initials = initials, initialsTextStyle = avatarStyle.avatarInitialsTextStyle, ), ) diff --git a/stream-video-android-xml/src/main/kotlin/io/getstream/video/android/xml/widget/participant/CallParticipantView.kt b/stream-video-android-xml/src/main/kotlin/io/getstream/video/android/xml/widget/participant/CallParticipantView.kt index 53cb541a4b..ba6c0453a4 100644 --- a/stream-video-android-xml/src/main/kotlin/io/getstream/video/android/xml/widget/participant/CallParticipantView.kt +++ b/stream-video-android-xml/src/main/kotlin/io/getstream/video/android/xml/widget/participant/CallParticipantView.kt @@ -25,6 +25,7 @@ import androidx.core.view.isVisible import io.getstream.log.taggedLogger import io.getstream.video.android.core.ParticipantState import io.getstream.video.android.core.model.MediaTrack +import io.getstream.video.android.core.utils.initials import io.getstream.video.android.model.User import io.getstream.video.android.xml.databinding.StreamVideoViewCallParticipantBinding import io.getstream.video.android.xml.font.setTextStyle @@ -141,7 +142,8 @@ public class CallParticipantView : CallCardView, VideoRenderer { */ public fun setParticipant(participant: ParticipantState) { binding.labelHolder.isVisible = !participant.isLocal - setUserData(participant.user.value) + val userName = participant.userNameOrId.value + setUserData(userName = userName, userImage = participant.image.value) setTrack(participant.videoTrack.value) setAvatarVisibility(participant) setHasAudio(participant.audioEnabled.value) @@ -174,9 +176,9 @@ public class CallParticipantView : CallCardView, VideoRenderer { * * @param user The [User] whose video we are viewing. */ - private fun setUserData(user: User) { - binding.participantAvatar.setData(user) - binding.participantLabel.text = user.name.ifBlank { user.id } + private fun setUserData(userName: String, userImage: String?) { + binding.participantAvatar.setData(initials = userName.initials(), userImage = userImage) + binding.participantLabel.text = userName } /**