mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-19 06:04:31 -04:00
sdk-ui: move conversion between Content::RoomPinnedEvents from ffi to sdk-ui
This commit is contained in:
committed by
Jorge Martin Espinosa
parent
d509d79472
commit
c83fa3a532
@@ -12,17 +12,11 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use matrix_sdk::{crypto::types::events::UtdCause, room::power_levels::power_level_user_changes};
|
||||
use matrix_sdk_ui::timeline::{PollResult, TimelineDetails};
|
||||
use ruma::{
|
||||
events::room::{message::RoomMessageEventContentWithoutRelation, MediaSource},
|
||||
OwnedEventId,
|
||||
};
|
||||
use matrix_sdk_ui::timeline::{PollResult, RoomPinnedEventsChange, TimelineDetails};
|
||||
use ruma::events::room::{message::RoomMessageEventContentWithoutRelation, MediaSource};
|
||||
use tracing::warn;
|
||||
|
||||
use super::ProfileDetails;
|
||||
@@ -355,13 +349,6 @@ pub enum OtherState {
|
||||
Custom { event_type: String },
|
||||
}
|
||||
|
||||
#[derive(Clone, uniffi::Enum)]
|
||||
pub enum RoomPinnedEventsChange {
|
||||
Added,
|
||||
Removed,
|
||||
Changed,
|
||||
}
|
||||
|
||||
impl From<&matrix_sdk_ui::timeline::AnyOtherFullStateEventContent> for OtherState {
|
||||
fn from(content: &matrix_sdk_ui::timeline::AnyOtherFullStateEventContent) -> Self {
|
||||
use matrix_sdk::ruma::events::FullStateEventContent as FullContent;
|
||||
@@ -394,49 +381,7 @@ impl From<&matrix_sdk_ui::timeline::AnyOtherFullStateEventContent> for OtherStat
|
||||
};
|
||||
Self::RoomName { name }
|
||||
}
|
||||
Content::RoomPinnedEvents(c) => {
|
||||
match c {
|
||||
FullContent::Original { content, prev_content } => {
|
||||
let change = if let Some(prev_content) = prev_content {
|
||||
let mut new_pinned: HashSet<&OwnedEventId> =
|
||||
HashSet::from_iter(&content.pinned);
|
||||
if let Some(old_pinned) = &prev_content.pinned {
|
||||
let mut still_pinned: HashSet<&OwnedEventId> =
|
||||
HashSet::from_iter(old_pinned);
|
||||
|
||||
// Newly added elements will be kept in new_pinned, previous ones in
|
||||
// still_pinned instead
|
||||
still_pinned.retain(|item| new_pinned.remove(item));
|
||||
|
||||
let added = !new_pinned.is_empty();
|
||||
let removed = still_pinned.len() < old_pinned.len();
|
||||
if added && removed {
|
||||
RoomPinnedEventsChange::Changed
|
||||
} else if added {
|
||||
RoomPinnedEventsChange::Added
|
||||
} else if removed {
|
||||
RoomPinnedEventsChange::Removed
|
||||
} else {
|
||||
// Any other case
|
||||
RoomPinnedEventsChange::Changed
|
||||
}
|
||||
} else {
|
||||
// We don't know the previous state, so let's assume a generic
|
||||
// change
|
||||
RoomPinnedEventsChange::Changed
|
||||
}
|
||||
} else {
|
||||
// If there is no previous content we can assume the first pinned event
|
||||
// id was just added
|
||||
RoomPinnedEventsChange::Added
|
||||
};
|
||||
Self::RoomPinnedEvents { change }
|
||||
}
|
||||
FullContent::Redacted(_) => {
|
||||
Self::RoomPinnedEvents { change: RoomPinnedEventsChange::Changed }
|
||||
}
|
||||
}
|
||||
}
|
||||
Content::RoomPinnedEvents(c) => Self::RoomPinnedEvents { change: c.into() },
|
||||
Content::RoomPowerLevels(c) => match c {
|
||||
FullContent::Original { content, prev_content } => Self::RoomPowerLevels {
|
||||
users: power_level_user_changes(content, prev_content)
|
||||
|
||||
@@ -58,6 +58,9 @@ use tracing::warn;
|
||||
use crate::timeline::{polls::PollState, TimelineItem};
|
||||
|
||||
mod message;
|
||||
pub(crate) mod pinned_events;
|
||||
|
||||
pub use pinned_events::RoomPinnedEventsChange;
|
||||
|
||||
pub use self::message::{InReplyToDetails, Message, RepliedToEvent};
|
||||
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
// Copyright 2024 The Matrix.org Foundation C.I.C.
|
||||
//
|
||||
// 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.
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use ruma::{
|
||||
events::{room::pinned_events::RoomPinnedEventsEventContent, FullStateEventContent},
|
||||
OwnedEventId,
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
|
||||
/// The type of change between the previous and current pinned events.
|
||||
pub enum RoomPinnedEventsChange {
|
||||
/// Only new event ids were added.
|
||||
Added,
|
||||
/// Only event ids were removed.
|
||||
Removed,
|
||||
/// Some change other than only adding or only removing ids happened.
|
||||
Changed,
|
||||
}
|
||||
|
||||
impl From<&FullStateEventContent<RoomPinnedEventsEventContent>> for RoomPinnedEventsChange {
|
||||
fn from(value: &FullStateEventContent<RoomPinnedEventsEventContent>) -> Self {
|
||||
match value {
|
||||
FullStateEventContent::Original { content, prev_content } => {
|
||||
if let Some(prev_content) = prev_content {
|
||||
let mut new_pinned: HashSet<&OwnedEventId> =
|
||||
HashSet::from_iter(&content.pinned);
|
||||
if let Some(old_pinned) = &prev_content.pinned {
|
||||
let mut still_pinned: HashSet<&OwnedEventId> =
|
||||
HashSet::from_iter(old_pinned);
|
||||
|
||||
// Newly added elements will be kept in new_pinned, previous ones in
|
||||
// still_pinned instead
|
||||
still_pinned.retain(|item| new_pinned.remove(item));
|
||||
|
||||
let added = !new_pinned.is_empty();
|
||||
let removed = still_pinned.len() < old_pinned.len();
|
||||
if added && removed {
|
||||
RoomPinnedEventsChange::Changed
|
||||
} else if added {
|
||||
RoomPinnedEventsChange::Added
|
||||
} else if removed {
|
||||
RoomPinnedEventsChange::Removed
|
||||
} else {
|
||||
// Any other case
|
||||
RoomPinnedEventsChange::Changed
|
||||
}
|
||||
} else {
|
||||
// We don't know the previous state, so let's assume a generic change
|
||||
RoomPinnedEventsChange::Changed
|
||||
}
|
||||
} else {
|
||||
// If there is no previous content we can assume the first pinned event id was
|
||||
// just added
|
||||
RoomPinnedEventsChange::Added
|
||||
}
|
||||
}
|
||||
FullStateEventContent::Redacted(_) => RoomPinnedEventsChange::Changed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use assert_matches::assert_matches;
|
||||
use ruma::{
|
||||
events::{
|
||||
room::pinned_events::{
|
||||
PossiblyRedactedRoomPinnedEventsEventContent, RedactedRoomPinnedEventsEventContent,
|
||||
RoomPinnedEventsEventContent,
|
||||
},
|
||||
FullStateEventContent,
|
||||
},
|
||||
owned_event_id,
|
||||
serde::Raw,
|
||||
};
|
||||
use serde_json::json;
|
||||
|
||||
use crate::timeline::event_item::content::pinned_events::RoomPinnedEventsChange;
|
||||
|
||||
#[test]
|
||||
fn redacted_pinned_events_content_has_generic_changes() {
|
||||
let content = FullStateEventContent::Redacted(RedactedRoomPinnedEventsEventContent::new());
|
||||
let ret: RoomPinnedEventsChange = (&content).into();
|
||||
assert_matches!(ret, RoomPinnedEventsChange::Changed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pinned_events_content_with_no_prev_content_returns_added() {
|
||||
let content = FullStateEventContent::Original {
|
||||
content: RoomPinnedEventsEventContent::new(vec![owned_event_id!("$1")]),
|
||||
prev_content: None,
|
||||
};
|
||||
let ret: RoomPinnedEventsChange = (&content).into();
|
||||
assert_matches!(ret, RoomPinnedEventsChange::Added);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pinned_events_content_with_added_ids_returns_added() {
|
||||
// This is the only way I found to create the PossiblyRedacted content
|
||||
let prev_content = possibly_redacted_content(Vec::new());
|
||||
let content = FullStateEventContent::Original {
|
||||
content: RoomPinnedEventsEventContent::new(vec![owned_event_id!("$1")]),
|
||||
prev_content,
|
||||
};
|
||||
let ret: RoomPinnedEventsChange = (&content).into();
|
||||
assert_matches!(ret, RoomPinnedEventsChange::Added);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pinned_events_content_with_removed_ids_returns_removed() {
|
||||
// This is the only way I found to create the PossiblyRedacted content
|
||||
let prev_content = possibly_redacted_content(vec!["$1"]);
|
||||
let content = FullStateEventContent::Original {
|
||||
content: RoomPinnedEventsEventContent::new(Vec::new()),
|
||||
prev_content,
|
||||
};
|
||||
let ret: RoomPinnedEventsChange = (&content).into();
|
||||
assert_matches!(ret, RoomPinnedEventsChange::Removed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pinned_events_content_with_added_and_removed_ids_returns_changed() {
|
||||
// This is the only way I found to create the PossiblyRedacted content
|
||||
let prev_content = possibly_redacted_content(vec!["$1"]);
|
||||
let content = FullStateEventContent::Original {
|
||||
content: RoomPinnedEventsEventContent::new(vec![owned_event_id!("$2")]),
|
||||
prev_content,
|
||||
};
|
||||
let ret: RoomPinnedEventsChange = (&content).into();
|
||||
assert_matches!(ret, RoomPinnedEventsChange::Changed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pinned_events_content_with_changed_order_returns_changed() {
|
||||
// This is the only way I found to create the PossiblyRedacted content
|
||||
let prev_content = possibly_redacted_content(vec!["$1", "$2"]);
|
||||
let content = FullStateEventContent::Original {
|
||||
content: RoomPinnedEventsEventContent::new(vec![
|
||||
owned_event_id!("$2"),
|
||||
owned_event_id!("$1"),
|
||||
]),
|
||||
prev_content,
|
||||
};
|
||||
let ret: RoomPinnedEventsChange = (&content).into();
|
||||
assert_matches!(ret, RoomPinnedEventsChange::Changed);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pinned_events_content_with_no_changes_returns_changed() {
|
||||
// Returning Changed is counter-intuitive, but it makes no sense to display in
|
||||
// the timeline 'UserFoo didn't change anything in the pinned events'
|
||||
|
||||
// This is the only way I found to create the PossiblyRedacted content
|
||||
let prev_content = possibly_redacted_content(vec!["$1", "$2"]);
|
||||
let content = FullStateEventContent::Original {
|
||||
content: RoomPinnedEventsEventContent::new(vec![
|
||||
owned_event_id!("$1"),
|
||||
owned_event_id!("$2"),
|
||||
]),
|
||||
prev_content,
|
||||
};
|
||||
let ret: RoomPinnedEventsChange = (&content).into();
|
||||
assert_matches!(ret, RoomPinnedEventsChange::Changed);
|
||||
}
|
||||
|
||||
fn possibly_redacted_content(
|
||||
ids: Vec<&str>,
|
||||
) -> Option<PossiblyRedactedRoomPinnedEventsEventContent> {
|
||||
// This is the only way I found to create the PossiblyRedacted content
|
||||
Raw::new(&json!({
|
||||
"pinned": ids,
|
||||
}))
|
||||
.unwrap()
|
||||
.cast::<PossiblyRedactedRoomPinnedEventsEventContent>()
|
||||
.deserialize()
|
||||
.ok()
|
||||
}
|
||||
}
|
||||
@@ -41,8 +41,8 @@ mod remote;
|
||||
pub use self::{
|
||||
content::{
|
||||
AnyOtherFullStateEventContent, EncryptedMessage, InReplyToDetails, MemberProfileChange,
|
||||
MembershipChange, Message, OtherState, RepliedToEvent, RoomMembershipChange, Sticker,
|
||||
TimelineItemContent,
|
||||
MembershipChange, Message, OtherState, RepliedToEvent, RoomMembershipChange,
|
||||
RoomPinnedEventsChange, Sticker, TimelineItemContent,
|
||||
},
|
||||
local::EventSendState,
|
||||
};
|
||||
|
||||
@@ -94,7 +94,8 @@ pub use self::{
|
||||
AnyOtherFullStateEventContent, EncryptedMessage, EventItemOrigin, EventSendState,
|
||||
EventTimelineItem, InReplyToDetails, MemberProfileChange, MembershipChange, Message,
|
||||
OtherState, Profile, ReactionInfo, ReactionsByKeyBySender, RepliedToEvent,
|
||||
RoomMembershipChange, Sticker, TimelineDetails, TimelineEventItemId, TimelineItemContent,
|
||||
RoomMembershipChange, RoomPinnedEventsChange, Sticker, TimelineDetails,
|
||||
TimelineEventItemId, TimelineItemContent,
|
||||
},
|
||||
event_type_filter::TimelineEventTypeFilter,
|
||||
inner::default_event_filter,
|
||||
|
||||
Reference in New Issue
Block a user