mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-24 13:08:46 +00:00
Adding UI polish for polls.
This commit is contained in:
committed by
jeffrey-signal
parent
109f651681
commit
303c2ea14a
@@ -1109,7 +1109,6 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
|
||||
}
|
||||
if (MessageRecordUtil.hasPoll(messageRecord)) {
|
||||
styledText.setSpan(new StyleSpan(Typeface.BOLD), 0, styledText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
bodyText.setMaxWidth(readDimen(R.dimen.media_bubble_default_dimens));
|
||||
}
|
||||
styledText = SearchUtil.getHighlightedSpan(locale, STYLE_FACTORY, styledText, searchQuery, SearchUtil.STRICT);
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ private fun Poll(
|
||||
),
|
||||
onClick = onViewVotes,
|
||||
enabled = hasVotes,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally).fillMaxWidth().padding(horizontal = 16.dp)
|
||||
) {
|
||||
Text(
|
||||
text = if (!hasVotes) {
|
||||
|
||||
@@ -4,9 +4,11 @@ import android.os.Bundle
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
@@ -39,6 +41,7 @@ import androidx.core.os.bundleOf
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import org.signal.core.ui.compose.Buttons
|
||||
import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Dividers
|
||||
import org.signal.core.ui.compose.Previews
|
||||
@@ -52,12 +55,14 @@ import org.thoughtcrime.securesms.conversation.clicklisteners.PollVotesFragment.
|
||||
import org.thoughtcrime.securesms.polls.PollOption
|
||||
import org.thoughtcrime.securesms.polls.PollRecord
|
||||
import org.thoughtcrime.securesms.polls.Voter
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.recipients.ui.bottomsheet.RecipientBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.util.viewModel
|
||||
|
||||
/**
|
||||
* Fragment that shows the results for a given poll.
|
||||
*/
|
||||
class PollVotesFragment : ComposeDialogFragment() {
|
||||
class PollVotesFragment : ComposeDialogFragment(), RecipientBottomSheetDialogFragment.Callback {
|
||||
|
||||
companion object {
|
||||
const val MAX_INITIAL_VOTER_COUNT = 5
|
||||
@@ -103,67 +108,74 @@ class PollVotesFragment : ComposeDialogFragment() {
|
||||
onEndPoll = {
|
||||
setFragmentResult(RESULT_KEY, bundleOf(RESULT_KEY to true))
|
||||
dismissAllowingStateLoss()
|
||||
},
|
||||
onRecipientClick = { id ->
|
||||
RecipientBottomSheetDialogFragment.show(childFragmentManager, id, null)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onRecipientBottomSheetDismissed() = Unit
|
||||
|
||||
override fun onMessageClicked() {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun PollResultsScreen(
|
||||
state: PollVotesState,
|
||||
onEndPoll: () -> Unit = {},
|
||||
onRecipientClick: (RecipientId) -> Unit = {},
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
item {
|
||||
Spacer(Modifier.size(16.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.Poll__question),
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
modifier = Modifier.horizontalGutters()
|
||||
)
|
||||
TextField(
|
||||
value = state.poll!!.question,
|
||||
onValueChange = {},
|
||||
modifier = Modifier.padding(top = 12.dp, bottom = 24.dp).horizontalGutters().fillMaxWidth(),
|
||||
colors = TextFieldDefaults.colors(
|
||||
disabledTextColor = MaterialTheme.colorScheme.onSurface,
|
||||
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
disabledIndicatorColor = Color.Transparent
|
||||
),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
enabled = false
|
||||
)
|
||||
}
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
LazyColumn(
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
item {
|
||||
Spacer(Modifier.size(16.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.Poll__question),
|
||||
style = MaterialTheme.typography.titleSmall,
|
||||
modifier = Modifier.horizontalGutters()
|
||||
)
|
||||
TextField(
|
||||
value = state.poll!!.question,
|
||||
onValueChange = {},
|
||||
modifier = Modifier.padding(top = 12.dp, bottom = 24.dp).horizontalGutters().fillMaxWidth(),
|
||||
colors = TextFieldDefaults.colors(
|
||||
disabledTextColor = MaterialTheme.colorScheme.onSurface,
|
||||
disabledContainerColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
disabledIndicatorColor = Color.Transparent
|
||||
),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
enabled = false
|
||||
)
|
||||
}
|
||||
|
||||
itemsIndexed(state.pollOptions) { index, option ->
|
||||
PollOptionSection(option, state.poll!!.hasEnded)
|
||||
if (index != state.pollOptions.lastIndex) {
|
||||
Dividers.Default()
|
||||
itemsIndexed(state.pollOptions) { index, option ->
|
||||
PollOptionSection(option, onRecipientClick)
|
||||
if (index != state.pollOptions.lastIndex) {
|
||||
Dividers.Default()
|
||||
} else if (!state.poll!!.hasEnded) {
|
||||
Spacer(Modifier.size(72.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.isAuthor && !state.poll!!.hasEnded) {
|
||||
item {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onEndPoll)
|
||||
.padding(vertical = 16.dp)
|
||||
.horizontalGutters()
|
||||
) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(id = R.drawable.symbol_stop_24),
|
||||
contentDescription = stringResource(R.string.Poll__end_poll),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
Text(text = stringResource(id = R.string.Poll__end_poll), modifier = Modifier.padding(start = 24.dp), style = MaterialTheme.typography.bodyLarge)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.surface)
|
||||
.padding(16.dp)
|
||||
.align(Alignment.BottomCenter)
|
||||
) {
|
||||
Buttons.MediumTonal(onClick = onEndPoll, modifier = Modifier.fillMaxWidth()) {
|
||||
Text(text = stringResource(id = R.string.Poll__end_poll))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,7 +185,7 @@ private fun PollResultsScreen(
|
||||
@Composable
|
||||
private fun PollOptionSection(
|
||||
option: PollOptionModel,
|
||||
hasEnded: Boolean
|
||||
onRecipientClick: (RecipientId) -> Unit
|
||||
) {
|
||||
var expand by remember { mutableStateOf(false) }
|
||||
val context = LocalContext.current
|
||||
@@ -182,7 +194,7 @@ private fun PollOptionSection(
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(text = option.pollOption.text, modifier = Modifier.weight(1f), style = MaterialTheme.typography.titleSmall)
|
||||
if (option.hasMostVotes && hasEnded) {
|
||||
if (option.hasMostVotes) {
|
||||
Icon(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.symbol_favorite_fill_16),
|
||||
contentDescription = stringResource(R.string.Poll__poll_winner),
|
||||
@@ -205,7 +217,11 @@ private fun PollOptionSection(
|
||||
option.voters.subList(0, MAX_INITIAL_VOTER_COUNT).forEach { recipient ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = 12.dp).horizontalGutters()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = { onRecipientClick(recipient.id) })
|
||||
.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))
|
||||
@@ -228,7 +244,11 @@ private fun PollOptionSection(
|
||||
option.voters.forEach { recipient ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(vertical = 12.dp).horizontalGutters()
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = { onRecipientClick(recipient.id) })
|
||||
.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))
|
||||
|
||||
@@ -34,6 +34,8 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.snapshotFlow
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
@@ -132,6 +134,8 @@ private fun CreatePollScreen(
|
||||
onSend: (String, Boolean, List<String>) -> Unit = { _, _, _ -> },
|
||||
onShowErrorSnackbar: (Boolean, Boolean) -> Unit = { _, _ -> }
|
||||
) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
// Parts of poll
|
||||
var question by remember { mutableStateOf("") }
|
||||
val options = remember { mutableStateListOf("", "") }
|
||||
@@ -177,6 +181,10 @@ private fun CreatePollScreen(
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
focusRequester.requestFocus()
|
||||
}
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
@@ -212,7 +220,8 @@ private fun CreatePollScreen(
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.onFocusChanged { focusState -> if (focusState.isFocused) focusedOption = -1 },
|
||||
.onFocusChanged { focusState -> if (focusState.isFocused) focusedOption = -1 }
|
||||
.focusRequester(focusRequester),
|
||||
countdownThreshold = CreatePollFragment.CHARACTER_COUNTDOWN_THRESHOLD
|
||||
)
|
||||
|
||||
|
||||
@@ -297,6 +297,7 @@ class RecipientBottomSheetDialogFragment : FixedRoundedCornerBottomSheetDialogFr
|
||||
background = DSLSettingsIcon.from(ContextUtil.requireDrawable(requireContext(), R.drawable.selectable_recipient_bottom_sheet_icon_button)),
|
||||
enabled = !viewModel.isDeprecatedOrUnregistered,
|
||||
onMessageClick = {
|
||||
callback?.onMessageClicked()
|
||||
dismiss()
|
||||
viewModel.onMessageClicked(requireActivity())
|
||||
},
|
||||
@@ -449,5 +450,6 @@ class RecipientBottomSheetDialogFragment : FixedRoundedCornerBottomSheetDialogFr
|
||||
|
||||
interface Callback {
|
||||
fun onRecipientBottomSheetDismissed()
|
||||
fun onMessageClicked()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1500,6 +1500,8 @@ class StoryViewerPageFragment :
|
||||
viewModel.setIsDisplayingRecipientBottomSheet(false)
|
||||
}
|
||||
|
||||
override fun onMessageClicked() = Unit
|
||||
|
||||
interface Callback {
|
||||
fun onGoToPreviousStory(recipientId: RecipientId)
|
||||
fun onFinishedPosts(recipientId: RecipientId)
|
||||
|
||||
@@ -233,7 +233,8 @@
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/poll"
|
||||
android:layout_width="@dimen/media_bubble_max_width"
|
||||
android:layout_width="wrap_content"
|
||||
android:maxWidth="@dimen/media_bubble_max_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="-4dp"
|
||||
android:layout="@layout/conversation_item_poll" />
|
||||
|
||||
@@ -174,7 +174,8 @@
|
||||
|
||||
<ViewStub
|
||||
android:id="@+id/poll"
|
||||
android:layout_width="@dimen/media_bubble_max_width"
|
||||
android:layout_width="wrap_content"
|
||||
android:maxWidth="@dimen/media_bubble_max_width"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="-4dp"
|
||||
android:layout="@layout/conversation_item_poll" />
|
||||
|
||||
Reference in New Issue
Block a user