diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java index 5cb5c24dfc..7e1b4e43fc 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationItem.java @@ -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); diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/PollComponent.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/PollComponent.kt index d7625a6205..2ab7338be6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/PollComponent.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/PollComponent.kt @@ -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) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/clicklisteners/PollVotesFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/clicklisteners/PollVotesFragment.kt index e51a1266e1..9e2fcc402c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/clicklisteners/PollVotesFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/clicklisteners/PollVotesFragment.kt @@ -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)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/CreatePollFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/CreatePollFragment.kt index 8ce249e7c7..76681bb6b6 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/CreatePollFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/CreatePollFragment.kt @@ -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) -> 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 ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.kt index c02a478bce..280b3b1f9c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/recipients/ui/bottomsheet/RecipientBottomSheetDialogFragment.kt @@ -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() } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageFragment.kt index 70813b8ee9..2c46e2e688 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/page/StoryViewerPageFragment.kt @@ -1500,6 +1500,8 @@ class StoryViewerPageFragment : viewModel.setIsDisplayingRecipientBottomSheet(false) } + override fun onMessageClicked() = Unit + interface Callback { fun onGoToPreviousStory(recipientId: RecipientId) fun onFinishedPosts(recipientId: RecipientId) diff --git a/app/src/main/res/layout/conversation_item_received_multimedia.xml b/app/src/main/res/layout/conversation_item_received_multimedia.xml index 666ad9c841..71c707915b 100644 --- a/app/src/main/res/layout/conversation_item_received_multimedia.xml +++ b/app/src/main/res/layout/conversation_item_received_multimedia.xml @@ -233,7 +233,8 @@ diff --git a/app/src/main/res/layout/conversation_item_sent_multimedia.xml b/app/src/main/res/layout/conversation_item_sent_multimedia.xml index 89361d78ec..937f424f80 100644 --- a/app/src/main/res/layout/conversation_item_sent_multimedia.xml +++ b/app/src/main/res/layout/conversation_item_sent_multimedia.xml @@ -174,7 +174,8 @@