Browse Source

chore: Upgrade matrix-sdk and ruma

And run `cargo update`.
pipelines/767384
Kévin Commaille 1 year ago committed by Kévin Commaille
parent
commit
752f8941c0
  1. 972
      Cargo.lock
  2. 12
      Cargo.toml
  3. 2
      src/prelude.rs
  4. 141
      src/session/model/room/event/mod.rs
  5. 25
      src/session/model/room/mod.rs
  6. 2
      src/session/model/room/permissions.rs
  7. 27
      src/session/model/room/timeline/mod.rs
  8. 2
      src/session/model/session.rs
  9. 23
      src/session/model/verification/identity_verification.rs
  10. 2
      src/session/view/account_settings/general_page/mod.rs
  11. 3
      src/session/view/content/room_details/edit_details_subpage.rs
  12. 28
      src/session/view/content/room_history/item_row.rs
  13. 12
      src/session/view/content/room_history/message_toolbar/composer_state.rs
  14. 5
      src/session/view/content/room_history/message_toolbar/mod.rs
  15. 18
      src/session/view/content/room_history/mod.rs
  16. 73
      src/utils/matrix/ext_traits.rs
  17. 30
      src/utils/matrix/mod.rs
  18. 14
      src/utils/media/image/mod.rs
  19. 8
      src/utils/media/image/queue.rs

972
Cargo.lock generated

File diff suppressed because it is too large Load Diff

12
Cargo.toml

@ -67,7 +67,7 @@ sourceview = { package = "sourceview5", version = "0.9" }
[dependencies.matrix-sdk]
git = "https://github.com/matrix-org/matrix-rust-sdk.git"
rev = "ee4ef2eb539f25d69ea3582a80646e467adceafd"
rev = "e55a1c7e00d2693d87d798f09852161d5cbf0495"
features = [
"socks",
"sso-login",
@ -77,16 +77,16 @@ features = [
[dependencies.matrix-sdk-ui]
git = "https://github.com/matrix-org/matrix-rust-sdk.git"
rev = "ee4ef2eb539f25d69ea3582a80646e467adceafd"
rev = "e55a1c7e00d2693d87d798f09852161d5cbf0495"
[dependencies.ruma]
# version = "0.10"
git = "https://github.com/ruma/ruma.git"
rev = "26165b23fc2ae9928c5497a21db3d31f4b44cc2a"
version = "0.11"
# git = "https://github.com/ruma/ruma.git"
# rev = "26165b23fc2ae9928c5497a21db3d31f4b44cc2a"
features = [
"unstable-unspecified",
"client-api-c",
"compat-key-id",
"compat-server-signing-key-version",
"compat-user-id",
"compat-empty-string-null",
"compat-null",

2
src/prelude.rs

@ -8,7 +8,7 @@ pub use crate::{
session_list::SessionInfoExt,
user_facing_error::UserFacingError,
utils::{
matrix::AtMentionExt,
matrix::ext_traits::*,
string::{StrExt, StrMutExt},
LocationExt,
},

141
src/session/model/room/event/mod.rs

@ -1,10 +1,8 @@
use std::{borrow::Cow, fmt};
use gtk::{gio, glib, glib::closure_local, prelude::*, subclass::prelude::*};
use indexmap::IndexMap;
use matrix_sdk_ui::timeline::{
AnyOtherFullStateEventContent, Error as TimelineError, EventSendState, EventTimelineItem,
RepliedToEvent, TimelineDetails, TimelineItemContent,
RepliedToEvent, TimelineDetails, TimelineEventItemId, TimelineItemContent, TimelineUniqueId,
};
use ruma::{
events::{
@ -13,7 +11,7 @@ use ruma::{
AnySyncTimelineEvent, Mentions, TimelineEventType,
},
serde::Raw,
EventId, MatrixToUri, MatrixUri, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId,
MatrixToUri, MatrixUri, MilliSecondsSinceUnixEpoch, OwnedEventId, OwnedTransactionId,
OwnedUserId,
};
use serde::{de::IgnoredAny, Deserialize};
@ -36,51 +34,6 @@ use crate::{
utils::matrix::{raw_eq, MediaMessage, VisualMediaMessage},
};
/// The unique key to identify an event in a room.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum EventKey {
/// This is the local echo of the event, the key is its transaction ID.
TransactionId(OwnedTransactionId),
/// This is the remote echo of the event, the key is its event ID.
EventId(OwnedEventId),
}
impl fmt::Display for EventKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
EventKey::TransactionId(txn_id) => write!(f, "transaction_id:{txn_id}"),
EventKey::EventId(event_id) => write!(f, "event_id:{event_id}"),
}
}
}
impl StaticVariantType for EventKey {
fn static_variant_type() -> Cow<'static, glib::VariantTy> {
Cow::Borrowed(glib::VariantTy::STRING)
}
}
impl ToVariant for EventKey {
fn to_variant(&self) -> glib::Variant {
self.to_string().to_variant()
}
}
impl FromVariant for EventKey {
fn from_variant(variant: &glib::Variant) -> Option<Self> {
let s = variant.str()?;
if let Some(s) = s.strip_prefix("transaction_id:") {
Some(EventKey::TransactionId(s.into()))
} else if let Some(s) = s.strip_prefix("event_id:") {
EventId::parse(s).ok().map(EventKey::EventId)
} else {
None
}
}
}
#[derive(Debug, Default, Hash, Eq, PartialEq, Clone, Copy, glib::Enum)]
#[enum_type(name = "MessageState")]
pub enum MessageState {
@ -147,9 +100,8 @@ mod imp {
/// server, as a string.
#[property(get = Self::event_id_string)]
pub event_id_string: PhantomData<Option<String>>,
/// The ID of this `Event` in the SDK timeline.
#[property(get = Self::timeline_id, type = String)]
pub timeline_id: RefCell<Option<String>>,
/// The unique local ID of this `Event` in the SDK timeline.
timeline_id: RefCell<Option<TimelineUniqueId>>,
/// The ID of the sender of this `Event`, as a string.
#[property(get = Self::sender_id_string)]
pub sender_id_string: PhantomData<String>,
@ -227,7 +179,7 @@ mod imp {
impl TimelineItemImpl for Event {
fn id(&self) -> String {
format!("Event::{}", self.obj().key())
format!("Event::{:?}", self.identifier())
}
fn can_hide_header(&self) -> bool {
@ -245,7 +197,7 @@ mod imp {
impl Event {
/// Set the underlying SDK timeline item of this `Event`.
pub fn set_item(&self, item: EventTimelineItem, timeline_id: &str) {
pub fn set_item(&self, item: EventTimelineItem, timeline_id: TimelineUniqueId) {
let obj = self.obj();
let prev_raw = self.raw();
@ -259,7 +211,7 @@ mod imp {
obj.update_read_receipts(item.read_receipts());
self.item.replace(Some(item));
self.timeline_id.replace(Some(timeline_id.to_owned()));
self.timeline_id.replace(Some(timeline_id));
if !raw_eq(prev_raw.as_ref(), self.raw().as_ref()) {
obj.notify_source();
@ -288,7 +240,6 @@ mod imp {
obj.update_state();
obj.emit_by_name::<()>("item-changed", &[]);
obj.notify_timeline_id();
}
/// The raw JSON source for this `Event`, if it has been echoed back
@ -325,14 +276,23 @@ mod imp {
.map(ToString::to_string)
}
/// The ID of this `Event` in the SDK timeline.
fn timeline_id(&self) -> String {
/// The unique local ID of this `Event` in the SDK timeline.
pub(super) fn timeline_id(&self) -> TimelineUniqueId {
self.timeline_id
.borrow()
.clone()
.expect("event should always have timeline ID after construction")
}
/// The unique global key of this `Event` in the timeline.
pub(super) fn identifier(&self) -> TimelineEventItemId {
self.item
.borrow()
.as_ref()
.expect("event should always have item after construction")
.identifier()
}
/// The ID of the sender of this `Event`, as a string.
fn sender_id_string(&self) -> String {
self.item
@ -463,12 +423,12 @@ glib::wrapper! {
impl Event {
/// Create a new `Event` with the given SDK timeline item.
pub fn new(item: EventTimelineItem, timeline_id: &str, room: &Room) -> Self {
pub fn new(item: EventTimelineItem, timeline_id: &TimelineUniqueId, room: &Room) -> Self {
let obj = glib::Object::builder::<Self>()
.property("room", room)
.build();
obj.imp().set_item(item, timeline_id);
obj.imp().set_item(item, timeline_id.clone());
obj
}
@ -476,18 +436,22 @@ impl Event {
/// Try to update this `Event` with the given SDK timeline item.
///
/// Returns `true` if the update succeeded.
pub fn try_update_with(&self, item: &EventTimelineItem, timeline_id: &str) -> bool {
match &self.key() {
EventKey::TransactionId(txn_id)
pub fn try_update_with(
&self,
item: &EventTimelineItem,
timeline_id: &TimelineUniqueId,
) -> bool {
match &self.identifier() {
TimelineEventItemId::TransactionId(txn_id)
if item.is_local_echo() && item.transaction_id() == Some(txn_id) =>
{
self.imp().set_item(item.clone(), timeline_id);
self.imp().set_item(item.clone(), timeline_id.clone());
return true;
}
EventKey::EventId(event_id)
TimelineEventItemId::EventId(event_id)
if !item.is_local_echo() && item.event_id() == Some(event_id) =>
{
self.imp().set_item(item.clone(), timeline_id);
self.imp().set_item(item.clone(), timeline_id.clone());
return true;
}
_ => {}
@ -507,43 +471,46 @@ impl Event {
self.imp().raw()
}
/// The unique key of this `Event` in the timeline.
pub fn key(&self) -> EventKey {
let item_ref = self.imp().item.borrow();
let item = item_ref.as_ref().unwrap();
if item.is_local_echo() {
EventKey::TransactionId(item.transaction_id().unwrap().to_owned())
} else {
EventKey::EventId(item.event_id().unwrap().to_owned())
}
/// The unique local ID of this `Event` in the SDK timeline.
pub fn timeline_id(&self) -> TimelineUniqueId {
self.imp().timeline_id()
}
/// Whether the given key matches this `Event`.
/// The unique global identifier of this `Event` in the timeline.
pub fn identifier(&self) -> TimelineEventItemId {
self.imp().identifier()
}
/// Whether the given identifier matches this `Event`.
///
/// The result can be different from comparing two `EventKey`s because an
/// event can have a transaction ID and an event ID.
pub fn matches_key(&self, key: &EventKey) -> bool {
pub fn matches_identifier(&self, identifier: &TimelineEventItemId) -> bool {
let item_ref = self.imp().item.borrow();
let item = item_ref.as_ref().unwrap();
match key {
EventKey::TransactionId(txn_id) => item.transaction_id().is_some_and(|id| id == txn_id),
EventKey::EventId(event_id) => item.event_id().is_some_and(|id| id == event_id),
match identifier {
TimelineEventItemId::TransactionId(txn_id) => {
item.transaction_id().is_some_and(|id| id == txn_id)
}
TimelineEventItemId::EventId(event_id) => {
item.event_id().is_some_and(|id| id == event_id)
}
}
}
/// The event ID of this `Event`, if it has been received from the server.
pub fn event_id(&self) -> Option<OwnedEventId> {
match self.key() {
EventKey::TransactionId(_) => None,
EventKey::EventId(event_id) => Some(event_id),
match self.identifier() {
TimelineEventItemId::TransactionId(_) => None,
TimelineEventItemId::EventId(event_id) => Some(event_id),
}
}
/// The transaction ID of this `Event`, if it is still pending.
pub fn transaction_id(&self) -> Option<OwnedTransactionId> {
match self.key() {
EventKey::TransactionId(txn_id) => Some(txn_id),
EventKey::EventId(_) => None,
match self.identifier() {
TimelineEventItemId::TransactionId(txn_id) => Some(txn_id),
TimelineEventItemId::EventId(_) => None,
}
}
@ -774,7 +741,7 @@ impl Event {
let event_id = self.reply_to_id()?;
self.room()
.timeline()
.event_by_key(&EventKey::EventId(event_id))
.event_by_identifier(&TimelineEventItemId::EventId(event_id))
}
/// Fetch missing details for this event.

25
src/session/model/room/mod.rs

@ -10,8 +10,8 @@ use gtk::{
};
use matrix_sdk::{
deserialized_responses::AmbiguityChange, event_handler::EventHandlerDropGuard,
room::Room as MatrixRoom, send_queue::RoomSendQueueUpdate, DisplayName, Result as MatrixResult,
RoomInfo, RoomMemberships, RoomState,
room::Room as MatrixRoom, send_queue::RoomSendQueueUpdate, Result as MatrixResult,
RoomDisplayName, RoomInfo, RoomMemberships, RoomState,
};
use ruma::{
api::client::{
@ -377,17 +377,17 @@ mod imp {
let mut display_name = if let Some(sdk_display_name) = sdk_display_name {
match sdk_display_name {
DisplayName::Named(s)
| DisplayName::Calculated(s)
| DisplayName::Aliased(s) => s,
// Translators: This is the name of a room that is empty but had another
// user before. Do NOT translate the content between
// '{' and '}', this is a variable name.
DisplayName::EmptyWas(s) => {
RoomDisplayName::Named(s)
| RoomDisplayName::Calculated(s)
| RoomDisplayName::Aliased(s) => s,
RoomDisplayName::EmptyWas(s) => {
// Translators: This is the name of a room that is empty but had another
// user before. Do NOT translate the content between
// '{' and '}', this is a variable name.
gettext_f("Empty Room (was {user})", &[("user", &s)])
}
// Translators: This is the name of a room without other users.
DisplayName::Empty => gettext("Empty Room"),
RoomDisplayName::Empty => gettext("Empty Room"),
}
} else {
Default::default()
@ -1702,10 +1702,9 @@ impl Room {
/// Toggle the `key` reaction on the given related event in this room.
pub async fn toggle_reaction(&self, key: String, event: &Event) -> Result<(), ()> {
let timeline = self.timeline().matrix_timeline();
let event_timeline_id = event.timeline_id();
let identifier = event.identifier();
let handle =
spawn_tokio!(async move { timeline.toggle_reaction(&event_timeline_id, &key).await });
let handle = spawn_tokio!(async move { timeline.toggle_reaction(&identifier, &key).await });
if let Err(error) = handle.await.expect("task was not aborted") {
error!("Could not toggle reaction: {error}");

2
src/session/model/room/permissions.rs

@ -203,7 +203,7 @@ mod imp {
let matrix_room = room.matrix_room();
let matrix_room_clone = matrix_room.clone();
let handle = spawn_tokio!(async move { matrix_room_clone.room_power_levels().await });
let handle = spawn_tokio!(async move { matrix_room_clone.power_levels().await });
match handle.await.expect("task was not aborted") {
Ok(power_levels) => self.update_power_levels(&power_levels),

27
src/session/model/room/timeline/mod.rs

@ -13,7 +13,8 @@ use gtk::{
use matrix_sdk_ui::{
eyeball_im::VectorDiff,
timeline::{
default_event_filter, RoomExt, Timeline as SdkTimeline, TimelineItem as SdkTimelineItem,
default_event_filter, RoomExt, Timeline as SdkTimeline, TimelineEventItemId,
TimelineItem as SdkTimelineItem,
},
};
use ruma::{
@ -30,7 +31,7 @@ pub use self::{
timeline_item::{TimelineItem, TimelineItemExt, TimelineItemImpl},
virtual_item::{VirtualItem, VirtualItemKind},
};
use super::{Event, EventKey, Room};
use super::{Event, Room};
use crate::{prelude::*, spawn, spawn_tokio};
/// The possible states of the timeline.
@ -82,8 +83,9 @@ mod imp {
/// The `GListModel` containing all the timeline items.
#[property(get)]
items: gtk::FlattenListModel,
/// A Hashmap linking `EventKey` to corresponding `Event`
pub(super) event_map: RefCell<HashMap<EventKey, Event>>,
/// A Hashmap linking a `TimelineEventItemId` to the corresponding
/// `Event`.
pub(super) event_map: RefCell<HashMap<TimelineEventItemId, Event>>,
/// The state of the timeline.
#[property(get, builder(TimelineState::default()))]
state: Cell<TimelineState>,
@ -464,7 +466,7 @@ mod imp {
if let Some(event) = item.downcast_ref::<Event>() {
self.event_map
.borrow_mut()
.insert(event.key(), event.clone());
.insert(event.identifier(), event.clone());
// Keep track of the activity of the sender.
if event.counts_as_unread() {
@ -485,7 +487,7 @@ mod imp {
/// Remove the given item from this `Timeline`.
fn remove_item(&self, item: &TimelineItem) {
if let Some(event) = item.downcast_ref::<Event>() {
self.event_map.borrow_mut().remove(&event.key());
self.event_map.borrow_mut().remove(&event.identifier());
if event.is_room_create_event() {
self.set_has_room_create(false);
@ -666,16 +668,17 @@ impl Timeline {
}
}
/// Get the event with the given key from this `Timeline`.
/// Get the event with the given identifier from this `Timeline`.
///
/// Use this method if you are sure the event has already been received.
/// Otherwise use `fetch_event_by_id`.
pub(crate) fn event_by_key(&self, key: &EventKey) -> Option<Event> {
self.imp().event_map.borrow().get(key).cloned()
pub(crate) fn event_by_identifier(&self, identifier: &TimelineEventItemId) -> Option<Event> {
self.imp().event_map.borrow().get(identifier).cloned()
}
/// Get the position of the event with the given key in this `Timeline`.
pub(crate) fn find_event_position(&self, key: &EventKey) -> Option<usize> {
/// Get the position of the event with the given identifier in this
/// `Timeline`.
pub(crate) fn find_event_position(&self, identifier: &TimelineEventItemId) -> Option<usize> {
for (pos, item) in self
.items()
.iter::<glib::Object>()
@ -687,7 +690,7 @@ impl Timeline {
};
if let Some(event) = item.downcast_ref::<Event>() {
if event.key() == *key {
if event.identifier() == *identifier {
return Some(pos);
}
}

2
src/session/model/session.rs

@ -321,7 +321,7 @@ impl Session {
spawn_tokio!(async move {
client
.send_queue()
.respawn_tasks_for_rooms_with_unsent_events()
.respawn_tasks_for_rooms_with_unsent_requests()
.await;
});

23
src/session/model/verification/identity_verification.rs

@ -431,24 +431,25 @@ impl IdentityVerification {
/// The ID of the other device that is being verified.
pub fn other_device_id(&self) -> Option<OwnedDeviceId> {
let verification = match self.request().state() {
let request_state = self.request().state();
let other_device_data = match &request_state {
VerificationRequestState::Requested {
other_device_id, ..
other_device_data, ..
}
| VerificationRequestState::Ready {
other_device_id, ..
} => return Some(other_device_id),
VerificationRequestState::Transitioned { verification } => verification,
other_device_data, ..
} => other_device_data,
VerificationRequestState::Transitioned { verification } => match verification {
Verification::SasV1(sas) => sas.other_device(),
Verification::QrV1(qr) => qr.other_device(),
_ => None?,
},
VerificationRequestState::Created { .. }
| VerificationRequestState::Done
| VerificationRequestState::Cancelled(_) => return None,
| VerificationRequestState::Cancelled(_) => None?,
};
match verification {
Verification::SasV1(sas) => Some(sas.other_device().device_id().to_owned()),
Verification::QrV1(qr) => Some(qr.other_device().device_id().to_owned()),
_ => None,
}
Some(other_device_data.device_id().to_owned())
}
/// Set whether this request was accepted.

2
src/session/view/account_settings/general_page/mod.rs

@ -237,7 +237,7 @@ impl GeneralPage {
let client = session.client();
let client_clone = client.clone();
let handle =
spawn_tokio!(async move { client_clone.media().upload(&info.mime, data).await });
spawn_tokio!(async move { client_clone.media().upload(&info.mime, data, None).await });
let uri = match handle.await.unwrap() {
Ok(res) => res.content_uri,

3
src/session/view/content/room_details/edit_details_subpage.rs

@ -195,7 +195,8 @@ mod imp {
return;
};
let client = session.client();
let handle = spawn_tokio!(async move { client.media().upload(&info.mime, data).await });
let handle =
spawn_tokio!(async move { client.media().upload(&info.mime, data, None).await });
let uri = match handle.await.unwrap() {
Ok(res) => res.content_uri,

28
src/session/view/content/room_history/item_row.rs

@ -3,7 +3,7 @@ use std::sync::LazyLock;
use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk::{gio, glib, glib::clone};
use matrix_sdk_ui::timeline::TimelineItemContent;
use matrix_sdk_ui::timeline::{TimelineEventItemId, TimelineItemContent};
use ruma::events::room::message::MessageType;
use tracing::error;
@ -12,7 +12,7 @@ use crate::{
components::{ContextMenuBin, ContextMenuBinExt, ContextMenuBinImpl},
prelude::*,
session::{
model::{Event, EventKey, MessageState, Room, TimelineItem, VirtualItem, VirtualItemKind},
model::{Event, MessageState, Room, TimelineItem, VirtualItem, VirtualItemKind},
view::{content::room_history::message_toolbar::ComposerState, EventDetailsDialog},
},
spawn, spawn_tokio, toast,
@ -222,14 +222,22 @@ mod imp {
obj,
move |composer_state| {
obj.update_for_related_event(
composer_state.related_to().map(|i| i.key()).as_ref(),
composer_state
.related_to()
.map(|info| info.identifier())
.as_ref(),
);
}
));
self.composer_state
.set(composer_state, vec![composer_state_handler]);
obj.update_for_related_event(composer_state.related_to().map(|i| i.key()).as_ref());
obj.update_for_related_event(
composer_state
.related_to()
.map(|info| info.identifier())
.as_ref(),
);
}
/// Set the [`TimelineItem`] presented by this row.
@ -483,11 +491,13 @@ impl ItemRow {
emoji_chooser.popup();
}
/// Update this row for the related event with the given key.
fn update_for_related_event(&self, related_event_id: Option<&EventKey>) {
/// Update this row for the related event with the given identifier.
fn update_for_related_event(&self, related_event_id: Option<&TimelineEventItemId>) {
let event = self.item().and_downcast::<Event>();
if event.is_some_and(|event| related_event_id.is_some_and(|key| event.matches_key(key))) {
if event.is_some_and(|event| {
related_event_id.is_some_and(|identifier| event.matches_identifier(identifier))
}) {
self.add_css_class("selected");
} else {
self.remove_css_class("selected");
@ -979,8 +989,8 @@ impl ItemRow {
};
let matrix_timeline = event.room().timeline().matrix_timeline();
let event_item = event.item();
let handle = spawn_tokio!(async move { matrix_timeline.redact(&event_item, None).await });
let identifier = event.identifier();
let handle = spawn_tokio!(async move { matrix_timeline.redact(&identifier, None).await });
if let Err(error) = handle.await.unwrap() {
error!("Could not discard local event: {error}");

12
src/session/view/content/room_history/message_toolbar/composer_state.rs

@ -5,7 +5,7 @@ use gtk::{
subclass::prelude::*,
};
use matrix_sdk::{ComposerDraft, ComposerDraftType};
use matrix_sdk_ui::timeline::{Message, RepliedToInfo};
use matrix_sdk_ui::timeline::{Message, RepliedToInfo, TimelineEventItemId};
use ruma::{
events::room::message::{MessageFormat, MessageType},
OwnedEventId, RoomOrAliasId, UserId,
@ -17,7 +17,7 @@ use super::{MessageBufferChunk, MessageBufferParser};
use crate::{
components::{AtRoom, Pill, PillSource},
prelude::*,
session::model::{EventKey, Member, Room},
session::model::{Member, Room},
spawn, spawn_tokio,
utils::matrix::{find_at_room, find_html_mentions, AT_ROOM},
};
@ -569,11 +569,11 @@ pub enum RelationInfo {
}
impl RelationInfo {
/// The unique key of the related event.
pub fn key(&self) -> EventKey {
/// The unique global identifier of the related event.
pub fn identifier(&self) -> TimelineEventItemId {
match self {
RelationInfo::Reply(info) => EventKey::EventId(info.event_id().to_owned()),
RelationInfo::Edit(event_id) => EventKey::EventId(event_id.clone()),
RelationInfo::Reply(info) => TimelineEventItemId::EventId(info.event_id().to_owned()),
RelationInfo::Edit(event_id) => TimelineEventItemId::EventId(event_id.clone()),
}
}

5
src/session/view/content/room_history/message_toolbar/mod.rs

@ -554,7 +554,8 @@ impl MessageToolbar {
let handle = spawn_tokio!(async move {
let full_content = matrix_room
.make_edit_event(&event_id, EditedContent::RoomMessage(content))
.await?;
.await
.map_err(matrix_sdk_ui::timeline::EditError::from)?;
let send_queue = matrix_room.send_queue();
send_queue.send(full_content).await?;
Ok::<(), matrix_sdk_ui::timeline::Error>(())
@ -1014,7 +1015,7 @@ impl MessageToolbar {
if let Some(related_to) = self.current_composer_state().related_to() {
self.activate_action(
"room-history.scroll-to-event",
Some(&related_to.key().to_variant()),
Some(&related_to.identifier().to_variant()),
)
.unwrap();
}

18
src/session/view/content/room_history/mod.rs

@ -16,6 +16,7 @@ use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk::{gdk, gio, glib, glib::clone, graphene::Point, CompositeTemplate};
use matrix_sdk::ruma::EventId;
use matrix_sdk_ui::timeline::TimelineEventItemId;
use ruma::{api::client::receipt::create_receipt::v3::ReceiptType, OwnedEventId};
use tracing::{error, warn};
@ -30,8 +31,7 @@ use crate::{
components::{confirm_leave_room_dialog, DragOverlay, QuickReactionChooser},
prelude::*,
session::model::{
Event, EventKey, MemberList, Membership, ReceiptPosition, Room, RoomCategory, Timeline,
TimelineState,
Event, MemberList, Membership, ReceiptPosition, Room, RoomCategory, Timeline, TimelineState,
},
spawn, toast,
utils::{template_callbacks::TemplateCallbacks, BoundObject},
@ -157,9 +157,9 @@ mod imp {
klass.install_action(
"room-history.scroll-to-event",
Some(&EventKey::static_variant_type()),
Some(&TimelineEventItemId::static_variant_type()),
|obj, _, v| {
if let Some(event_key) = v.and_then(EventKey::from_variant) {
if let Some(event_key) = v.and_then(TimelineEventItemId::from_variant) {
obj.imp().scroll_to_event(&event_key);
}
},
@ -176,7 +176,8 @@ mod imp {
if let Some(event) = obj
.room()
.and_then(|room| {
room.timeline().event_by_key(&EventKey::EventId(event_id))
room.timeline()
.event_by_identifier(&TimelineEventItemId::EventId(event_id))
})
.and_downcast_ref()
{
@ -197,7 +198,8 @@ mod imp {
if let Some(event) = obj
.room()
.and_then(|room| {
room.timeline().event_by_key(&EventKey::EventId(event_id))
room.timeline()
.event_by_identifier(&TimelineEventItemId::EventId(event_id))
})
.and_downcast_ref()
{
@ -677,8 +679,8 @@ mod imp {
));
}
/// Scroll to the event with the given key.
fn scroll_to_event(&self, key: &EventKey) {
/// Scroll to the event with the given identifier.
fn scroll_to_event(&self, key: &TimelineEventItemId) {
let Some(room) = self.room.obj() else {
return;
};

73
src/utils/matrix/ext_traits.rs

@ -0,0 +1,73 @@
//! Extension traits for Matrix types.
use std::borrow::Cow;
use gtk::{glib, prelude::*};
use matrix_sdk_ui::timeline::{Message, TimelineEventItemId, TimelineItemContent};
/// Helper trait for types possibly containing an `@room` mention.
pub trait AtMentionExt {
/// Whether this event might contain an `@room` mention.
///
/// This means that either it doesn't have intentional mentions, or it has
/// intentional mentions and `room` is set to `true`.
fn can_contain_at_room(&self) -> bool;
}
impl AtMentionExt for TimelineItemContent {
fn can_contain_at_room(&self) -> bool {
match self {
TimelineItemContent::Message(msg) => msg.can_contain_at_room(),
_ => false,
}
}
}
impl AtMentionExt for Message {
fn can_contain_at_room(&self) -> bool {
let Some(mentions) = self.mentions() else {
return true;
};
mentions.room
}
}
/// Extension trait for [`TimelineEventItemId`].
pub trait TimelineEventItemIdExt: Sized {
/// The type used to represent a [`TimelineEventItemId`] as a `GVariant`.
fn static_variant_type() -> Cow<'static, glib::VariantTy>;
/// Convert this [`TimelineEventItemId`] to a `GVariant`.
fn to_variant(&self) -> glib::Variant;
/// Try to convert a `GVariant` to a [`TimelineEventItemId`].
fn from_variant(variant: &glib::Variant) -> Option<Self>;
}
impl TimelineEventItemIdExt for TimelineEventItemId {
fn static_variant_type() -> Cow<'static, glib::VariantTy> {
Cow::Borrowed(glib::VariantTy::STRING)
}
fn to_variant(&self) -> glib::Variant {
let s = match self {
Self::TransactionId(txn_id) => format!("transaction_id:{txn_id}"),
Self::EventId(event_id) => format!("event_id:{event_id}"),
};
s.to_variant()
}
fn from_variant(variant: &glib::Variant) -> Option<Self> {
let s = variant.str()?;
if let Some(s) = s.strip_prefix("transaction_id:") {
Some(Self::TransactionId(s.into()))
} else if let Some(s) = s.strip_prefix("event_id:") {
s.try_into().ok().map(Self::EventId)
} else {
None
}
}
}

30
src/utils/matrix/mod.rs

@ -11,7 +11,6 @@ use matrix_sdk::{
matrix_auth::{MatrixSession, MatrixSessionTokens},
Client, ClientBuildError, SessionMeta,
};
use matrix_sdk_ui::timeline::{Message, TimelineItemContent};
use ruma::{
events::{
room::{member::MembershipState, message::MessageType},
@ -29,6 +28,7 @@ use ruma::{
};
use thiserror::Error;
pub mod ext_traits;
mod media_message;
pub use self::media_message::{MediaMessage, VisualMediaMessage};
@ -652,31 +652,3 @@ pub enum MatrixIdUriParseError {
#[error("unsupported Matrix ID: {0:?}")]
UnsupportedId(MatrixId),
}
/// Helper trait for types possibly containing an `@room` mention.
pub trait AtMentionExt {
/// Whether this event might contain an `@room` mention.
///
/// This means that either it doesn't have intentional mentions, or it has
/// intentional mentions and `room` is set to `true`.
fn can_contain_at_room(&self) -> bool;
}
impl AtMentionExt for TimelineItemContent {
fn can_contain_at_room(&self) -> bool {
match self {
TimelineItemContent::Message(msg) => msg.can_contain_at_room(),
_ => false,
}
}
}
impl AtMentionExt for Message {
fn can_contain_at_room(&self) -> bool {
let Some(mentions) = self.mentions() else {
return true;
};
mentions.room
}
}

14
src/utils/media/image/mod.rs

@ -7,7 +7,7 @@ use gtk::{gdk, gio, prelude::*};
use image::{ColorType, DynamicImage, ImageDecoder, ImageResult};
use matrix_sdk::{
attachment::{BaseImageInfo, BaseThumbnailInfo, Thumbnail},
media::{MediaFormat, MediaRequest, MediaThumbnailSettings, MediaThumbnailSize},
media::{MediaFormat, MediaRequestParameters, MediaThumbnailSettings},
Client,
};
use ruma::{
@ -466,7 +466,7 @@ impl<'a> ThumbnailDownloader<'a> {
if source.should_thumbnail(settings.prefer_thumbnail, settings.dimensions) {
// Try to get a thumbnail.
let request = MediaRequest {
let request = MediaRequestParameters {
source: source.source.to_common_media_source(),
format: MediaFormat::Thumbnail(settings.into()),
};
@ -480,7 +480,7 @@ impl<'a> ThumbnailDownloader<'a> {
}
// Fallback to downloading the full source.
let request = MediaRequest {
let request = MediaRequestParameters {
source: source.source.to_common_media_source(),
format: MediaFormat::File,
};
@ -674,11 +674,9 @@ impl From<ThumbnailSettings> for MediaThumbnailSettings {
} = value;
MediaThumbnailSettings {
size: MediaThumbnailSize {
method,
width: dimensions.width.into(),
height: dimensions.height.into(),
},
method,
width: dimensions.width.into(),
height: dimensions.height.into(),
animated,
}
}

8
src/utils/media/image/queue.rs

@ -10,7 +10,7 @@ use std::{
use futures_util::future::BoxFuture;
use gtk::glib;
use matrix_sdk::{
media::{MediaRequest, UniqueKey},
media::{MediaRequestParameters, UniqueKey},
Client,
};
use tokio::{
@ -97,7 +97,7 @@ impl ImageRequestQueue {
pub async fn add_download_request(
&self,
client: Client,
settings: MediaRequest,
settings: MediaRequestParameters,
dimensions: Option<FrameDimensions>,
priority: ImageRequestPriority,
) -> ImageRequestHandle {
@ -181,7 +181,7 @@ impl ImageRequestQueueInner {
fn add_download_request(
&mut self,
client: Client,
settings: MediaRequest,
settings: MediaRequestParameters,
dimensions: Option<FrameDimensions>,
priority: ImageRequestPriority,
) -> ImageRequestHandle {
@ -467,7 +467,7 @@ struct DownloadRequestData {
/// The Matrix client to use to make the request.
client: Client,
/// The settings of the request.
settings: MediaRequest,
settings: MediaRequestParameters,
/// The dimensions to request.
dimensions: Option<FrameDimensions>,
}

Loading…
Cancel
Save