- Improves rendering of the completed polls

- Doesn't render quoted polls
This commit is contained in:
Vitor Pamplona
2026-03-23 18:01:41 -04:00
parent e5aeb49a4b
commit 4c9f2de6f7
@@ -36,6 +36,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material3.Button import androidx.compose.material3.Button
import androidx.compose.material3.Checkbox 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.draw.drawWithContent
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.drawscope.clipRect 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.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp 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.screen.loggedIn.mockAccountViewModel
import com.vitorpamplona.amethyst.ui.stringRes import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.BigPadding 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.Size25dp
import com.vitorpamplona.amethyst.ui.theme.SmallishBorder 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.SpacedBy5dp
import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer
import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn import com.vitorpamplona.amethyst.ui.theme.ThemeComparisonColumn
import com.vitorpamplona.amethyst.ui.theme.allGoodColor import com.vitorpamplona.amethyst.ui.theme.allGoodColor
import com.vitorpamplona.amethyst.ui.theme.grayText import com.vitorpamplona.amethyst.ui.theme.grayText
@@ -174,11 +180,11 @@ fun InnerRenderPoll(
}, },
) )
}, },
) { code, label -> ) { code, label, closed ->
TranslatableRichTextViewer( TranslatableRichTextViewer(
content = label, content = label,
canPreview = canPreview, canPreview = canPreview,
quotesLeft = 1, quotesLeft = if (quotesLeft > 0) 1 else 0,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
tags = tags, tags = tags,
backgroundColor = backgroundColor, backgroundColor = backgroundColor,
@@ -221,7 +227,7 @@ fun RenderPollCard(
pollState: PollResponsesCache, pollState: PollResponsesCache,
accountViewModel: AccountViewModel, accountViewModel: AccountViewModel,
galleryUser: @Composable RowScope.(user: User) -> Unit, 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 = val card =
remember(event) { remember(event) {
@@ -274,7 +280,7 @@ fun RenderPollCard(
card: PollCard, card: PollCard,
onRespond: (Set<String>) -> Unit, onRespond: (Set<String>) -> Unit,
resultContent: @Composable RowScope.(user: User) -> 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( Column(
verticalArrangement = SpacedBy5dp, verticalArrangement = SpacedBy5dp,
@@ -306,7 +312,7 @@ fun RenderPollCard(
@Composable @Composable
private fun ColumnScope.RenderSingleChoiceOptions( private fun ColumnScope.RenderSingleChoiceOptions(
card: PollCard, card: PollCard,
labelContent: @Composable (ColumnScope.(String, String) -> Unit), labelContent: @Composable (ColumnScope.(String, String, closed: Boolean) -> Unit),
onRespond: (Set<String>) -> Unit, onRespond: (Set<String>) -> Unit,
) { ) {
card.options.forEach { card.options.forEach {
@@ -333,7 +339,7 @@ private fun ColumnScope.RenderSingleChoiceOptions(
Modifier Modifier
.fillMaxWidth(), .fillMaxWidth(),
) { ) {
labelContent(it.code, it.label) labelContent(it.code, it.label, false)
} }
} }
} }
@@ -343,7 +349,7 @@ private fun ColumnScope.RenderSingleChoiceOptions(
@Composable @Composable
private fun ColumnScope.RenderMultiChoiceOptions( private fun ColumnScope.RenderMultiChoiceOptions(
card: PollCard, card: PollCard,
labelContent: @Composable (ColumnScope.(String, String) -> Unit), labelContent: @Composable (ColumnScope.(String, String, closed: Boolean) -> Unit),
onRespond: (Set<String>) -> Unit, onRespond: (Set<String>) -> Unit,
) { ) {
var multichoice by var multichoice by
@@ -380,7 +386,7 @@ private fun ColumnScope.RenderMultiChoiceOptions(
Column( Column(
modifier = Modifier.weight(1f), 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( private fun RenderResults(
card: PollCard, card: PollCard,
resultContent: @Composable RowScope.(user: User) -> 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),
) { ) {
card.options.forEach { pollItem -> card.options.forEach { pollItem ->
RenderClosedItem(pollItem, resultContent) { 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()) val tally by item.results.collectAsStateWithLifecycle(item.currentResults())
RenderClosedItem(tally, resultContent, labelContent) RenderClosedItem(tally, item.label, resultContent, labelContent)
} }
@Composable @Composable
private fun RenderClosedItem( private fun RenderClosedItem(
tally: TallyResults, tally: TallyResults,
label: String,
resultContent: @Composable RowScope.(user: User) -> Unit, resultContent: @Composable RowScope.(user: User) -> Unit,
labelContent: @Composable ColumnScope.() -> Unit, labelContent: @Composable ColumnScope.() -> Unit,
) { ) {
@@ -481,18 +488,21 @@ private fun RenderClosedItem(
content = labelContent, content = labelContent,
) )
Spacer(StdHorzSpacer) Spacer(DoubleHorzSpacer)
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = SpacedBy10dp,
) { ) {
UserGallery(tally, resultContent) if (label.length < 30) {
UserGallery(tally, resultContent)
}
Text( Text(
text = "${(tally.percent * 100).toInt()}%", text = "${(tally.percent * 100).toInt()}%",
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
textAlign = TextAlign.End,
modifier = measure100PercentWidthModifier(MaterialTheme.typography.bodyMedium),
maxLines = 1, 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 @Composable
fun UserGallery( fun UserGallery(
tally: TallyResults, tally: TallyResults,
@@ -510,13 +538,13 @@ fun UserGallery(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy((-10).dp), horizontalArrangement = Arrangement.spacedBy((-10).dp),
) { ) {
tally.users.take(6).forEach { tally.users.take(4).forEach {
key(it.pubkeyHex) { key(it.pubkeyHex) {
galleryUser(it) galleryUser(it)
} }
} }
if (tally.users.size > 6) { if (tally.users.size > 4) {
Box( Box(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
modifier = modifier =
@@ -526,7 +554,7 @@ fun UserGallery(
.background(MaterialTheme.colorScheme.secondaryContainer), .background(MaterialTheme.colorScheme.secondaryContainer),
) { ) {
Text( Text(
text = "+" + showCount(tally.users.size - 6), text = "+" + showCount(tally.users.size - 4),
fontSize = 10.sp, fontSize = 10.sp,
color = MaterialTheme.colorScheme.onSurface, color = MaterialTheme.colorScheme.onSurface,
) )
@@ -575,7 +603,55 @@ fun RenderPollManualPreview() {
ThemeComparisonColumn { ThemeComparisonColumn {
Column(Modifier.padding(10.dp)) { 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(
text = label, text = label,
) )