[fractal] session: Allow to join a room by ID, alias or permalink



commit 5d7d49a9733d6e0c275df33b2cdd8218f88cf7bd
Author: Kévin Commaille <zecakeh tedomum fr>
Date:   Tue Oct 4 16:25:05 2022 +0200

    session: Allow to join a room by ID, alias or permalink

 data/resources/resources.gresource.xml     |  1 +
 data/resources/ui/join-room-dialog.ui      | 18 +++++++
 data/resources/ui/sidebar.ui               |  5 +-
 po/POTFILES.in                             |  1 +
 src/session/content/explore/public_room.rs |  2 +-
 src/session/mod.rs                         | 79 +++++++++++++++++++++++++++---
 src/session/room/mod.rs                    | 12 +++++
 src/session/room_list.rs                   | 24 +++++++--
 8 files changed, 129 insertions(+), 13 deletions(-)
---
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index 58d0a9fb1..1ab003879 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -112,6 +112,7 @@
     <file compressed="true" preprocess="xml-stripblanks" 
alias="event-source-dialog.ui">ui/event-source-dialog.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" alias="greeter.ui">ui/greeter.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" 
alias="identity-verification-widget.ui">ui/identity-verification-widget.ui</file>
+    <file compressed="true" preprocess="xml-stripblanks" 
alias="join-room-dialog.ui">ui/join-room-dialog.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" 
alias="login-advanced-dialog.ui">ui/login-advanced-dialog.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" 
alias="login-idp-button.ui">ui/login-idp-button.ui</file>
     <file compressed="true" preprocess="xml-stripblanks" alias="login.ui">ui/login.ui</file>
diff --git a/data/resources/ui/join-room-dialog.ui b/data/resources/ui/join-room-dialog.ui
new file mode 100644
index 000000000..d12ba2e7e
--- /dev/null
+++ b/data/resources/ui/join-room-dialog.ui
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="AdwMessageDialog" id="dialog">
+    <property name="heading" translatable="yes">Join a Room</property>
+    <property name="body" translatable="yes">Enter a room ID, room alias, or permalink.</property>
+    <property name="default-response">join</property>
+    <property name="close-response">cancel</property>
+    <responses>
+      <response id="cancel" translatable="yes">_Cancel</response>
+      <response id="join" translatable="yes" appearance="suggested" enabled="false">_Join</response>
+    </responses>
+    <property name="extra-child">
+      <object class="GtkEntry" id="entry">
+        <property name="activates-default">True</property>
+      </object>
+    </property>
+  </object>
+</interface>
diff --git a/data/resources/ui/sidebar.ui b/data/resources/ui/sidebar.ui
index 69b31d73a..1b4c94617 100644
--- a/data/resources/ui/sidebar.ui
+++ b/data/resources/ui/sidebar.ui
@@ -6,6 +6,10 @@
         <attribute name="label" translatable="yes">_New Room</attribute>
         <attribute name="action">session.room-creation</attribute>
       </item>
+      <item>
+        <attribute name="label" translatable="yes">_Join Room</attribute>
+        <attribute name="action">session.show-join-room</attribute>
+      </item>
     </section>
     <section>
       <item>
@@ -170,4 +174,3 @@
     </child>
   </template>
 </interface>
-
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 78987dfa3..abc18a60c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -34,6 +34,7 @@ data/resources/ui/event-menu.ui
 data/resources/ui/event-source-dialog.ui
 data/resources/ui/greeter.ui
 data/resources/ui/identity-verification-widget.ui
+data/resources/ui/join-room-dialog.ui
 data/resources/ui/login-advanced-dialog.ui
 data/resources/ui/login.ui
 data/resources/ui/member-menu.ui
diff --git a/src/session/content/explore/public_room.rs b/src/session/content/explore/public_room.rs
index 9995251d3..50b668b97 100644
--- a/src/session/content/explore/public_room.rs
+++ b/src/session/content/explore/public_room.rs
@@ -193,7 +193,7 @@ impl PublicRoom {
         } else if let Some(matrix_public_room) = self.matrix_public_room() {
             let room_id: &RoomId = matrix_public_room.room_id.as_ref();
             self.room_list()
-                .join_by_id_or_alias(<&RoomOrAliasId>::from(room_id).to_owned());
+                .join_by_id_or_alias(<&RoomOrAliasId>::from(room_id).to_owned(), vec![]);
         }
     }
 }
diff --git a/src/session/mod.rs b/src/session/mod.rs
index 53265685f..780469688 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -13,16 +13,12 @@ pub mod verification;
 
 use std::{collections::HashSet, fs, path::PathBuf, time::Duration};
 
-use adw::subclass::prelude::BinImpl;
+use adw::{prelude::*, subclass::prelude::*};
 use futures::StreamExt;
 use gettextrs::gettext;
 use gtk::{
-    self, gdk, gio,
-    gio::prelude::*,
-    glib,
+    self, gdk, gio, glib,
     glib::{clone, signal::SignalHandlerId},
-    prelude::*,
-    subclass::prelude::*,
     CompositeTemplate,
 };
 use log::{debug, error, warn};
@@ -44,7 +40,8 @@ use matrix_sdk::{
             direct::DirectEventContent, room::encryption::SyncRoomEncryptionEvent,
             GlobalAccountDataEvent,
         },
-        RoomId,
+        matrix_uri::MatrixId,
+        MatrixUri, OwnedRoomOrAliasId, OwnedServerName, RoomId, RoomOrAliasId,
     },
     store::{MigrationConflictStrategy, OpenStoreError, SledStateStore},
     Client, ClientBuildError, Error, HttpError, RumaApiError, StoreError,
@@ -74,7 +71,7 @@ use crate::{
     secret::{Secret, StoredSession},
     session::sidebar::ItemList,
     spawn, spawn_tokio, toast,
-    utils::check_if_reachable,
+    utils::{check_if_reachable, parse_matrix_to_uri},
     UserFacingError, Window,
 };
 
@@ -174,6 +171,12 @@ mod imp {
                 session.show_room_creation_dialog();
             });
 
+            klass.install_action("session.show-join-room", None, move |widget, _, _| {
+                spawn!(clone!(@weak widget => async move {
+                    widget.show_join_room_dialog().await;
+                }));
+            });
+
             klass.add_binding_action(
                 gdk::Key::Escape,
                 gdk::ModifierType::empty(),
@@ -821,6 +824,40 @@ impl Session {
         window.show();
     }
 
+    async fn show_join_room_dialog(&self) {
+        let builder = gtk::Builder::from_resource("/org/gnome/Fractal/join-room-dialog.ui");
+        let dialog = builder.object::<adw::MessageDialog>("dialog").unwrap();
+        let entry = builder.object::<gtk::Entry>("entry").unwrap();
+
+        entry.connect_changed(clone!(@weak self as obj, @weak dialog => move |entry| {
+            let room = parse_room(&entry.text());
+            dialog.set_response_enabled("join", room.is_some());
+
+            if room
+                .and_then(|(room_id, _)| obj.room_list().find_joined_room(&room_id))
+                .is_some()
+            {
+                dialog.set_response_label("join", &gettext("_View"));
+            } else {
+                dialog.set_response_label("join", &gettext("_Join"));
+            }
+        }));
+
+        dialog.set_transient_for(self.parent_window().as_ref());
+        if dialog.run_future().await == "join" {
+            let (room_id, via) = match parse_room(&entry.text()) {
+                Some(room) => room,
+                None => return,
+            };
+
+            if let Some(room) = self.room_list().find_joined_room(&room_id) {
+                self.select_room(Some(room));
+            } else {
+                self.room_list().join_by_id_or_alias(room_id, via)
+            }
+        }
+    }
+
     pub async fn logout(&self, cleanup: bool) {
         let stack = &self.imp().stack;
         self.emit_by_name::<()>("logged-out", &[]);
@@ -1027,3 +1064,29 @@ async fn create_client(
         .await
         .map_err(Into::into)
 }
+
+fn parse_room(room: &str) -> Option<(OwnedRoomOrAliasId, Vec<OwnedServerName>)> {
+    MatrixUri::parse(room)
+        .ok()
+        .and_then(|uri| match uri.id() {
+            MatrixId::Room(room_id) => Some((room_id.clone().into(), uri.via().to_owned())),
+            MatrixId::RoomAlias(room_alias) => {
+                Some((room_alias.clone().into(), uri.via().to_owned()))
+            }
+            _ => None,
+        })
+        .or_else(|| {
+            parse_matrix_to_uri(room)
+                .ok()
+                .and_then(|(id, via)| match id {
+                    MatrixId::Room(room_id) => Some((room_id.into(), via)),
+                    MatrixId::RoomAlias(room_alias) => Some((room_alias.into(), via)),
+                    _ => None,
+                })
+        })
+        .or_else(|| {
+            RoomOrAliasId::parse(room)
+                .ok()
+                .map(|room_id| (room_id, vec![]))
+        })
+}
diff --git a/src/session/room/mod.rs b/src/session/room/mod.rs
index e5256d5bd..efbd5e09f 100644
--- a/src/session/room/mod.rs
+++ b/src/session/room/mod.rs
@@ -466,6 +466,18 @@ impl Room {
         );
     }
 
+    pub fn is_joined(&self) -> bool {
+        matches!(
+            self.category(),
+            RoomType::Favorite
+                | RoomType::Normal
+                | RoomType::LowPriority
+                | RoomType::Outdated
+                | RoomType::Space
+                | RoomType::Direct
+        )
+    }
+
     pub fn category(&self) -> RoomType {
         self.imp().category.get()
     }
diff --git a/src/session/room_list.rs b/src/session/room_list.rs
index 7c7dbf52a..74c103475 100644
--- a/src/session/room_list.rs
+++ b/src/session/room_list.rs
@@ -5,7 +5,7 @@ use indexmap::map::IndexMap;
 use log::error;
 use matrix_sdk::{
     deserialized_responses::Rooms as ResponseRooms,
-    ruma::{OwnedRoomId, OwnedRoomOrAliasId, RoomId, RoomOrAliasId},
+    ruma::{OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName, RoomId, RoomOrAliasId},
 };
 
 use crate::{
@@ -298,7 +298,7 @@ impl RoomList {
         }
     }
 
-    pub fn join_by_id_or_alias(&self, identifier: OwnedRoomOrAliasId) {
+    pub fn join_by_id_or_alias(&self, identifier: OwnedRoomOrAliasId, via: Vec<OwnedServerName>) {
         let client = self.session().client();
         let identifier_clone = identifier.clone();
 
@@ -306,7 +306,7 @@ impl RoomList {
 
         let handle = spawn_tokio!(async move {
             client
-                .join_room_by_id_or_alias(&identifier_clone, &[])
+                .join_room_by_id_or_alias(&identifier_clone, &via)
                 .await
         });
 
@@ -344,4 +344,22 @@ impl RoomList {
             None
         })
     }
+
+    pub fn find_joined_room(&self, room_id: &RoomOrAliasId) -> Option<Room> {
+        let room_id = room_id.as_str();
+        self.imp()
+            .list
+            .borrow()
+            .values()
+            .find(|room| {
+                (room.room_id() == room_id
+                    || room
+                        .matrix_room()
+                        .canonical_alias()
+                        .filter(|id| id == room_id)
+                        .is_some())
+                    && room.is_joined()
+            })
+            .cloned()
+    }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]