mirror of
https://github.com/ProtonMail/android-mail.git
synced 2026-05-15 09:50:40 +00:00
Add copy address and message actions to RsvpWidget
ET-4189
This commit is contained in:
committed by
MargeBot
parent
7aec1bcb31
commit
fb818f5658
+10
-5
@@ -272,9 +272,12 @@ private fun ColumnScope.ConversationDetailExpandedItem(
|
||||
onRetry = { actions.onRetryRsvpEventLoading(uiModel.messageId) }
|
||||
)
|
||||
is RsvpWidgetUiModel.Shown -> RsvpWidget(
|
||||
uiModel.messageRsvpWidgetUiModel.event,
|
||||
{ actions.onOpenInProtonCalendar(uiModel.messageId) },
|
||||
{ actions.onAnswerRsvpEvent(uiModel.messageId, it) }
|
||||
uiModel = uiModel.messageRsvpWidgetUiModel.event,
|
||||
actions = RsvpWidget.Actions(
|
||||
onOpenInProtonCalendar = { actions.onOpenInProtonCalendar(uiModel.messageId) },
|
||||
onAnswerRsvpEvent = { actions.onAnswerRsvpEvent(uiModel.messageId, it) },
|
||||
onMessage = actions.onMessage
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -390,7 +393,8 @@ object ConversationDetailItem {
|
||||
val onUnblockSender: (MessageIdUiModel, String) -> Unit,
|
||||
val onEditScheduleSendMessage: (MessageIdUiModel) -> Unit,
|
||||
val onRetryRsvpEventLoading: (MessageIdUiModel) -> Unit,
|
||||
val onAnswerRsvpEvent: (MessageIdUiModel, RsvpAnswer) -> Unit
|
||||
val onAnswerRsvpEvent: (MessageIdUiModel, RsvpAnswer) -> Unit,
|
||||
val onMessage: (String) -> Unit
|
||||
)
|
||||
|
||||
val previewActions = Actions(
|
||||
@@ -422,7 +426,8 @@ object ConversationDetailItem {
|
||||
{ model: MessageIdUiModel, string: String -> },
|
||||
{ model: MessageIdUiModel -> },
|
||||
{},
|
||||
{ _, _ -> }
|
||||
{ _, _ -> },
|
||||
{}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+8
-4
@@ -523,7 +523,8 @@ fun ConversationDetailScreen(
|
||||
},
|
||||
onAnswerRsvpEvent = { messageId, answer ->
|
||||
viewModel.submit(ConversationDetailViewAction.AnswerRsvpEvent(MessageId(messageId.id), answer))
|
||||
}
|
||||
},
|
||||
onMessage = actions.onComposeNewMessage
|
||||
),
|
||||
scrollToMessageId = state.scrollToMessage?.id
|
||||
)
|
||||
@@ -725,7 +726,8 @@ fun ConversationDetailScreen(
|
||||
onUnblockSender = actions.onUnblockSender,
|
||||
onEditScheduleSendMessage = actions.onEditScheduleSendMessage,
|
||||
onRetryRsvpEventLoading = actions.onRetryRsvpEventLoading,
|
||||
onAnswerRsvpEvent = actions.onAnswerRsvpEvent
|
||||
onAnswerRsvpEvent = actions.onAnswerRsvpEvent,
|
||||
onMessage = actions.onMessage
|
||||
)
|
||||
MessagesContentWithHiddenEdges(
|
||||
uiModels = state.messagesState.messages,
|
||||
@@ -1092,7 +1094,8 @@ object ConversationDetailScreen {
|
||||
val onEditScheduleSendMessage: (MessageIdUiModel) -> Unit,
|
||||
val onExitWithOpenInComposer: (MessageIdUiModel) -> Unit,
|
||||
val onRetryRsvpEventLoading: (MessageIdUiModel) -> Unit,
|
||||
val onAnswerRsvpEvent: (MessageIdUiModel, RsvpAnswer) -> Unit
|
||||
val onAnswerRsvpEvent: (MessageIdUiModel, RsvpAnswer) -> Unit,
|
||||
val onMessage: (String) -> Unit
|
||||
) {
|
||||
|
||||
companion object {
|
||||
@@ -1145,7 +1148,8 @@ object ConversationDetailScreen {
|
||||
onEditScheduleSendMessage = {},
|
||||
onExitWithOpenInComposer = {},
|
||||
onRetryRsvpEventLoading = {},
|
||||
onAnswerRsvpEvent = { _, _ -> }
|
||||
onAnswerRsvpEvent = { _, _ -> },
|
||||
onMessage = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+115
-16
@@ -47,6 +47,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@@ -62,6 +63,7 @@ import ch.protonmail.android.design.compose.theme.labelMediumNorm
|
||||
import ch.protonmail.android.design.compose.theme.titleLargeNorm
|
||||
import ch.protonmail.android.mailcommon.presentation.NO_CONTENT_DESCRIPTION
|
||||
import ch.protonmail.android.mailcommon.presentation.compose.MailDimens
|
||||
import ch.protonmail.android.mailcommon.presentation.extension.copyTextToClipboard
|
||||
import ch.protonmail.android.mailcommon.presentation.model.TextUiModel
|
||||
import ch.protonmail.android.mailcommon.presentation.model.string
|
||||
import ch.protonmail.android.maildetail.presentation.R
|
||||
@@ -76,10 +78,11 @@ import ch.protonmail.android.mailmessage.domain.model.RsvpAnswer
|
||||
@Composable
|
||||
fun RsvpWidget(
|
||||
uiModel: RsvpEventUiModel,
|
||||
onOpenInProtonCalendar: () -> Unit,
|
||||
onAnswerRsvpEvent: (RsvpAnswer) -> Unit,
|
||||
actions: RsvpWidget.Actions,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
|
||||
Column(
|
||||
modifier = modifier
|
||||
.padding(horizontal = ProtonDimens.Spacing.Large)
|
||||
@@ -105,10 +108,10 @@ fun RsvpWidget(
|
||||
title = uiModel.title,
|
||||
dateTime = uiModel.dateTime,
|
||||
isAttendanceOptional = uiModel.isAttendanceOptional,
|
||||
onOpenInProtonCalendar = onOpenInProtonCalendar
|
||||
onOpenInProtonCalendar = actions.onOpenInProtonCalendar
|
||||
)
|
||||
|
||||
RsvpResponse(uiModel.buttons, onAnswerRsvpEvent)
|
||||
RsvpResponse(uiModel.buttons, actions.onAnswerRsvpEvent)
|
||||
Spacer(modifier = Modifier.size(ProtonDimens.Spacing.Large))
|
||||
|
||||
uiModel.calendar?.let {
|
||||
@@ -134,12 +137,15 @@ fun RsvpWidget(
|
||||
}
|
||||
|
||||
val organizerName = (uiModel.organizer.name ?: uiModel.organizer.email).string()
|
||||
RsvpDetailsRow(
|
||||
val organizerEmail = uiModel.organizer.email.string()
|
||||
RsvpParticipantRow(
|
||||
icon = R.drawable.ic_proton_user,
|
||||
text = "$organizerName ${stringResource(id = R.string.rsvp_widget_organizer)}"
|
||||
text = "$organizerName ${stringResource(id = R.string.rsvp_widget_organizer)}",
|
||||
onCopyAddress = { context.copyTextToClipboard("Email", organizerEmail) },
|
||||
onMessage = { actions.onMessage(organizerEmail) }
|
||||
)
|
||||
|
||||
RsvpAttendees(uiModel.attendees)
|
||||
RsvpAttendees(uiModel.attendees, actions.onMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -446,9 +452,81 @@ private fun RsvpDetailsRow(
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RsvpAttendees(attendees: List<RsvpAttendeeUiModel>) {
|
||||
private fun RsvpParticipantRow(
|
||||
@DrawableRes icon: Int,
|
||||
text: String,
|
||||
onCopyAddress: () -> Unit,
|
||||
onMessage: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
iconTint: Color = ProtonTheme.colors.iconWeak
|
||||
) {
|
||||
Row {
|
||||
val expanded = remember { mutableStateOf(false) }
|
||||
|
||||
RsvpDetailsRow(
|
||||
modifier = modifier
|
||||
.clip(ProtonTheme.shapes.mediumLarge)
|
||||
.clickable(
|
||||
onClick = { expanded.value = !expanded.value }
|
||||
),
|
||||
icon = icon,
|
||||
text = text,
|
||||
iconTint = iconTint
|
||||
)
|
||||
|
||||
DropdownMenu(
|
||||
expanded = expanded.value,
|
||||
onDismissRequest = { expanded.value = false },
|
||||
containerColor = ProtonTheme.colors.backgroundNorm
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_proton_squares),
|
||||
contentDescription = NO_CONTENT_DESCRIPTION
|
||||
)
|
||||
Spacer(modifier = Modifier.size(ProtonDimens.Spacing.Standard))
|
||||
Text(
|
||||
text = stringResource(id = R.string.rsvp_widget_copy_address),
|
||||
style = ProtonTheme.typography.bodyLargeNorm
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
expanded.value = false
|
||||
onCopyAddress()
|
||||
}
|
||||
)
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_proton_pen_square),
|
||||
contentDescription = NO_CONTENT_DESCRIPTION
|
||||
)
|
||||
Spacer(modifier = Modifier.size(ProtonDimens.Spacing.Standard))
|
||||
Text(
|
||||
text = stringResource(id = R.string.rsvp_widget_message),
|
||||
style = ProtonTheme.typography.bodyLargeNorm
|
||||
)
|
||||
}
|
||||
},
|
||||
onClick = {
|
||||
expanded.value = false
|
||||
onMessage()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RsvpAttendees(attendees: List<RsvpAttendeeUiModel>, onMessage: (String) -> Unit) {
|
||||
if (attendees.isEmpty()) return
|
||||
|
||||
val context = LocalContext.current
|
||||
|
||||
if (attendees.size == 1) {
|
||||
val attendee = attendees.first()
|
||||
val text = if (attendee.name == null) {
|
||||
@@ -457,10 +535,13 @@ private fun RsvpAttendees(attendees: List<RsvpAttendeeUiModel>) {
|
||||
"${attendee.name.string()} • ${attendee.email.string()}"
|
||||
}
|
||||
|
||||
RsvpDetailsRow(
|
||||
val attendeeEmail = attendee.email.string()
|
||||
RsvpParticipantRow(
|
||||
icon = attendee.answer.getIcon(isOnlyAttendee = true),
|
||||
text = text,
|
||||
iconTint = attendee.answer.getIconTint(isOnlyAttendee = true)
|
||||
iconTint = attendee.answer.getIconTint(isOnlyAttendee = true),
|
||||
onCopyAddress = { context.copyTextToClipboard("Email", attendeeEmail) },
|
||||
onMessage = { onMessage(attendeeEmail) }
|
||||
)
|
||||
} else {
|
||||
val isExpanded = remember { mutableStateOf(false) }
|
||||
@@ -493,10 +574,13 @@ private fun RsvpAttendees(attendees: List<RsvpAttendeeUiModel>) {
|
||||
"${attendee.name.string()} • ${attendee.email.string()}"
|
||||
}
|
||||
|
||||
RsvpDetailsRow(
|
||||
val attendeeEmail = attendee.email.string()
|
||||
RsvpParticipantRow(
|
||||
icon = attendee.answer.getIcon(isOnlyAttendee = false),
|
||||
text = text,
|
||||
iconTint = attendee.answer.getIconTint(isOnlyAttendee = false)
|
||||
iconTint = attendee.answer.getIconTint(isOnlyAttendee = false),
|
||||
onCopyAddress = { context.copyTextToClipboard("Email", attendeeEmail) },
|
||||
onMessage = { onMessage(attendeeEmail) }
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -570,8 +654,11 @@ private fun RsvpStatusUiModel.getBackgroundColor() = when (this) {
|
||||
fun RsvpWidgetUnansweredPreview() {
|
||||
RsvpWidget(
|
||||
uiModel = RsvpWidgetPreviewData.UnansweredWithMultipleParticipants,
|
||||
onOpenInProtonCalendar = {},
|
||||
onAnswerRsvpEvent = {}
|
||||
actions = RsvpWidget.Actions(
|
||||
onOpenInProtonCalendar = {},
|
||||
onAnswerRsvpEvent = {},
|
||||
onMessage = {}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -580,7 +667,19 @@ fun RsvpWidgetUnansweredPreview() {
|
||||
fun RsvpWidgetAnsweredPreview() {
|
||||
RsvpWidget(
|
||||
uiModel = RsvpWidgetPreviewData.AnsweredWithOneParticipantAndStatus,
|
||||
onOpenInProtonCalendar = {},
|
||||
onAnswerRsvpEvent = {}
|
||||
actions = RsvpWidget.Actions(
|
||||
onOpenInProtonCalendar = {},
|
||||
onAnswerRsvpEvent = {},
|
||||
onMessage = {}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
object RsvpWidget {
|
||||
|
||||
data class Actions(
|
||||
val onOpenInProtonCalendar: () -> Unit,
|
||||
val onAnswerRsvpEvent: (RsvpAnswer) -> Unit,
|
||||
val onMessage: (String) -> Unit
|
||||
)
|
||||
}
|
||||
|
||||
@@ -166,4 +166,6 @@
|
||||
<string name="rsvp_widget_button_retry">Retry</string>
|
||||
<string name="rsvp_widget_error_answering">An error occurred while answering this event</string>
|
||||
<string name="rsvp_widget_open_in_proton_calendar">Open in Proton Calendar</string>
|
||||
<string name="rsvp_widget_copy_address">Copy address</string>
|
||||
<string name="rsvp_widget_message">Message</string>
|
||||
</resources>
|
||||
|
||||
+2
-1
@@ -65,7 +65,8 @@ internal class MessageDetailFooterActionsTest {
|
||||
onUnblockSender = { _, _ -> },
|
||||
onEditScheduleSendMessage = {},
|
||||
onRetryRsvpEventLoading = {},
|
||||
onAnswerRsvpEvent = { _, _ -> }
|
||||
onAnswerRsvpEvent = { _, _ -> },
|
||||
onMessage = {}
|
||||
)
|
||||
|
||||
// When
|
||||
|
||||
Reference in New Issue
Block a user