session: Allow to join a room by ID, alias or permalink
This commit is contained in:
parent
23691dbf87
commit
5d7d49a973
8 changed files with 129 additions and 13 deletions
|
@ -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>
|
||||
|
|
18
data/resources/ui/join-room-dialog.ui
Normal file
18
data/resources/ui/join-room-dialog.ui
Normal file
|
@ -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>
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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![]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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![]))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue