mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-02-08 06:32:58 -05:00
ui: new type for EventTimelineItem::get_shield
Separate the shield types between common and UI, so that we can change common without breaking UI. The new type does not include a `message` field: since it cannot be localised, clients should not be using it.
This commit is contained in:
@@ -21,7 +21,6 @@ use matrix_sdk::{
|
||||
attachment::{
|
||||
AttachmentInfo, BaseAudioInfo, BaseFileInfo, BaseImageInfo, BaseVideoInfo, Thumbnail,
|
||||
},
|
||||
deserialized_responses::{ShieldState as SdkShieldState, ShieldStateCode},
|
||||
event_cache::RoomPaginationStatus,
|
||||
room::edit::EditedContent as SdkEditedContent,
|
||||
};
|
||||
@@ -33,6 +32,7 @@ use matrix_sdk_ui::timeline::{
|
||||
self, AttachmentConfig, AttachmentSource, EventItemOrigin,
|
||||
LatestEventValue as UiLatestEventValue, LatestEventValueLocalState,
|
||||
MediaUploadProgress as SdkMediaUploadProgress, Profile, TimelineDetails,
|
||||
TimelineEventShieldState as SdkShieldState, TimelineEventShieldStateCode,
|
||||
TimelineUniqueId as SdkTimelineUniqueId,
|
||||
};
|
||||
use mime::Mime;
|
||||
@@ -993,8 +993,8 @@ pub enum ShieldState {
|
||||
impl From<SdkShieldState> for ShieldState {
|
||||
fn from(value: SdkShieldState) -> Self {
|
||||
match value {
|
||||
SdkShieldState::Red { code, message: _ } => Self::Red { code },
|
||||
SdkShieldState::Grey { code, message: _ } => Self::Grey { code },
|
||||
SdkShieldState::Red { code } => Self::Red { code },
|
||||
SdkShieldState::Grey { code } => Self::Grey { code },
|
||||
SdkShieldState::None => Self::None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ const UNKNOWN_DEVICE: &str = "Encrypted by an unknown or deleted device.";
|
||||
const MISMATCHED_SENDER: &str = "\
|
||||
The sender of the event does not match the owner of the device \
|
||||
that created the Megolm session.";
|
||||
pub const SENT_IN_CLEAR: &str = "Not encrypted.";
|
||||
|
||||
/// Represents the state of verification for a decrypted message sent by a
|
||||
/// device.
|
||||
|
||||
@@ -18,6 +18,10 @@ All notable changes to this project will be documented in this file.
|
||||
|
||||
### Features
|
||||
|
||||
- [**breaking**] `EventTimelineItem::get_shield` now returns a new type,
|
||||
`TimelineEventShieldState`, which extends the old `ShieldState` with a code
|
||||
for `SentInClear`, now that the latter has been removed from `ShieldState`.
|
||||
([#5959](https://github.com/matrix-org/matrix-rust-sdk/pull/5959))
|
||||
- Add `SpaceService::get_space_room` to get a space
|
||||
given its id from the space graph if available.
|
||||
([#5944](https://github.com/matrix-org/matrix-rust-sdk/pull/5944))
|
||||
|
||||
@@ -24,7 +24,7 @@ use matrix_sdk::{
|
||||
deserialized_responses::{EncryptionInfo, ShieldState},
|
||||
send_queue::{SendHandle, SendReactionHandle},
|
||||
};
|
||||
use matrix_sdk_base::deserialized_responses::{SENT_IN_CLEAR, ShieldStateCode};
|
||||
use matrix_sdk_base::deserialized_responses::ShieldStateCode;
|
||||
use once_cell::sync::Lazy;
|
||||
use ruma::{
|
||||
EventId, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedMxcUri, OwnedTransactionId,
|
||||
@@ -309,16 +309,16 @@ impl EventTimelineItem {
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the [`ShieldState`] which can be used to decorate
|
||||
/// Gets the [`TimelineEventShieldState`] which can be used to decorate
|
||||
/// messages in the recommended way.
|
||||
pub fn get_shield(&self, strict: bool) -> ShieldState {
|
||||
pub fn get_shield(&self, strict: bool) -> TimelineEventShieldState {
|
||||
if !self.is_room_encrypted || self.is_local_echo() {
|
||||
return ShieldState::None;
|
||||
return TimelineEventShieldState::None;
|
||||
}
|
||||
|
||||
// An unable-to-decrypt message has no authenticity shield.
|
||||
if self.content().is_unable_to_decrypt() {
|
||||
return ShieldState::None;
|
||||
return TimelineEventShieldState::None;
|
||||
}
|
||||
|
||||
match self.encryption_info() {
|
||||
@@ -329,10 +329,9 @@ impl EventTimelineItem {
|
||||
info.verification_state.to_shield_state_lax().into()
|
||||
}
|
||||
}
|
||||
None => ShieldState::Red {
|
||||
code: ShieldStateCode::SentInClear,
|
||||
message: SENT_IN_CLEAR,
|
||||
},
|
||||
None => {
|
||||
TimelineEventShieldState::Red { code: TimelineEventShieldStateCode::SentInClear }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,3 +692,72 @@ impl ReactionsByKeyBySender {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Extends [`ShieldState`] to allow for a `SentInClear` code.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum TimelineEventShieldState {
|
||||
/// A red shield with a tooltip containing a message appropriate to the
|
||||
/// associated code should be presented.
|
||||
Red {
|
||||
/// A machine-readable representation.
|
||||
code: TimelineEventShieldStateCode,
|
||||
},
|
||||
/// A grey shield with a tooltip containing a message appropriate to the
|
||||
/// associated code should be presented.
|
||||
Grey {
|
||||
/// A machine-readable representation.
|
||||
code: TimelineEventShieldStateCode,
|
||||
},
|
||||
/// No shield should be presented.
|
||||
None,
|
||||
}
|
||||
|
||||
impl From<ShieldState> for TimelineEventShieldState {
|
||||
fn from(value: ShieldState) -> Self {
|
||||
match value {
|
||||
ShieldState::Red { code, message: _ } => {
|
||||
TimelineEventShieldState::Red { code: code.into() }
|
||||
}
|
||||
ShieldState::Grey { code, message: _ } => {
|
||||
TimelineEventShieldState::Grey { code: code.into() }
|
||||
}
|
||||
ShieldState::None => TimelineEventShieldState::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Extends [`ShieldStateCode`] to allow for a `SentInClear` code.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
|
||||
pub enum TimelineEventShieldStateCode {
|
||||
/// Not enough information available to check the authenticity.
|
||||
AuthenticityNotGuaranteed,
|
||||
/// The sending device isn't yet known by the Client.
|
||||
UnknownDevice,
|
||||
/// The sending device hasn't been verified by the sender.
|
||||
UnsignedDevice,
|
||||
/// The sender hasn't been verified by the Client's user.
|
||||
UnverifiedIdentity,
|
||||
/// The sender was previously verified but changed their identity.
|
||||
VerificationViolation,
|
||||
/// The `sender` field on the event does not match the owner of the device
|
||||
/// that established the Megolm session.
|
||||
MismatchedSender,
|
||||
/// An unencrypted event in an encrypted room.
|
||||
SentInClear,
|
||||
}
|
||||
|
||||
impl From<ShieldStateCode> for TimelineEventShieldStateCode {
|
||||
fn from(value: ShieldStateCode) -> Self {
|
||||
use TimelineEventShieldStateCode::*;
|
||||
match value {
|
||||
ShieldStateCode::AuthenticityNotGuaranteed => AuthenticityNotGuaranteed,
|
||||
ShieldStateCode::UnknownDevice => UnknownDevice,
|
||||
ShieldStateCode::UnsignedDevice => UnsignedDevice,
|
||||
ShieldStateCode::UnverifiedIdentity => UnverifiedIdentity,
|
||||
ShieldStateCode::SentInClear => SentInClear,
|
||||
ShieldStateCode::VerificationViolation => VerificationViolation,
|
||||
ShieldStateCode::MismatchedSender => MismatchedSender,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,8 @@ pub use self::{
|
||||
MemberProfileChange, MembershipChange, Message, MsgLikeContent, MsgLikeKind,
|
||||
OtherMessageLike, OtherState, PollResult, PollState, Profile, ReactionInfo, ReactionStatus,
|
||||
ReactionsByKeyBySender, RoomMembershipChange, RoomPinnedEventsChange, Sticker,
|
||||
ThreadSummary, TimelineDetails, TimelineEventItemId, TimelineItemContent,
|
||||
ThreadSummary, TimelineDetails, TimelineEventItemId, TimelineEventShieldState,
|
||||
TimelineEventShieldStateCode, TimelineItemContent,
|
||||
},
|
||||
event_type_filter::TimelineEventTypeFilter,
|
||||
item::{TimelineItem, TimelineItemKind, TimelineUniqueId},
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use assert_matches::assert_matches;
|
||||
use eyeball_im::VectorDiff;
|
||||
use matrix_sdk_base::deserialized_responses::{ShieldState, ShieldStateCode};
|
||||
use matrix_sdk_test::{ALICE, async_test, event_factory::EventFactory};
|
||||
use ruma::{
|
||||
event_id,
|
||||
@@ -17,7 +16,7 @@ use ruma::{
|
||||
use stream_assert::{assert_next_matches, assert_pending};
|
||||
|
||||
use crate::timeline::{
|
||||
EventSendState,
|
||||
EventSendState, TimelineEventShieldState, TimelineEventShieldStateCode,
|
||||
tests::{TestTimeline, TestTimelineBuilder},
|
||||
};
|
||||
|
||||
@@ -31,7 +30,7 @@ async fn test_no_shield_in_unencrypted_room() {
|
||||
|
||||
let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
let shield = item.as_event().unwrap().get_shield(false);
|
||||
assert_eq!(shield, ShieldState::None);
|
||||
assert_eq!(shield, TimelineEventShieldState::None);
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
@@ -46,7 +45,7 @@ async fn test_sent_in_clear_shield() {
|
||||
let shield = item.as_event().unwrap().get_shield(false);
|
||||
assert_eq!(
|
||||
shield,
|
||||
ShieldState::Red { code: ShieldStateCode::SentInClear, message: "Not encrypted." }
|
||||
TimelineEventShieldState::Red { code: TimelineEventShieldStateCode::SentInClear }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -75,7 +74,7 @@ async fn test_local_sent_in_clear_shield() {
|
||||
// available).
|
||||
assert!(event_item.is_local_echo());
|
||||
let shield = event_item.get_shield(false);
|
||||
assert_eq!(shield, ShieldState::None);
|
||||
assert_eq!(shield, TimelineEventShieldState::None);
|
||||
|
||||
{
|
||||
// The date divider comes in late.
|
||||
@@ -96,7 +95,7 @@ async fn test_local_sent_in_clear_shield() {
|
||||
// Then the local echo still should not have a shield.
|
||||
assert!(event_item.is_local_echo());
|
||||
let shield = event_item.get_shield(false);
|
||||
assert_eq!(shield, ShieldState::None);
|
||||
assert_eq!(shield, TimelineEventShieldState::None);
|
||||
|
||||
// When the remote echo comes in.
|
||||
timeline
|
||||
@@ -118,7 +117,7 @@ async fn test_local_sent_in_clear_shield() {
|
||||
let shield = event_item.get_shield(false);
|
||||
assert_eq!(
|
||||
shield,
|
||||
ShieldState::Red { code: ShieldStateCode::SentInClear, message: "Not encrypted." }
|
||||
TimelineEventShieldState::Red { code: TimelineEventShieldStateCode::SentInClear }
|
||||
);
|
||||
|
||||
// Date divider is adjusted.
|
||||
@@ -168,5 +167,5 @@ async fn test_utd_shield() {
|
||||
// Then the message is displayed with no shield
|
||||
let item = assert_next_matches!(stream, VectorDiff::PushBack { value } => value);
|
||||
let shield = item.as_event().unwrap().get_shield(false);
|
||||
assert_eq!(shield, ShieldState::None);
|
||||
assert_eq!(shield, TimelineEventShieldState::None);
|
||||
}
|
||||
|
||||
@@ -22,7 +22,6 @@ use matrix_sdk::{
|
||||
linked_chunk::{ChunkIdentifier, LinkedChunkId, Position, Update},
|
||||
test_utils::mocks::{MatrixMockServer, RoomContextResponseTemplate},
|
||||
};
|
||||
use matrix_sdk_common::deserialized_responses::ShieldState;
|
||||
use matrix_sdk_test::{
|
||||
ALICE, BOB, JoinedRoomBuilder, RoomAccountDataTestEvent, StateTestEvent, async_test,
|
||||
event_factory::EventFactory,
|
||||
@@ -31,8 +30,8 @@ use matrix_sdk_ui::{
|
||||
Timeline,
|
||||
timeline::{
|
||||
AnyOtherFullStateEventContent, Error, EventSendState, MsgLikeKind, OtherMessageLike,
|
||||
RedactError, RoomExt, TimelineBuilder, TimelineEventItemId, TimelineFocus,
|
||||
TimelineItemContent, VirtualTimelineItem, default_event_filter,
|
||||
RedactError, RoomExt, TimelineBuilder, TimelineEventItemId, TimelineEventShieldState,
|
||||
TimelineFocus, TimelineItemContent, VirtualTimelineItem, default_event_filter,
|
||||
},
|
||||
};
|
||||
use ruma::{
|
||||
@@ -758,7 +757,7 @@ async fn test_timeline_without_encryption_info() {
|
||||
assert_eq!(items.len(), 2);
|
||||
assert!(items[0].as_virtual().is_some());
|
||||
// No encryption, no shields.
|
||||
assert_eq!(items[1].as_event().unwrap().get_shield(false), ShieldState::None);
|
||||
assert_eq!(items[1].as_event().unwrap().get_shield(false), TimelineEventShieldState::None);
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
@@ -788,7 +787,7 @@ async fn test_timeline_without_encryption_can_update() {
|
||||
assert_eq!(items.len(), 2);
|
||||
assert!(items[0].as_virtual().is_some());
|
||||
// No encryption, no shields
|
||||
assert_eq!(items[1].as_event().unwrap().get_shield(false), ShieldState::None);
|
||||
assert_eq!(items[1].as_event().unwrap().get_shield(false), TimelineEventShieldState::None);
|
||||
|
||||
let encryption_event_content = RoomEncryptionEventContent::with_recommended_defaults();
|
||||
server
|
||||
@@ -806,17 +805,17 @@ async fn test_timeline_without_encryption_can_update() {
|
||||
// Previous timeline event now has a shield.
|
||||
assert_let!(VectorDiff::Set { index, value } = &timeline_updates[0]);
|
||||
assert_eq!(*index, 1);
|
||||
assert_ne!(value.as_event().unwrap().get_shield(false), ShieldState::None);
|
||||
assert_ne!(value.as_event().unwrap().get_shield(false), TimelineEventShieldState::None);
|
||||
|
||||
// Room encryption event is received.
|
||||
assert_let!(VectorDiff::PushBack { value } = &timeline_updates[1]);
|
||||
assert_let!(TimelineItemContent::OtherState(other_state) = value.as_event().unwrap().content());
|
||||
assert_let!(AnyOtherFullStateEventContent::RoomEncryption(_) = other_state.content());
|
||||
assert_ne!(value.as_event().unwrap().get_shield(false), ShieldState::None);
|
||||
assert_ne!(value.as_event().unwrap().get_shield(false), TimelineEventShieldState::None);
|
||||
|
||||
// New message event is received and has a shield.
|
||||
assert_let!(VectorDiff::PushBack { value } = &timeline_updates[2]);
|
||||
assert_ne!(value.as_event().unwrap().get_shield(false), ShieldState::None);
|
||||
assert_ne!(value.as_event().unwrap().get_shield(false), TimelineEventShieldState::None);
|
||||
|
||||
assert_pending!(stream);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user