diff --git a/src/components/dialogs/join_room.rs b/src/components/dialogs/join_room.rs index 4e1a02d4..56794ab6 100644 --- a/src/components/dialogs/join_room.rs +++ b/src/components/dialogs/join_room.rs @@ -9,7 +9,10 @@ use crate::{ prelude::*, session::model::{RemoteRoom, Session}, toast, - utils::{matrix::MatrixRoomIdUri, LoadingState}, + utils::{ + matrix::{MatrixIdUri, MatrixRoomIdUri}, + LoadingState, + }, Window, }; @@ -78,7 +81,32 @@ mod imp { } #[glib::derived_properties] - impl ObjectImpl for JoinRoomDialog {} + impl ObjectImpl for JoinRoomDialog { + fn constructed(&self) { + self.parent_constructed(); + let obj = self.obj(); + + self.room_topic.connect_activate_link(clone!( + #[weak] + obj, + #[upgrade_or] + glib::Propagation::Proceed, + move |_, uri| { + let Ok(uri) = MatrixIdUri::parse(uri) else { + return glib::Propagation::Proceed; + }; + let Some(parent_window) = + obj.ancestor(Window::static_type()).and_downcast::() + else { + return glib::Propagation::Proceed; + }; + + parent_window.session_view().show_matrix_uri(uri); + glib::Propagation::Stop + } + )); + } + } impl WidgetImpl for JoinRoomDialog {} impl AdwDialogImpl for JoinRoomDialog {} diff --git a/src/session/view/content/explore/public_room_row.rs b/src/session/view/content/explore/public_room_row.rs index 6e4bcce4..c27db894 100644 --- a/src/session/view/content/explore/public_room_row.rs +++ b/src/session/view/content/explore/public_room_row.rs @@ -9,7 +9,7 @@ use crate::{ gettext_f, ngettext_f, prelude::*, spawn, toast, - utils::{string::linkify, BoundObject}, + utils::{matrix::MatrixIdUri, string::linkify, BoundObject}, Window, }; @@ -63,6 +63,8 @@ mod imp { impl ObjectImpl for PublicRoomRow { fn constructed(&self) { self.parent_constructed(); + let obj = self.obj(); + self.button.connect_clicked(clone!( #[weak(rename_to = imp)] self, @@ -70,6 +72,22 @@ mod imp { imp.obj().join_or_view(); } )); + + self.description.connect_activate_link(clone!( + #[weak] + obj, + #[upgrade_or] + glib::Propagation::Proceed, + move |_, uri| { + if MatrixIdUri::parse(uri).is_ok() { + let _ = + obj.activate_action("session.show-matrix-uri", Some(&uri.to_variant())); + glib::Propagation::Stop + } else { + glib::Propagation::Proceed + } + } + )); } } diff --git a/src/session/view/content/invite.rs b/src/session/view/content/invite.rs index 2cf7f09c..f1d0776a 100644 --- a/src/session/view/content/invite.rs +++ b/src/session/view/content/invite.rs @@ -8,6 +8,7 @@ use crate::{ prelude::*, session::model::{MemberList, Room, RoomType, User}, toast, + utils::matrix::MatrixIdUri, }; mod imp { @@ -73,6 +74,7 @@ mod imp { impl ObjectImpl for Invite { fn constructed(&self) { self.parent_constructed(); + let obj = self.obj(); self.room_alias.connect_label_notify(|room_alias| { room_alias.set_visible(!room_alias.label().is_empty()); @@ -85,6 +87,21 @@ mod imp { }); self.room_topic .set_visible(!self.room_topic.label().is_empty()); + self.room_topic.connect_activate_link(clone!( + #[weak] + obj, + #[upgrade_or] + glib::Propagation::Proceed, + move |_, uri| { + if MatrixIdUri::parse(uri).is_ok() { + let _ = + obj.activate_action("session.show-matrix-uri", Some(&uri.to_variant())); + glib::Propagation::Stop + } else { + glib::Propagation::Proceed + } + } + )); } fn dispose(&self) { diff --git a/src/session/view/content/room_details/general_page.rs b/src/session/view/content/room_details/general_page.rs index 39dafc07..5847f54f 100644 --- a/src/session/view/content/room_details/general_page.rs +++ b/src/session/view/content/room_details/general_page.rs @@ -21,7 +21,7 @@ use ruma::{ }; use tracing::error; -use super::room_upgrade_dialog::confirm_room_upgrade; +use super::{room_upgrade_dialog::confirm_room_upgrade, RoomDetails}; use crate::{ components::{ ButtonCountRow, ButtonRow, CheckLoadingRow, ComboLoadingRow, CopyableRow, LoadingButton, @@ -34,8 +34,10 @@ use crate::{ }, spawn, spawn_tokio, toast, utils::{ - expression, template_callbacks::TemplateCallbacks, BoundObjectWeakRef, OngoingAsyncAction, + expression, matrix::MatrixIdUri, template_callbacks::TemplateCallbacks, BoundObjectWeakRef, + OngoingAsyncAction, }, + Window, }; mod imp { @@ -143,6 +145,38 @@ mod imp { #[glib::derived_properties] impl ObjectImpl for GeneralPage { + fn constructed(&self) { + self.parent_constructed(); + let obj = self.obj(); + + self.room_topic.connect_activate_link(clone!( + #[weak] + obj, + #[upgrade_or] + glib::Propagation::Proceed, + move |_, uri| { + let Ok(uri) = MatrixIdUri::parse(uri) else { + return glib::Propagation::Proceed; + }; + let Some(room_details) = obj + .ancestor(RoomDetails::static_type()) + .and_downcast::() + else { + return glib::Propagation::Proceed; + }; + let Some(parent_window) = room_details.transient_for().and_downcast::() + else { + return glib::Propagation::Proceed; + }; + + parent_window.session_view().show_matrix_uri(uri); + room_details.close(); + + glib::Propagation::Stop + } + )); + } + fn dispose(&self) { self.disconnect_all(); } diff --git a/src/session/view/session_view.rs b/src/session/view/session_view.rs index a71d9b1b..3d6ebd6b 100644 --- a/src/session/view/session_view.rs +++ b/src/session/view/session_view.rs @@ -14,7 +14,7 @@ use crate::{ Event, IdentityVerification, Room, Selection, Session, SidebarListModel, VerificationKey, }, toast, - utils::matrix::MatrixRoomIdUri, + utils::matrix::{MatrixEventIdUri, MatrixIdUri, MatrixRoomIdUri}, Window, }; @@ -113,6 +113,18 @@ mod imp { gdk::ModifierType::CONTROL_MASK, "session.toggle-room-search", ); + + klass.install_action( + "session.show-matrix-uri", + Some(&MatrixIdUri::static_variant_type()), + |obj, _, parameter| { + if let Some(uri) = parameter.unwrap().get::() { + obj.show_matrix_uri(uri); + } else { + error!("Cannot show invalid Matrix URI"); + } + }, + ); } fn instance_init(obj: &InitializingObject) { @@ -397,4 +409,18 @@ impl SessionView { notifications.withdraw_identity_verification(&verification.key()); } } + + /// Show the given `MatrixIdUri`. + pub fn show_matrix_uri(&self, uri: MatrixIdUri) { + match uri { + MatrixIdUri::Room(room_uri) | MatrixIdUri::Event(MatrixEventIdUri { room_uri, .. }) => { + if !self.select_room_if_exists(&room_uri.id) { + self.show_join_room_dialog(Some(room_uri)); + } + } + MatrixIdUri::User(user_id) => { + self.show_user_profile_dialog(user_id); + } + } + } } diff --git a/src/utils/matrix.rs b/src/utils/matrix.rs index 10c41acc..0fb822ee 100644 --- a/src/utils/matrix.rs +++ b/src/utils/matrix.rs @@ -1,7 +1,8 @@ //! Collection of methods related to the Matrix specification. -use std::str::FromStr; +use std::{borrow::Cow, str::FromStr}; +use gtk::{glib, prelude::*}; use matrix_sdk::{ config::RequestConfig, deserialized_responses::RawAnySyncOrStrippedTimelineEvent, @@ -623,6 +624,18 @@ impl TryFrom for MatrixIdUri { } } +impl StaticVariantType for MatrixIdUri { + fn static_variant_type() -> Cow<'static, glib::VariantTy> { + String::static_variant_type() + } +} + +impl FromVariant for MatrixIdUri { + fn from_variant(variant: &glib::Variant) -> Option { + Self::parse(&variant.get::()?).ok() + } +} + /// A URI for a Matrix room ID. #[derive(Debug, Clone, PartialEq, Eq)] pub struct MatrixRoomIdUri {