Browse Source

Render correctly in reply to data when Event cannot be decrypted or has been redacted

pull/2384/head
Benoit Marty 7 months ago
parent
commit
73abf548ea
  1. 1
      changelog.d/2318.misc
  2. 50
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt
  3. 42
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyInformativePreview.kt
  4. 9
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyPreview.kt
  5. 25
      features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToMetadata.kt

1
changelog.d/2318.misc

@ -0,0 +1 @@ @@ -0,0 +1 @@
Render correctly in reply to data when Event cannot be decrypted or has been redacted

50
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRow.kt

@ -53,6 +53,7 @@ import androidx.compose.ui.platform.LocalContext @@ -53,6 +53,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalViewConfiguration
import androidx.compose.ui.platform.ViewConfiguration
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
@ -92,6 +93,7 @@ import io.element.android.libraries.designsystem.colors.AvatarColorsProvider @@ -92,6 +93,7 @@ import io.element.android.libraries.designsystem.colors.AvatarColorsProvider
import io.element.android.libraries.designsystem.components.EqualWidthColumn
import io.element.android.libraries.designsystem.components.avatar.Avatar
import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.icons.CompoundDrawables
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.swipe.SwipeableActionsState
@ -99,6 +101,7 @@ import io.element.android.libraries.designsystem.swipe.rememberSwipeableActionsS @@ -99,6 +101,7 @@ import io.element.android.libraries.designsystem.swipe.rememberSwipeableActionsS
import io.element.android.libraries.designsystem.text.toPx
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.CommonDrawables
import io.element.android.libraries.matrix.api.core.EventId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.permalink.PermalinkData
@ -648,15 +651,48 @@ private fun ReplyToContent( @@ -648,15 +651,48 @@ private fun ReplyToContent(
maxLines = 1,
overflow = TextOverflow.Ellipsis,
)
Text(
text = metadata?.text.orEmpty(),
style = ElementTheme.typography.fontBodyMdRegular,
textAlign = TextAlign.Start,
color = ElementTheme.materialColors.secondary,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
ReplyToContentText(metadata)
}
}
}
@Composable
private fun ReplyToContentText(metadata: InReplyToMetadata?) {
val text = when (metadata) {
InReplyToMetadata.Redacted -> stringResource(id = CommonStrings.common_message_removed)
InReplyToMetadata.UnableToDecrypt -> stringResource(id = CommonStrings.common_waiting_for_decryption_key)
else -> metadata?.text.orEmpty()
}
val iconResourceId = when (metadata) {
InReplyToMetadata.Redacted -> CompoundDrawables.ic_compound_delete
InReplyToMetadata.UnableToDecrypt -> CompoundDrawables.ic_compound_time
else -> null
}
val fontStyle = when (metadata) {
is InReplyToMetadata.Informative -> FontStyle.Italic
else -> FontStyle.Normal
}
Row(
verticalAlignment = Alignment.CenterVertically,
) {
if (iconResourceId != null) {
Icon(
resourceId = iconResourceId,
tint = MaterialTheme.colorScheme.secondary,
contentDescription = null,
modifier = Modifier.size(16.dp)
)
Spacer(modifier = Modifier.width(4.dp))
}
Text(
text = text,
style = ElementTheme.typography.fontBodyMdRegular,
fontStyle = fontStyle,
textAlign = TextAlign.Start,
color = MaterialTheme.colorScheme.secondary,
maxLines = 2,
overflow = TextOverflow.Ellipsis,
)
}
}

42
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyInformativePreview.kt

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.messages.impl.timeline.components
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.PreviewParameter
import io.element.android.features.messages.impl.timeline.model.InReplyToDetails
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
@PreviewsDayNight
@Composable
internal fun TimelineItemEventRowWithReplyInformativePreview(
@PreviewParameter(InReplyToDetailsInformativeProvider::class) inReplyToDetails: InReplyToDetails,
) = TimelineItemEventRowWithReplyContentToPreview(inReplyToDetails)
class InReplyToDetailsInformativeProvider : InReplyToDetailsProvider() {
override val values: Sequence<InReplyToDetails>
get() = sequenceOf(
RedactedContent,
UnableToDecryptContent(UnableToDecryptContent.Data.Unknown),
).map {
aInReplyToDetails(
eventContent = it,
)
}
}

9
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/TimelineItemEventRowWithReplyPreview.kt

@ -53,7 +53,10 @@ import kotlinx.collections.immutable.persistentMapOf @@ -53,7 +53,10 @@ import kotlinx.collections.immutable.persistentMapOf
@Composable
internal fun TimelineItemEventRowWithReplyPreview(
@PreviewParameter(InReplyToDetailsProvider::class) inReplyToDetails: InReplyToDetails,
) = ElementPreview {
) = TimelineItemEventRowWithReplyContentToPreview(inReplyToDetails)
@Composable
internal fun TimelineItemEventRowWithReplyContentToPreview(inReplyToDetails: InReplyToDetails) = ElementPreview {
Column {
sequenceOf(false, true).forEach {
ATimelineItemEventRow(
@ -83,7 +86,7 @@ internal fun TimelineItemEventRowWithReplyPreview( @@ -83,7 +86,7 @@ internal fun TimelineItemEventRowWithReplyPreview(
}
}
class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails> {
open class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails> {
override val values: Sequence<InReplyToDetails>
get() = sequenceOf(
aMessageContent(
@ -156,7 +159,7 @@ class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails> { @@ -156,7 +159,7 @@ class InReplyToDetailsProvider : PreviewParameterProvider<InReplyToDetails> {
type = type,
)
private fun aInReplyToDetails(
protected fun aInReplyToDetails(
eventContent: EventContent,
) = InReplyToDetails(
eventId = EventId("\$event"),

25
features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/model/InReplyToMetadata.kt

@ -21,12 +21,20 @@ import androidx.compose.runtime.Immutable @@ -21,12 +21,20 @@ import androidx.compose.runtime.Immutable
import androidx.compose.ui.res.stringResource
import io.element.android.libraries.matrix.api.media.MediaSource
import io.element.android.libraries.matrix.api.timeline.item.event.AudioMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseMessageLikeContent
import io.element.android.libraries.matrix.api.timeline.item.event.FailedToParseStateContent
import io.element.android.libraries.matrix.api.timeline.item.event.FileMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.ImageMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.LocationMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.MessageContent
import io.element.android.libraries.matrix.api.timeline.item.event.PollContent
import io.element.android.libraries.matrix.api.timeline.item.event.ProfileChangeContent
import io.element.android.libraries.matrix.api.timeline.item.event.RedactedContent
import io.element.android.libraries.matrix.api.timeline.item.event.RoomMembershipContent
import io.element.android.libraries.matrix.api.timeline.item.event.StateContent
import io.element.android.libraries.matrix.api.timeline.item.event.StickerContent
import io.element.android.libraries.matrix.api.timeline.item.event.UnableToDecryptContent
import io.element.android.libraries.matrix.api.timeline.item.event.UnknownContent
import io.element.android.libraries.matrix.api.timeline.item.event.VideoMessageType
import io.element.android.libraries.matrix.api.timeline.item.event.VoiceMessageType
import io.element.android.libraries.matrix.ui.components.AttachmentThumbnailInfo
@ -46,6 +54,13 @@ internal sealed interface InReplyToMetadata { @@ -46,6 +54,13 @@ internal sealed interface InReplyToMetadata {
data class Text(
override val text: String
) : InReplyToMetadata
abstract class Informative : InReplyToMetadata {
override val text: String? = null
}
data object Redacted : Informative()
data object UnableToDecrypt : Informative()
}
/**
@ -112,5 +127,13 @@ internal fun InReplyToDetails.metadata(): InReplyToMetadata? = when (eventConten @@ -112,5 +127,13 @@ internal fun InReplyToDetails.metadata(): InReplyToMetadata? = when (eventConten
type = AttachmentThumbnailType.Poll,
)
)
else -> null
is RedactedContent -> InReplyToMetadata.Redacted
is UnableToDecryptContent -> InReplyToMetadata.UnableToDecrypt
is FailedToParseMessageLikeContent,
is FailedToParseStateContent,
is ProfileChangeContent,
is RoomMembershipContent,
is StateContent,
UnknownContent,
null -> null
}

Loading…
Cancel
Save