Skip to content

Commit

Permalink
Improve participant actions button UI
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksandar-apostolov committed Nov 16, 2023
1 parent c8db9b6 commit 3b0832c
Showing 1 changed file with 75 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.getstream.video.android.compose.ui.components.call.pinning

import android.content.res.Configuration
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
Expand All @@ -27,30 +28,39 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.FlowRow
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.Button
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Icon
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Cancel
import androidx.compose.material.icons.filled.PushPin
import androidx.compose.material.icons.outlined.MoreHoriz
import androidx.compose.material.icons.outlined.PushPin
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Alignment.Companion.Center
import androidx.compose.ui.Alignment.Companion.CenterHorizontally
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
import androidx.lifecycle.compose.collectAsStateWithLifecycle
Expand All @@ -72,12 +82,14 @@ import org.openapitools.client.models.OwnCapability
*
* @param icon the icon that represents the action.
* @param label the text that represents the action.
* @param firstToggleAction a boolean noting if this action is first of two (i.e. Pin is first = true, where Unpin is first=false)
* @param condition the condition if the action is to be shown or not.
* @param action the action (i.e. callable)
*/
public class ParticipantAction(
public val icon: ImageVector? = null,
public val icon: ImageVector,
public val label: String,
public val firstToggleAction: Boolean = true,
public val condition: (Call, ParticipantState) -> Boolean = { _, _ -> true },
public val action: CoroutineScope.(Call, ParticipantState) -> Unit = { _, _ -> },
)
Expand All @@ -87,7 +99,7 @@ public class ParticipantAction(
*/
internal val pinUnpinActions: List<ParticipantAction> = listOf(
ParticipantAction(
icon = Icons.Filled.PushPin,
icon = Icons.Outlined.PushPin,
label = "Pin",
condition = { call, participantState ->
!call.isLocalPin(participantState.sessionId)
Expand All @@ -99,8 +111,9 @@ internal val pinUnpinActions: List<ParticipantAction> = listOf(
},
),
ParticipantAction(
icon = Icons.Filled.Cancel,
icon = Icons.Filled.PushPin,
label = "Unpin",
firstToggleAction = false,
condition = { call, participantState ->
call.isLocalPin(participantState.sessionId)
},
Expand All @@ -111,7 +124,7 @@ internal val pinUnpinActions: List<ParticipantAction> = listOf(
},
),
ParticipantAction(
icon = Icons.Filled.PushPin,
icon = Icons.Outlined.PushPin,
label = "Pin for everyone",
condition = { call, participantState ->
call.hasCapability(OwnCapability.PinForEveryone) && !call.isServerPin(participantState.sessionId)
Expand All @@ -123,8 +136,9 @@ internal val pinUnpinActions: List<ParticipantAction> = listOf(
},
),
ParticipantAction(
icon = Icons.Filled.Cancel,
icon = Icons.Filled.PushPin,
label = "Unpin for everyone",
firstToggleAction = false,
condition = { call, participantState ->
call.hasCapability(OwnCapability.PinForEveryone) && call.isServerPin(participantState.sessionId)
},
Expand Down Expand Up @@ -188,10 +202,8 @@ internal fun BoxScope.ParticipantActionsDialog(
val userImage by participant.image.collectAsStateWithLifecycle()
val name = remember {
val nameValue = participant.name.value
if (nameValue.isEmpty()) {
nameValue.ifEmpty {
participant.userNameOrId.value
} else {
nameValue
}
}
Dialog(onDismiss) {
Expand Down Expand Up @@ -223,21 +235,24 @@ internal fun BoxScope.ParticipantActionsDialog(
) {
actions.forEach {
if (it.condition.invoke(call, participant)) {
Button(
modifier = Modifier.padding(8.dp),
onClick = {
val circleColor = if (it.firstToggleAction) VideoTheme.colors.textHighEmphasis else VideoTheme.colors.primaryAccent
val strokeWidth = if (it.firstToggleAction) 2.dp else 4.dp
Column {
CircleIcon(
icon = it.icon,
modifier = Modifier.align(CenterHorizontally),
tint = circleColor,
circleColor = circleColor,
strokeWidth = strokeWidth,
) {
it.action.invoke(coroutineScope, call, participant)
},
) {
it.icon?.let { hasIcon ->
Icon(
imageVector = hasIcon,
contentDescription = it.label,
)
}
Spacer(modifier = Modifier.height(8.dp))
Text(
textAlign = TextAlign.Start,
modifier = Modifier.align(CenterHorizontally).width(80.dp),
textAlign = TextAlign.Center,
text = it.label,
color = VideoTheme.colors.textHighEmphasis,
)
}
}
Expand All @@ -248,6 +263,45 @@ internal fun BoxScope.ParticipantActionsDialog(
}
}

@Composable
private fun CircleIcon(
icon: ImageVector,
modifier: Modifier,
tint: Color,
circleColor: Color,
strokeWidth: Dp = 2.dp,
onClick: () -> Unit,
) {
val density = LocalDensity.current
Box(
modifier = modifier
.size(48.dp)
.clip(CircleShape)
.background(Color.Transparent)
.clickable {
onClick()
},
) {
Canvas(modifier = Modifier.fillMaxSize(), onDraw = {
drawCircleOutline(density, circleColor, strokeWidth)
})
Icon(
modifier = Modifier.align(Center),
imageVector = icon,
contentDescription = null,
tint = tint,
)
}
}

private fun DrawScope.drawCircleOutline(density: Density, color: Color, width: Dp) {
val strokeWidth = with(density) { width.toPx() }
drawCircle(
color = color,
style = androidx.compose.ui.graphics.drawscope.Stroke(strokeWidth),
)
}

@Preview
@Composable
private fun ParticipantActionDialogPreview() {
Expand Down

0 comments on commit 3b0832c

Please sign in to comment.