mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-15 07:28:30 +00:00
Update UI when viewing votes.
This commit is contained in:
committed by
Cody Henthorne
parent
e4abc6d256
commit
1544cb81d5
@@ -11,8 +11,9 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
@@ -26,6 +27,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
@@ -38,6 +40,7 @@ import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Dividers
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.Scaffolds
|
||||
import org.signal.core.ui.compose.horizontalGutters
|
||||
@@ -85,7 +88,7 @@ class PollVotesFragment : ComposeDialogFragment() {
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
|
||||
Scaffolds.Settings(
|
||||
title = stringResource(id = R.string.Poll__poll_results),
|
||||
title = stringResource(if (state.poll?.hasEnded == true) R.string.Poll__poll_results else R.string.Poll__poll_details),
|
||||
onNavigationClick = this::dismissAllowingStateLoss,
|
||||
navigationIcon = ImageVector.vectorResource(id = R.drawable.symbol_x_24),
|
||||
navigationContentDescription = stringResource(id = R.string.Material3SearchToolbar__close)
|
||||
@@ -117,27 +120,34 @@ private fun PollResultsScreen(
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.horizontalGutters(24.dp)
|
||||
) {
|
||||
item {
|
||||
Spacer(Modifier.size(16.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.Poll__question),
|
||||
style = MaterialTheme.typography.titleSmall
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
modifier = Modifier.horizontalGutters()
|
||||
)
|
||||
TextField(
|
||||
value = state.poll!!.question,
|
||||
onValueChange = {},
|
||||
modifier = Modifier.padding(top = 12.dp, bottom = 24.dp).fillMaxWidth(),
|
||||
modifier = Modifier.padding(top = 12.dp, bottom = 24.dp).horizontalGutters().fillMaxWidth(),
|
||||
colors = TextFieldDefaults.colors(
|
||||
disabledTextColor = MaterialTheme.colorScheme.onSurface,
|
||||
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant
|
||||
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
disabledIndicatorColor = Color.Transparent
|
||||
),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
enabled = false
|
||||
)
|
||||
}
|
||||
|
||||
items(state.pollOptions) { PollOptionSection(it) }
|
||||
itemsIndexed(state.pollOptions) { index, option ->
|
||||
PollOptionSection(option, state.poll!!.hasEnded)
|
||||
if (index != state.pollOptions.lastIndex) {
|
||||
Dividers.Default()
|
||||
}
|
||||
}
|
||||
|
||||
if (state.isAuthor && !state.poll!!.hasEnded) {
|
||||
item {
|
||||
@@ -146,9 +156,10 @@ private fun PollResultsScreen(
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onEndPoll)
|
||||
.padding(vertical = 16.dp)
|
||||
.horizontalGutters()
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.symbol_trash_24),
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.symbol_stop_24),
|
||||
contentDescription = stringResource(R.string.Poll__end_poll),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
@@ -161,22 +172,40 @@ private fun PollResultsScreen(
|
||||
|
||||
@Composable
|
||||
private fun PollOptionSection(
|
||||
option: PollOptionModel
|
||||
option: PollOptionModel,
|
||||
hasEnded: Boolean
|
||||
) {
|
||||
var expand by remember { mutableStateOf(false) }
|
||||
val context = LocalContext.current
|
||||
Row(
|
||||
modifier = Modifier.padding(vertical = 12.dp)
|
||||
modifier = Modifier.padding(vertical = 12.dp).horizontalGutters(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(text = option.pollOption.text, modifier = Modifier.weight(1f), style = MaterialTheme.typography.titleSmall)
|
||||
Text(text = pluralStringResource(R.plurals.Poll__num_votes, option.voters.size, option.voters.size), style = MaterialTheme.typography.bodyLarge)
|
||||
if (option.hasMostVotes && hasEnded) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.symbol_favorite_fill_16),
|
||||
contentDescription = stringResource(R.string.Poll__poll_winner),
|
||||
modifier = Modifier.padding(2.dp)
|
||||
)
|
||||
}
|
||||
if (option.voters.isNotEmpty()) {
|
||||
Text(text = pluralStringResource(R.plurals.Poll__num_votes, option.voters.size, option.voters.size), style = MaterialTheme.typography.bodyLarge)
|
||||
}
|
||||
}
|
||||
|
||||
if (!expand && option.voters.size > MAX_INITIAL_VOTER_COUNT) {
|
||||
if (option.voters.isEmpty()) {
|
||||
Text(
|
||||
text = stringResource(R.string.Poll__no_votes),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.horizontalGutters()
|
||||
)
|
||||
} else if (!expand && option.voters.size > MAX_INITIAL_VOTER_COUNT) {
|
||||
option.voters.subList(0, MAX_INITIAL_VOTER_COUNT).forEach { recipient ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = 12.dp)
|
||||
modifier = Modifier.padding(vertical = 12.dp).horizontalGutters()
|
||||
) {
|
||||
AvatarImage(recipient = recipient, modifier = Modifier.padding(end = 16.dp).size(40.dp))
|
||||
Text(text = if (recipient.isSelf) stringResource(id = R.string.Recipient_you) else recipient.getShortDisplayName(context))
|
||||
@@ -185,7 +214,7 @@ private fun PollOptionSection(
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = 12.dp).clickable { expand = true }
|
||||
modifier = Modifier.padding(vertical = 12.dp).horizontalGutters().clickable { expand = true }
|
||||
) {
|
||||
Image(
|
||||
colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.onSurface),
|
||||
@@ -199,7 +228,7 @@ private fun PollOptionSection(
|
||||
option.voters.forEach { recipient ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = 12.dp)
|
||||
modifier = Modifier.padding(vertical = 12.dp).horizontalGutters()
|
||||
) {
|
||||
AvatarImage(recipient = recipient, modifier = Modifier.padding(end = 16.dp).size(40.dp))
|
||||
Text(text = if (recipient.isSelf) stringResource(id = R.string.Recipient_you) else recipient.getShortDisplayName(context))
|
||||
|
||||
@@ -33,13 +33,15 @@ class PollVotesViewModel(pollId: Long) : ViewModel() {
|
||||
private fun loadPollInfo(pollId: Long) {
|
||||
viewModelScope.launch(SignalDispatchers.IO) {
|
||||
val poll = SignalDatabase.polls.getPollFromId(pollId)!!
|
||||
val mostVotes = poll.pollOptions.maxByOrNull { option -> option.voters.size }?.voters?.size
|
||||
_state.update {
|
||||
it.copy(
|
||||
poll = poll,
|
||||
pollOptions = poll.pollOptions.map { option ->
|
||||
PollOptionModel(
|
||||
pollOption = option,
|
||||
voters = Recipient.resolvedList(option.voters.map { voter -> RecipientId.from(voter.id) })
|
||||
voters = Recipient.resolvedList(option.voters.map { voter -> RecipientId.from(voter.id) }),
|
||||
hasMostVotes = option.voters.size == mostVotes
|
||||
)
|
||||
},
|
||||
isAuthor = poll.authorId == Recipient.self().id.toLong()
|
||||
@@ -57,5 +59,6 @@ data class PollVotesState(
|
||||
|
||||
data class PollOptionModel(
|
||||
val pollOption: PollOption,
|
||||
val voters: List<Recipient> = emptyList()
|
||||
val voters: List<Recipient> = emptyList(),
|
||||
val hasMostVotes: Boolean
|
||||
)
|
||||
|
||||
9
app/src/main/res/drawable/symbol_favorite_fill_16.xml
Normal file
9
app/src/main/res/drawable/symbol_favorite_fill_16.xml
Normal file
@@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="16dp"
|
||||
android:height="15dp"
|
||||
android:viewportWidth="16"
|
||||
android:viewportHeight="15">
|
||||
<path
|
||||
android:pathData="M8.951,1.348C8.652,0.427 7.348,0.427 7.049,1.348L5.887,4.925C5.842,5.062 5.714,5.155 5.57,5.155H1.809C0.841,5.155 0.438,6.395 1.222,6.964L4.264,9.174C4.381,9.259 4.43,9.41 4.385,9.547L3.223,13.124C2.924,14.045 3.978,14.811 4.762,14.242L7.804,12.031C7.921,11.946 8.079,11.946 8.196,12.031L11.238,14.242C12.022,14.811 13.076,14.045 12.777,13.124L11.615,9.547C11.57,9.41 11.619,9.259 11.736,9.174L14.778,6.964C15.562,6.395 15.159,5.155 14.191,5.155H10.43C10.286,5.155 10.158,5.062 10.113,4.925L8.951,1.348Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
||||
@@ -8809,8 +8809,10 @@
|
||||
<string name="Poll__poll_voted">%1$s voted in the poll: \"%2$s\"</string>
|
||||
<!-- Option in settings to configure notifications for polls -->
|
||||
<string name="Poll__poll">Polls</string>
|
||||
<!-- Title of screen that shows the poll results of a poll -->
|
||||
<!-- Title of screen that shows the poll results of a poll after it has ended-->
|
||||
<string name="Poll__poll_results">Poll results</string>
|
||||
<!-- Title of screen that shows the poll details of a poll -->
|
||||
<string name="Poll__poll_details">Poll details</string>
|
||||
<!-- Header text displaying the question of the poll -->
|
||||
<string name="Poll__question">Question</string>
|
||||
<!-- Text displaying how many votes, %1$d, an option has gotten -->
|
||||
@@ -8818,6 +8820,8 @@
|
||||
<item quantity="one">%1$d vote</item>
|
||||
<item quantity="other">%1$d votes</item>
|
||||
</plurals>
|
||||
<!-- Content description to describe the icon that is shown next to the winning option when the poll ends -->
|
||||
<string name="Poll__poll_winner">Winner</string>
|
||||
<!-- Text that when pressed will end the poll -->
|
||||
<string name="Poll__end_poll">End poll</string>
|
||||
<!-- Button that once pressed will show all of the voters for a poll -->
|
||||
|
||||
Reference in New Issue
Block a user