diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerView.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerView.kt index 4e7a23094b..0e4b168866 100644 --- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerView.kt +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollAnswerView.kt @@ -21,24 +21,21 @@ 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.size import androidx.compose.foundation.layout.width -import androidx.compose.foundation.selection.selectable import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.CheckCircle import androidx.compose.material.icons.filled.RadioButtonUnchecked -import androidx.compose.material3.IconButtonDefaults import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.StrokeCap import androidx.compose.ui.res.pluralStringResource -import androidx.compose.ui.semantics.Role -import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import io.element.android.libraries.designsystem.preview.ElementThemedPreview +import io.element.android.libraries.designsystem.preview.DayNightPreviews +import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.theme.components.Icon -import io.element.android.libraries.designsystem.theme.components.IconToggleButton import io.element.android.libraries.designsystem.theme.components.LinearProgressIndicator import io.element.android.libraries.designsystem.theme.components.Text import io.element.android.libraries.designsystem.theme.progressIndicatorTrackColor @@ -47,41 +44,33 @@ import io.element.android.libraries.theme.ElementTheme import io.element.android.libraries.ui.strings.CommonPlurals @Composable -fun PollAnswerView( +internal fun PollAnswerView( answerItem: PollAnswerItem, - onClick: () -> Unit, modifier: Modifier = Modifier, ) { Row( - modifier - .fillMaxWidth() - .selectable( - selected = answerItem.isSelected, - enabled = answerItem.isEnabled, - onClick = onClick, - role = Role.RadioButton, - ) + modifier = modifier.fillMaxWidth(), ) { - IconToggleButton( - modifier = Modifier.size(22.dp), - checked = answerItem.isSelected, - enabled = answerItem.isEnabled, - colors = IconButtonDefaults.iconToggleButtonColors( - contentColor = ElementTheme.colors.iconSecondary, - checkedContentColor = ElementTheme.colors.iconPrimary, - disabledContentColor = ElementTheme.colors.iconDisabled, - ), - onCheckedChange = { onClick() }, - ) { - Icon( - imageVector = if (answerItem.isSelected) { - Icons.Default.CheckCircle + Icon( + imageVector = if (answerItem.isSelected) { + Icons.Default.CheckCircle + } else { + Icons.Default.RadioButtonUnchecked + }, + contentDescription = null, + modifier = Modifier + .padding(0.5.dp) + .size(22.dp), + tint = if (answerItem.isEnabled) { + if (answerItem.isSelected) { + ElementTheme.colors.iconPrimary } else { - Icons.Default.RadioButtonUnchecked - }, - contentDescription = null, - ) - } + ElementTheme.colors.iconSecondary + } + } else { + ElementTheme.colors.iconDisabled + }, + ) Spacer(modifier = Modifier.width(12.dp)) Column { Row { @@ -119,65 +108,58 @@ fun PollAnswerView( } } -@Preview +@DayNightPreviews @Composable -internal fun PollAnswerDisclosedNotSelectedPreview() = ElementThemedPreview { +internal fun PollAnswerDisclosedNotSelectedPreview() = ElementPreview { PollAnswerView( answerItem = aPollAnswerItem(isDisclosed = true, isSelected = false), - onClick = { }, ) } -@Preview +@DayNightPreviews @Composable -internal fun PollAnswerDisclosedSelectedPreview() = ElementThemedPreview { +internal fun PollAnswerDisclosedSelectedPreview() = ElementPreview { PollAnswerView( answerItem = aPollAnswerItem(isDisclosed = true, isSelected = true), - onClick = { } ) } -@Preview +@DayNightPreviews @Composable -internal fun PollAnswerUndisclosedNotSelectedPreview() = ElementThemedPreview { +internal fun PollAnswerUndisclosedNotSelectedPreview() = ElementPreview { PollAnswerView( answerItem = aPollAnswerItem(isDisclosed = false, isSelected = false), - onClick = { }, ) } -@Preview +@DayNightPreviews @Composable -internal fun PollAnswerUndisclosedSelectedPreview() = ElementThemedPreview { +internal fun PollAnswerUndisclosedSelectedPreview() = ElementPreview { PollAnswerView( answerItem = aPollAnswerItem(isDisclosed = false, isSelected = true), - onClick = { } ) } -@Preview +@DayNightPreviews @Composable -internal fun PollAnswerEndedWinnerNotSelectedPreview() = ElementThemedPreview { +internal fun PollAnswerEndedWinnerNotSelectedPreview() = ElementPreview { PollAnswerView( answerItem = aPollAnswerItem(isDisclosed = true, isSelected = false, isEnabled = false, isWinner = true), - onClick = { } ) } -@Preview +@DayNightPreviews @Composable -internal fun PollAnswerEndedWinnerSelectedPreview() = ElementThemedPreview { +internal fun PollAnswerEndedWinnerSelectedPreview() = ElementPreview { PollAnswerView( answerItem = aPollAnswerItem(isDisclosed = true, isSelected = true, isEnabled = false, isWinner = true), - onClick = { } ) } -@Preview +@DayNightPreviews @Composable -internal fun PollAnswerEndedSelectedPreview() = ElementThemedPreview { +internal fun PollAnswerEndedSelectedPreview() = ElementPreview { PollAnswerView( answerItem = aPollAnswerItem(isDisclosed = true, isSelected = true, isEnabled = false, isWinner = false), - onClick = { } ) } diff --git a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollContentView.kt b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollContentView.kt index 7e03d7a46e..a47d69c780 100644 --- a/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollContentView.kt +++ b/features/poll/api/src/main/kotlin/io/element/android/features/poll/api/PollContentView.kt @@ -23,11 +23,14 @@ import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.selection.selectable import androidx.compose.foundation.selection.selectableGroup import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role import androidx.compose.ui.unit.dp import io.element.android.libraries.designsystem.VectorIcons import io.element.android.libraries.designsystem.preview.DayNightPreviews @@ -56,24 +59,24 @@ fun PollContentView( } Column( - modifier = modifier - .selectableGroup() - .fillMaxWidth(), + modifier = modifier.fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(16.dp), ) { PollTitle(title = question, isPollEnded = isPollEnded) PollAnswers(answerItems = answerItems, onAnswerSelected = ::onAnswerSelected) - when { - isPollEnded || pollKind == PollKind.Disclosed -> DisclosedPollBottomNotice(answerItems) - pollKind == PollKind.Undisclosed -> UndisclosedPollBottomNotice() + if (isPollEnded || pollKind == PollKind.Disclosed) { + val votesCount = remember(answerItems) { answerItems.sumOf { it.votesCount } } + DisclosedPollBottomNotice(votesCount = votesCount) + } else { + UndisclosedPollBottomNotice() } } } @Composable -internal fun PollTitle( +private fun PollTitle( title: String, isPollEnded: Boolean, modifier: Modifier = Modifier @@ -85,13 +88,13 @@ internal fun PollTitle( if (isPollEnded) { Icon( resourceId = VectorIcons.PollEnd, - contentDescription = null, + contentDescription = stringResource(id = CommonStrings.a11y_poll_end), modifier = Modifier.size(22.dp) ) } else { Icon( resourceId = VectorIcons.Poll, - contentDescription = null, + contentDescription = stringResource(id = CommonStrings.a11y_poll), modifier = Modifier.size(22.dp) ) } @@ -103,27 +106,35 @@ internal fun PollTitle( } @Composable -internal fun PollAnswers( +private fun PollAnswers( answerItems: ImmutableList, onAnswerSelected: (PollAnswer) -> Unit, modifier: Modifier = Modifier, ) { - - answerItems.forEach { answerItem -> - PollAnswerView( - modifier = modifier, - answerItem = answerItem, - onClick = { onAnswerSelected(answerItem.answer) } - ) + Column( + modifier = modifier.selectableGroup(), + verticalArrangement = Arrangement.spacedBy(16.dp), + ) { + answerItems.forEach { + PollAnswerView( + answerItem = it, + modifier = Modifier + .selectable( + selected = it.isSelected, + enabled = it.isEnabled, + onClick = { onAnswerSelected(it.answer) }, + role = Role.RadioButton, + ), + ) + } } } @Composable -internal fun ColumnScope.DisclosedPollBottomNotice( - answerItems: ImmutableList, +private fun ColumnScope.DisclosedPollBottomNotice( + votesCount: Int, modifier: Modifier = Modifier ) { - val votesCount = answerItems.sumOf { it.votesCount } Text( modifier = modifier.align(Alignment.End), style = ElementTheme.typography.fontBodyXsRegular, @@ -133,7 +144,9 @@ internal fun ColumnScope.DisclosedPollBottomNotice( } @Composable -fun ColumnScope.UndisclosedPollBottomNotice(modifier: Modifier = Modifier) { +private fun ColumnScope.UndisclosedPollBottomNotice( + modifier: Modifier = Modifier +) { Text( modifier = modifier .align(Alignment.Start) diff --git a/libraries/ui-strings/src/main/res/values/localazy.xml b/libraries/ui-strings/src/main/res/values/localazy.xml index 2355e4b603..dfb095d05a 100644 --- a/libraries/ui-strings/src/main/res/values/localazy.xml +++ b/libraries/ui-strings/src/main/res/values/localazy.xml @@ -3,6 +3,8 @@ "Hide password" "Mentions only" "Muted" + "Poll" + "Ended poll" "Send files" "Show password" "User menu"