mirror of
https://github.com/ProtonMail/android-mail.git
synced 2026-05-15 09:50:40 +00:00
Fix Calendar app not opening when clicking the RSVP widget logo on reminder messages
ET-4724
This commit is contained in:
@@ -182,6 +182,14 @@ class MainActivity : AppCompatActivity() {
|
||||
values.recipient
|
||||
)
|
||||
|
||||
is OpenProtonCalendarIntentValues.OpenUriInProtonCalendar -> {
|
||||
ProtonCalendarUtil.getIntentToOpenEventInProtonCalendar(
|
||||
values.eventId,
|
||||
values.calendarId,
|
||||
values.recurrenceId
|
||||
)
|
||||
}
|
||||
|
||||
is OpenProtonCalendarIntentValues.OpenProtonCalendarOnPlayStore ->
|
||||
ProtonCalendarUtil.getIntentToProtonCalendarOnPlayStore()
|
||||
}
|
||||
|
||||
+7
-1
@@ -27,5 +27,11 @@ sealed class OpenProtonCalendarIntentValues {
|
||||
val recipient: String
|
||||
) : OpenProtonCalendarIntentValues()
|
||||
|
||||
object OpenProtonCalendarOnPlayStore : OpenProtonCalendarIntentValues()
|
||||
data class OpenUriInProtonCalendar(
|
||||
val eventId: String,
|
||||
val calendarId: String,
|
||||
val recurrenceId: Long
|
||||
) : OpenProtonCalendarIntentValues()
|
||||
|
||||
data object OpenProtonCalendarOnPlayStore : OpenProtonCalendarIntentValues()
|
||||
}
|
||||
|
||||
+3
@@ -53,6 +53,8 @@ class RsvpEventUiModelMapper @Inject constructor(
|
||||
}
|
||||
|
||||
return RsvpEventUiModel(
|
||||
eventId = eventDetails.eventId,
|
||||
startsAt = eventDetails.startsAt,
|
||||
title = eventDetails.getEventTitle(),
|
||||
dateTime = formatRsvpWidgetTime(eventDetails.occurrence, eventDetails.startsAt, eventDetails.endsAt),
|
||||
isAttendanceOptional = isAttendanceOptional(eventDetails.state),
|
||||
@@ -87,6 +89,7 @@ class RsvpEventUiModelMapper @Inject constructor(
|
||||
answerInProgress?.toRsvpAttendeeAnswer() ?: status?.toRsvpAttendeeAnswer()
|
||||
|
||||
private fun RsvpCalendar.toUiModel() = RsvpCalendarUiModel(
|
||||
calendarId = this.id,
|
||||
color = colorMapper.toColor(this.color).getOrElse { Color.Unspecified },
|
||||
name = TextUiModel.Text(this.name)
|
||||
)
|
||||
|
||||
+2
@@ -179,6 +179,8 @@ sealed interface ConversationDetailEvent : ConversationDetailOperation {
|
||||
AffectingMessageBar
|
||||
|
||||
data object ErrorUnsubscribingFromNewsletter : ConversationDetailEvent, AffectingErrorBar
|
||||
|
||||
data object ErrorOpeningEventInCalendar : ConversationDetailEvent, AffectingErrorBar
|
||||
}
|
||||
|
||||
sealed interface ConversationDetailViewAction : ConversationDetailOperation {
|
||||
|
||||
+5
@@ -20,6 +20,8 @@ package ch.protonmail.android.maildetail.presentation.model
|
||||
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import ch.protonmail.android.mailcommon.presentation.model.TextUiModel
|
||||
import ch.protonmail.android.mailmessage.domain.model.CalendarId
|
||||
import ch.protonmail.android.mailmessage.domain.model.EventId
|
||||
|
||||
interface RsvpWidgetUiModel {
|
||||
|
||||
@@ -30,6 +32,8 @@ interface RsvpWidgetUiModel {
|
||||
}
|
||||
|
||||
data class RsvpEventUiModel(
|
||||
val eventId: EventId?,
|
||||
val startsAt: Long,
|
||||
val title: TextUiModel,
|
||||
val dateTime: TextUiModel,
|
||||
val isAttendanceOptional: Boolean,
|
||||
@@ -67,6 +71,7 @@ data class RsvpOrganizerUiModel(
|
||||
)
|
||||
|
||||
data class RsvpCalendarUiModel(
|
||||
val calendarId: CalendarId,
|
||||
val color: Color,
|
||||
val name: TextUiModel
|
||||
)
|
||||
|
||||
+8
@@ -27,15 +27,20 @@ import ch.protonmail.android.maildetail.presentation.model.RsvpCalendarUiModel
|
||||
import ch.protonmail.android.maildetail.presentation.model.RsvpEventUiModel
|
||||
import ch.protonmail.android.maildetail.presentation.model.RsvpOrganizerUiModel
|
||||
import ch.protonmail.android.maildetail.presentation.model.RsvpStatusUiModel
|
||||
import ch.protonmail.android.mailmessage.domain.model.CalendarId
|
||||
import ch.protonmail.android.mailmessage.domain.model.EventId
|
||||
|
||||
object RsvpWidgetPreviewData {
|
||||
|
||||
val UnansweredWithMultipleParticipants = RsvpEventUiModel(
|
||||
eventId = EventId(""),
|
||||
startsAt = 0,
|
||||
title = TextUiModel.Text("Whispers of Tomorrow: An Evening of Unexpected Wonders"),
|
||||
dateTime = TextUiModel.Text("15 Jul • 14:30 - 15:30"),
|
||||
isAttendanceOptional = true,
|
||||
buttons = RsvpButtonsUiModel.Shown(RsvpAttendeeAnswer.Unanswered, isAnsweringInProgress = false),
|
||||
calendar = RsvpCalendarUiModel(
|
||||
calendarId = CalendarId(""),
|
||||
color = Color.Magenta,
|
||||
name = TextUiModel.Text("Work")
|
||||
),
|
||||
@@ -71,11 +76,14 @@ object RsvpWidgetPreviewData {
|
||||
)
|
||||
|
||||
val AnsweredWithOneParticipantAndStatus = RsvpEventUiModel(
|
||||
eventId = EventId(""),
|
||||
startsAt = 0,
|
||||
title = TextUiModel.Text("Inbox OKR Weekly"),
|
||||
dateTime = TextUiModel.Text("15 Jul • 14:30 - 15:30"),
|
||||
isAttendanceOptional = true,
|
||||
buttons = RsvpButtonsUiModel.Shown(RsvpAttendeeAnswer.Yes, isAnsweringInProgress = false),
|
||||
calendar = RsvpCalendarUiModel(
|
||||
calendarId = CalendarId(""),
|
||||
color = Color.Magenta,
|
||||
name = TextUiModel.Text("Work")
|
||||
),
|
||||
|
||||
+2
@@ -49,6 +49,7 @@ import ch.protonmail.android.maildetail.presentation.model.ConversationDetailEve
|
||||
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailEvent.ErrorMovingConversation
|
||||
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailEvent.ErrorMovingMessage
|
||||
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailEvent.ErrorMovingToTrash
|
||||
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailEvent.ErrorOpeningEventInCalendar
|
||||
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailEvent.ErrorRemoveStar
|
||||
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailEvent.ErrorUnsnoozing
|
||||
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailEvent.ErrorUnsubscribingFromNewsletter
|
||||
@@ -251,6 +252,7 @@ class ConversationDetailReducer @Inject constructor(
|
||||
|
||||
is ErrorAnsweringRsvpEvent -> R.string.rsvp_widget_error_answering
|
||||
is ErrorUnsubscribingFromNewsletter -> R.string.error_unsubscribe_newsletter
|
||||
is ErrorOpeningEventInCalendar -> R.string.rsvp_widget_failed_to_open_in_proton_calendar
|
||||
}
|
||||
Effect.of(TextUiModel(textResource))
|
||||
} else {
|
||||
|
||||
+16
@@ -20,6 +20,7 @@ package ch.protonmail.android.maildetail.presentation.util
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import androidx.core.net.toUri
|
||||
import ch.protonmail.android.maildetail.domain.usecase.IsProtonCalendarInstalled.Companion.PROTON_CALENDAR_PACKAGE_NAME
|
||||
|
||||
object ProtonCalendarUtil {
|
||||
@@ -43,6 +44,21 @@ object ProtonCalendarUtil {
|
||||
putExtra(EXTRA_RECIPIENT, recipient)
|
||||
}
|
||||
|
||||
fun getIntentToOpenEventInProtonCalendar(
|
||||
eventId: String,
|
||||
calendarId: String,
|
||||
recurrenceId: Long
|
||||
): Intent {
|
||||
val uri = (
|
||||
"https://calendar.proton.me/event?Action=VIEW&EventID=$eventId&" +
|
||||
"CalendarID=$calendarId&RecurrenceID=$recurrenceId"
|
||||
).toUri()
|
||||
return Intent(
|
||||
Intent.ACTION_VIEW,
|
||||
uri
|
||||
)
|
||||
}
|
||||
|
||||
fun getIntentToProtonCalendarOnPlayStore() = Intent(Intent.ACTION_VIEW).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
data = Uri.parse("market://details?id=$PROTON_CALENDAR_PACKAGE_NAME")
|
||||
|
||||
+50
-12
@@ -26,6 +26,8 @@ import androidx.lifecycle.viewModelScope
|
||||
import arrow.core.Either
|
||||
import arrow.core.NonEmptyList
|
||||
import arrow.core.getOrElse
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import arrow.core.toNonEmptyListOrNull
|
||||
import ch.protonmail.android.mailattachments.domain.model.AttachmentId
|
||||
import ch.protonmail.android.mailattachments.domain.model.AttachmentMetadata
|
||||
@@ -89,6 +91,7 @@ import ch.protonmail.android.maildetail.presentation.model.ConversationDetailVie
|
||||
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailViewAction.UnStar
|
||||
import ch.protonmail.android.maildetail.presentation.model.ConversationDetailsMessagesState
|
||||
import ch.protonmail.android.maildetail.presentation.model.MessageIdUiModel
|
||||
import ch.protonmail.android.maildetail.presentation.model.RsvpWidgetUiModel
|
||||
import ch.protonmail.android.maildetail.presentation.reducer.ConversationDetailReducer
|
||||
import ch.protonmail.android.maildetail.presentation.ui.ConversationDetailScreen
|
||||
import ch.protonmail.android.maildetail.presentation.usecase.GetMessagesInSameExclusiveLocation
|
||||
@@ -1493,19 +1496,52 @@ class ConversationDetailViewModel @Inject constructor(
|
||||
?.attachments
|
||||
?.firstOrNull { uiModel -> uiModel.isCalendar }
|
||||
|
||||
if (firstCalendarAttachment == null) return
|
||||
if (firstCalendarAttachment == null) {
|
||||
getRsvpEventIntentValues(messageUiModel.messageRsvpWidgetUiModel).fold(
|
||||
ifLeft = {
|
||||
emitNewStateFrom(ConversationDetailEvent.ErrorOpeningEventInCalendar)
|
||||
},
|
||||
ifRight = {
|
||||
val intent = OpenProtonCalendarIntentValues.OpenUriInProtonCalendar(
|
||||
it.eventId,
|
||||
it.calendarId,
|
||||
it.recurrenceId
|
||||
)
|
||||
emitNewStateFrom(ConversationDetailEvent.HandleOpenProtonCalendarRequest(intent))
|
||||
}
|
||||
)
|
||||
} else {
|
||||
getAttachmentIntentValues(
|
||||
userId = primaryUserId.first(),
|
||||
openMode = AttachmentOpenMode.Open,
|
||||
attachmentId = AttachmentId(firstCalendarAttachment.id.value)
|
||||
).fold(
|
||||
ifLeft = {
|
||||
Timber.d("Failed to download attachment: $it")
|
||||
emitNewStateFrom(ConversationDetailEvent.ErrorOpeningEventInCalendar)
|
||||
},
|
||||
ifRight = {
|
||||
val intent = OpenProtonCalendarIntentValues.OpenIcsInProtonCalendar(it.uri, sender, recipient)
|
||||
emitNewStateFrom(ConversationDetailEvent.HandleOpenProtonCalendarRequest(intent))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
getAttachmentIntentValues(
|
||||
userId = primaryUserId.first(),
|
||||
openMode = AttachmentOpenMode.Open,
|
||||
attachmentId = AttachmentId(firstCalendarAttachment.id.value)
|
||||
).fold(
|
||||
ifLeft = { Timber.d("Failed to download attachment: $it") },
|
||||
ifRight = {
|
||||
val intent = OpenProtonCalendarIntentValues.OpenIcsInProtonCalendar(it.uri, sender, recipient)
|
||||
emitNewStateFrom(ConversationDetailEvent.HandleOpenProtonCalendarRequest(intent))
|
||||
}
|
||||
)
|
||||
private fun getRsvpEventIntentValues(rsvpWidgetUiModel: RsvpWidgetUiModel): Either<Unit, RsvpEventIntentValues> {
|
||||
val event = when (rsvpWidgetUiModel) {
|
||||
is RsvpWidgetUiModel.Shown -> rsvpWidgetUiModel.event
|
||||
else -> null
|
||||
}
|
||||
return if (event?.eventId != null && event.calendar?.calendarId != null) {
|
||||
RsvpEventIntentValues(
|
||||
event.eventId.id,
|
||||
event.calendar.calendarId.id,
|
||||
event.startsAt
|
||||
).right()
|
||||
} else {
|
||||
Unit.left()
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleMarkMessageUnread(action: ConversationDetailViewAction.MarkMessageUnread) {
|
||||
@@ -1721,4 +1757,6 @@ class ConversationDetailViewModel @Inject constructor(
|
||||
|
||||
val initialState = ConversationDetailState.Loading
|
||||
}
|
||||
|
||||
data class RsvpEventIntentValues(val eventId: String, val calendarId: String, val recurrenceId: Long)
|
||||
}
|
||||
|
||||
@@ -167,6 +167,7 @@
|
||||
<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_failed_to_open_in_proton_calendar">Failed to open in Proton Calendar</string>
|
||||
<string name="rsvp_widget_copy_address">Copy address</string>
|
||||
<string name="rsvp_widget_message">Message</string>
|
||||
<string name="snooze_message_snoozed_until_banner_title">Snoozed until</string>
|
||||
|
||||
+3
@@ -101,11 +101,14 @@ class RsvpEventUiModelMapperTest {
|
||||
|
||||
// Then
|
||||
val expected = RsvpEventUiModel(
|
||||
eventId = EventId("id"),
|
||||
startsAt = 123,
|
||||
title = TextUiModel.Text("Inbox OKR Weekly"),
|
||||
dateTime = TextUiModel.Text("15 Jul • 14:30 - 15:30"),
|
||||
isAttendanceOptional = false,
|
||||
buttons = RsvpButtonsUiModel.Hidden,
|
||||
calendar = RsvpCalendarUiModel(
|
||||
calendarId = CalendarId("id"),
|
||||
color = Color.Magenta,
|
||||
name = TextUiModel.Text("Work")
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user