diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt index 949b92473..dc302597b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/types/Poll.kt @@ -36,6 +36,7 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.CircleShape import androidx.compose.material3.Button import androidx.compose.material3.Checkbox @@ -56,7 +57,13 @@ import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawWithContent import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.drawscope.clipRect +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.platform.LocalFontFamilyResolver +import androidx.compose.ui.platform.LocalLayoutDirection +import androidx.compose.ui.text.TextMeasurer +import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp @@ -82,11 +89,10 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel import com.vitorpamplona.amethyst.ui.screen.loggedIn.mockAccountViewModel import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.theme.BigPadding +import com.vitorpamplona.amethyst.ui.theme.DoubleHorzSpacer import com.vitorpamplona.amethyst.ui.theme.Size25dp import com.vitorpamplona.amethyst.ui.theme.SmallishBorder -import com.vitorpamplona.amethyst.ui.theme.SpacedBy10dp import com.vitorpamplona.amethyst.ui.theme.SpacedBy5dp -import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.ui.theme.allGoodColor import com.vitorpamplona.amethyst.ui.theme.grayText @@ -174,11 +180,11 @@ fun InnerRenderPoll( }, ) }, - ) { code, label -> + ) { code, label, closed -> TranslatableRichTextViewer( content = label, canPreview = canPreview, - quotesLeft = 1, + quotesLeft = if (quotesLeft > 0) 1 else 0, modifier = Modifier.fillMaxWidth(), tags = tags, backgroundColor = backgroundColor, @@ -221,7 +227,7 @@ fun RenderPollCard( pollState: PollResponsesCache, accountViewModel: AccountViewModel, galleryUser: @Composable RowScope.(user: User) -> Unit, - labelContent: @Composable ColumnScope.(code: String, label: String) -> Unit, + labelContent: @Composable ColumnScope.(code: String, label: String, closed: Boolean) -> Unit, ) { val card = remember(event) { @@ -274,7 +280,7 @@ fun RenderPollCard( card: PollCard, onRespond: (Set) -> Unit, resultContent: @Composable RowScope.(user: User) -> Unit, - labelContent: @Composable ColumnScope.(code: String, label: String) -> Unit, + labelContent: @Composable ColumnScope.(code: String, label: String, closed: Boolean) -> Unit, ) { Column( verticalArrangement = SpacedBy5dp, @@ -306,7 +312,7 @@ fun RenderPollCard( @Composable private fun ColumnScope.RenderSingleChoiceOptions( card: PollCard, - labelContent: @Composable (ColumnScope.(String, String) -> Unit), + labelContent: @Composable (ColumnScope.(String, String, closed: Boolean) -> Unit), onRespond: (Set) -> Unit, ) { card.options.forEach { @@ -333,7 +339,7 @@ private fun ColumnScope.RenderSingleChoiceOptions( Modifier .fillMaxWidth(), ) { - labelContent(it.code, it.label) + labelContent(it.code, it.label, false) } } } @@ -343,7 +349,7 @@ private fun ColumnScope.RenderSingleChoiceOptions( @Composable private fun ColumnScope.RenderMultiChoiceOptions( card: PollCard, - labelContent: @Composable (ColumnScope.(String, String) -> Unit), + labelContent: @Composable (ColumnScope.(String, String, closed: Boolean) -> Unit), onRespond: (Set) -> Unit, ) { var multichoice by @@ -380,7 +386,7 @@ private fun ColumnScope.RenderMultiChoiceOptions( Column( modifier = Modifier.weight(1f), ) { - labelContent(option.code, option.label) + labelContent(option.code, option.label, false) } } } @@ -401,11 +407,11 @@ private fun ColumnScope.RenderMultiChoiceOptions( private fun RenderResults( card: PollCard, resultContent: @Composable RowScope.(user: User) -> Unit, - labelContent: @Composable (ColumnScope.(code: String, label: String) -> Unit), + labelContent: @Composable (ColumnScope.(code: String, label: String, closed: Boolean) -> Unit), ) { card.options.forEach { pollItem -> RenderClosedItem(pollItem, resultContent) { - labelContent(pollItem.code, pollItem.label) + labelContent(pollItem.code, pollItem.label, true) } } } @@ -418,12 +424,13 @@ private fun RenderClosedItem( ) { val tally by item.results.collectAsStateWithLifecycle(item.currentResults()) - RenderClosedItem(tally, resultContent, labelContent) + RenderClosedItem(tally, item.label, resultContent, labelContent) } @Composable private fun RenderClosedItem( tally: TallyResults, + label: String, resultContent: @Composable RowScope.(user: User) -> Unit, labelContent: @Composable ColumnScope.() -> Unit, ) { @@ -481,18 +488,21 @@ private fun RenderClosedItem( content = labelContent, ) - Spacer(StdHorzSpacer) + Spacer(DoubleHorzSpacer) Row( verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = SpacedBy10dp, ) { - UserGallery(tally, resultContent) + if (label.length < 30) { + UserGallery(tally, resultContent) + } Text( text = "${(tally.percent * 100).toInt()}%", style = MaterialTheme.typography.bodyMedium, fontWeight = FontWeight.Bold, + textAlign = TextAlign.End, + modifier = measure100PercentWidthModifier(MaterialTheme.typography.bodyMedium), maxLines = 1, ) } @@ -500,6 +510,24 @@ private fun RenderClosedItem( } } +@Composable +fun measure100PercentWidthModifier(textStyle: TextStyle): Modifier { + val fontFamilyResolver = LocalFontFamilyResolver.current + val density = LocalDensity.current + val layoutDirection = LocalLayoutDirection.current + + return remember(fontFamilyResolver, density, layoutDirection, textStyle) { + val widthPx = + TextMeasurer(fontFamilyResolver, density, layoutDirection, 1) + .measure("100%", style = textStyle.copy(fontWeight = FontWeight.Bold)) + .size + .width + with(density) { + Modifier.width(widthPx.toDp()) + } + } +} + @Composable fun UserGallery( tally: TallyResults, @@ -510,13 +538,13 @@ fun UserGallery( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy((-10).dp), ) { - tally.users.take(6).forEach { + tally.users.take(4).forEach { key(it.pubkeyHex) { galleryUser(it) } } - if (tally.users.size > 6) { + if (tally.users.size > 4) { Box( contentAlignment = Alignment.Center, modifier = @@ -526,7 +554,7 @@ fun UserGallery( .background(MaterialTheme.colorScheme.secondaryContainer), ) { Text( - text = "+" + showCount(tally.users.size - 6), + text = "+" + showCount(tally.users.size - 4), fontSize = 10.sp, color = MaterialTheme.colorScheme.onSurface, ) @@ -575,7 +603,55 @@ fun RenderPollManualPreview() { ThemeComparisonColumn { Column(Modifier.padding(10.dp)) { - RenderPollCard(poll, {}, {}) { _, label -> + RenderPollCard(poll, {}, {}) { _, label, closed -> + Text( + text = label, + ) + } + } + } +} + +@Preview +@Composable +fun RenderPollManualLongPreview() { + val poll = + PollCard( + options = + listOf( + PollItemCard( + code = "1", + label = "Yes".repeat(300), + results = flow {}, + currentResults = { + TallyResults( + percent = 1.0f, + isWinning = true, + ) + }, + ), + PollItemCard( + code = "2", + label = "No".repeat(300), + results = flow {}, + currentResults = { + TallyResults( + percent = 0.0f, + isWinning = false, + ) + }, + ), + ), + type = PollType.SINGLE_CHOICE, + endsAt = null, + isMyPoll = true, + haveIVotedFlow = flow {}, + haveIVoted = { true }, + ) + + ThemeComparisonColumn { + Column(Modifier.padding(10.dp)) { + RenderPollCard(poll, {}, {}) { _, label, closed -> Text( text = label, )