From aacc0134858ed2e50d2491a958b8a757995fb865 Mon Sep 17 00:00:00 2001 From: Marcel Hibbe Date: Tue, 6 May 2025 14:30:45 +0200 Subject: [PATCH] improve call participants layout Signed-off-by: Marcel Hibbe --- .../nextcloud/talk/activities/CallActivity.kt | 19 +-- .../talk/call/components/ParticipantGrid.kt | 159 ++++++++++++++++-- .../talk/call/components/ParticipantTile.kt | 13 +- 3 files changed, 150 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt index 52037903f..82a83dcb2 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/CallActivity.kt @@ -956,27 +956,10 @@ class CallActivity : CallBaseActivity() { private fun initGrid() { Log.d(TAG, "initGrid") - val participantsInGrid = participantUiStates.size - val columns = when { - resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT -> { - if (participantsInGrid > 2) GRID_MAX_COLUMN_COUNT_PORTRAIT else GRID_MIN_COLUMN_COUNT_PORTRAIT - } - else -> { - if (participantsInGrid > 2) { - GRID_MAX_COLUMN_COUNT_LANDSCAPE - } else if (participantsInGrid > 1) { - GRID_MIN_GROUP_COLUMN_COUNT_LANDSCAPE - } else { - GRID_MIN_COLUMN_COUNT_LANDSCAPE - } - } - } - binding!!.composeParticipantGrid.setContent { MaterialTheme { ParticipantGrid( - participants = participantUiStates.toList(), - columns = columns + participants = participantUiStates.toList() ) { animateCallControls(true, 0) } diff --git a/app/src/main/java/com/nextcloud/talk/call/components/ParticipantGrid.kt b/app/src/main/java/com/nextcloud/talk/call/components/ParticipantGrid.kt index 8e25cded0..59d153c26 100644 --- a/app/src/main/java/com/nextcloud/talk/call/components/ParticipantGrid.kt +++ b/app/src/main/java/com/nextcloud/talk/call/components/ParticipantGrid.kt @@ -7,36 +7,159 @@ package com.nextcloud.talk.call.components +import android.content.res.Configuration import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.foundation.lazy.grid.items import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import com.nextcloud.talk.call.ParticipantUiState @Composable -fun ParticipantGrid( - participants: List, - columns: Int = 2, - modifier: Modifier = Modifier, - onClick: () -> Unit -) { - LazyVerticalGrid( - columns = GridCells.Fixed(columns), - modifier = modifier - .fillMaxSize() - .clickable { onClick() }, - contentPadding = PaddingValues(8.dp), - verticalArrangement = Arrangement.spacedBy(8.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp) - ) { - items(participants, key = { it.sessionKey }) { participant -> - ParticipantTile(participant) +fun ParticipantGrid(modifier: Modifier = Modifier, participants: List, onClick: () -> Unit) { + val configuration = LocalConfiguration.current + val isPortrait = configuration.orientation == Configuration.ORIENTATION_PORTRAIT + + when (participants.size) { + 0 -> {} + 1 -> { + Box( + modifier = Modifier + .fillMaxSize() + ) { + ParticipantTile( + participant = participants[0], + modifier = Modifier + .fillMaxSize() + .clickable { onClick() } + ) + } + } + + 2, 3 -> { + if (isPortrait) { + Column( + modifier = Modifier + .fillMaxSize() + .padding(vertical = 4.dp) + .clickable { onClick() }, + verticalArrangement = Arrangement.spacedBy(8.dp) + ) { + participants.forEach { + ParticipantTile( + participant = it, + modifier = Modifier + .weight(1f) + .fillMaxWidth() + ) + } + } + } else { + Row( + modifier = Modifier + .fillMaxSize() + .padding(horizontal = 4.dp) + .clickable { onClick() }, + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + participants.forEach { + ParticipantTile( + participant = it, + modifier = Modifier + .weight(1f) + .fillMaxHeight() + ) + } + } + } + } + + else -> { + LazyVerticalGrid( + columns = GridCells.Fixed(if (isPortrait) 2 else 3), + modifier = Modifier + .fillMaxSize() + .padding(8.dp) + .clickable { onClick() }, + verticalArrangement = Arrangement.spacedBy(8.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + items(participants) { participant -> + ParticipantTile( + participant = participant, + modifier = Modifier + .fillMaxWidth() + .aspectRatio(1.5f) + ) + } + } } } } + +const val numberOfParticipants = 4 + +@Preview( + showBackground = false +) +@Composable +fun ParticipantGridPreview() { + ParticipantGrid( + participants = getTestParticipants(numberOfParticipants) + ) {} +} + +@Preview( + showBackground = false, + heightDp = 902, + widthDp = 434 +) +@Composable +fun ParticipantGridPreviewPortrait2() { + ParticipantGrid( + participants = getTestParticipants(numberOfParticipants) + ) {} +} + +@Preview( + showBackground = false, + heightDp = 360, + widthDp = 800 +) +@Composable +fun ParticipantGridPreviewLandscape1() { + ParticipantGrid( + participants = getTestParticipants(numberOfParticipants) + ) {} +} + +fun getTestParticipants(numberOfParticipants: Int): List { + val participantList = mutableListOf() + for (i: Int in 1..numberOfParticipants) { + val participant = ParticipantUiState( + sessionKey = i.toString(), + nick = "testuser$i", + isConnected = true, + isAudioEnabled = if (i == 3) true else false, + isStreamEnabled = true, + raisedHand = true, + avatarUrl = "", + surfaceViewRenderer = null + ) + participantList.add(participant) + } + return participantList +} diff --git a/app/src/main/java/com/nextcloud/talk/call/components/ParticipantTile.kt b/app/src/main/java/com/nextcloud/talk/call/components/ParticipantTile.kt index 754d689e3..448303b01 100644 --- a/app/src/main/java/com/nextcloud/talk/call/components/ParticipantTile.kt +++ b/app/src/main/java/com/nextcloud/talk/call/components/ParticipantTile.kt @@ -9,7 +9,7 @@ package com.nextcloud.talk.call.components import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.RoundedCornerShape @@ -29,10 +29,9 @@ import com.nextcloud.talk.R import com.nextcloud.talk.call.ParticipantUiState @Composable -fun ParticipantTile(participant: ParticipantUiState) { +fun ParticipantTile(participant: ParticipantUiState, modifier: Modifier = Modifier) { Box( - modifier = Modifier - .aspectRatio(3f / 4f) + modifier = modifier .clip(RoundedCornerShape(12.dp)) .background(Color.DarkGray) ) { @@ -97,5 +96,9 @@ fun ParticipantTilePreview() { avatarUrl = "", surfaceViewRenderer = null ) - ParticipantTile(participant) + ParticipantTile( + participant = participant, + modifier = Modifier + .fillMaxWidth() + ) }