session: Create JoinRoomDialog instead of building it in Session

This commit is contained in:
Kévin Commaille 2023-04-10 10:43:53 +02:00
parent 686de7b5b6
commit 3541be94eb
No known key found for this signature in database
GPG key ID: DD507DAE96E8245C
4 changed files with 196 additions and 64 deletions

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="AdwMessageDialog" id="dialog">
<template class="JoinRoomDialog" parent="AdwMessageDialog">
<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>
@ -12,7 +12,8 @@
<property name="extra-child">
<object class="GtkEntry" id="entry">
<property name="activates-default">True</property>
<signal name="changed" handler="entry_changed" swapped="yes"/>
</object>
</property>
</object>
</template>
</interface>

View file

@ -85,6 +85,7 @@ src/session/content/room_history/typing_row.rs
src/session/content/room_history/verification_info_bar.rs
src/session/content/verification/identity_verification_widget.rs
src/session/content/verification/session_verification.rs
src/session/join_room_dialog.rs
src/session/mod.rs
src/session/room/event/event_actions.rs
src/session/room/member.rs

View file

@ -0,0 +1,187 @@
use adw::{prelude::*, subclass::prelude::*};
use gettextrs::gettext;
use gtk::{gdk, glib, CompositeTemplate};
use ruma::{
matrix_uri::MatrixId, MatrixToUri, MatrixUri, OwnedRoomOrAliasId, OwnedServerName,
RoomOrAliasId,
};
use crate::session::Session;
mod imp {
use glib::{object::WeakRef, subclass::InitializingObject};
use super::*;
#[derive(Debug, Default, CompositeTemplate)]
#[template(resource = "/org/gnome/Fractal/join-room-dialog.ui")]
pub struct JoinRoomDialog {
pub session: WeakRef<Session>,
#[template_child]
pub entry: TemplateChild<gtk::Entry>,
}
#[glib::object_subclass]
impl ObjectSubclass for JoinRoomDialog {
const NAME: &'static str = "JoinRoomDialog";
type Type = super::JoinRoomDialog;
type ParentType = adw::MessageDialog;
fn class_init(klass: &mut Self::Class) {
Self::bind_template(klass);
Self::Type::bind_template_callbacks(klass);
klass.add_binding(
gdk::Key::Escape,
gdk::ModifierType::empty(),
|obj, _| {
obj.close();
true
},
None,
);
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
impl ObjectImpl for JoinRoomDialog {
fn properties() -> &'static [glib::ParamSpec] {
use once_cell::sync::Lazy;
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![glib::ParamSpecObject::builder::<Session>("session")
.explicit_notify()
.build()]
});
PROPERTIES.as_ref()
}
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
match pspec.name() {
"session" => self.obj().set_session(value.get().unwrap()),
_ => unimplemented!(),
}
}
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"session" => self.obj().session().to_value(),
_ => unimplemented!(),
}
}
}
impl WidgetImpl for JoinRoomDialog {}
impl WindowImpl for JoinRoomDialog {}
impl MessageDialogImpl for JoinRoomDialog {
fn response(&self, response: &str) {
self.obj().join_room();
self.parent_response(response)
}
}
}
glib::wrapper! {
/// Dialog to join a room.
pub struct JoinRoomDialog(ObjectSubclass<imp::JoinRoomDialog>)
@extends gtk::Widget, gtk::Window, adw::MessageDialog, @implements gtk::Accessible;
}
#[gtk::template_callbacks]
impl JoinRoomDialog {
pub fn new(parent_window: Option<&impl IsA<gtk::Window>>, session: &Session) -> Self {
glib::Object::builder()
.property("transient-for", parent_window)
.property("session", session)
.build()
}
/// The current session.
pub fn session(&self) -> Option<Session> {
self.imp().session.upgrade()
}
/// Set the current session.
pub fn set_session(&self, session: Option<&Session>) {
let imp = self.imp();
if self.session().as_ref() == session {
return;
}
imp.session.set(session);
self.notify("session");
}
/// Handle when the entry text changed.
#[template_callback]
fn entry_changed(&self, entry: &gtk::Entry) {
let Some(session) = self.session() else {
self.set_response_enabled("join", false);
return;
};
let Some((room_id, _)) = parse_room(&entry.text()) else {
self.set_response_enabled("join", false);
return;
};
self.set_response_enabled("join", true);
if session.room_list().find_joined_room(&room_id).is_some() {
self.set_response_label("join", &gettext("_View"));
} else {
self.set_response_label("join", &gettext("_Join"));
}
}
/// Join the room that was entered, if it is valid.
fn join_room(&self) {
let Some(session) = self.session() else {
return;
};
let Some((room_id, via)) = parse_room(&self.imp().entry.text()) else {
return;
};
if let Some(room) = session.room_list().find_joined_room(&room_id) {
session.select_room(Some(room));
} else {
session.room_list().join_by_id_or_alias(room_id, via)
}
}
}
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(|| {
MatrixToUri::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(|| {
RoomOrAliasId::parse(room)
.ok()
.map(|room_id| (room_id, vec![]))
})
}

View file

@ -2,6 +2,7 @@ mod account_settings;
mod avatar;
mod content;
mod event_source_dialog;
mod join_room_dialog;
mod media_viewer;
pub mod room;
mod room_creation;
@ -36,9 +37,7 @@ use matrix_sdk::{
direct::DirectEventContent, room::encryption::SyncRoomEncryptionEvent,
GlobalAccountDataEvent,
},
matrix_uri::MatrixId,
MatrixToUri, MatrixUri, OwnedEventId, OwnedRoomId, OwnedRoomOrAliasId, OwnedServerName,
RoomId, RoomOrAliasId,
OwnedEventId, OwnedRoomId, RoomId,
},
sync::SyncResponse,
Client,
@ -49,6 +48,7 @@ use tokio::task::JoinHandle;
use self::{
account_settings::AccountSettings,
content::{verification::SessionVerification, Content},
join_room_dialog::JoinRoomDialog,
media_viewer::MediaViewer,
room_list::RoomList,
sidebar::Sidebar,
@ -684,37 +684,8 @@ impl Session {
}
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.choose_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)
}
}
let dialog = JoinRoomDialog::new(self.parent_window().as_ref(), self);
dialog.present();
}
pub async fn logout(&self) {
@ -1004,34 +975,6 @@ impl Session {
}
}
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(|| {
MatrixToUri::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(|| {
RoomOrAliasId::parse(room)
.ok()
.map(|room_id| (room_id, vec![]))
})
}
fn notification_id(session_id: &str, room_id: &RoomId, event_id: &EventId) -> String {
format!("{session_id}:{room_id}:{event_id}")
}