room: Add dialog to create new rooms
This commit is contained in:
parent
f3f570fc7e
commit
f01d402dd6
9 changed files with 594 additions and 0 deletions
|
@ -39,6 +39,7 @@
|
|||
<file compressed="true" preprocess="xml-stripblanks" alias="account-settings-device-row.ui">ui/account-settings-device-row.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="account-settings-devices-page.ui">ui/account-settings-devices-page.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="components-loading-listbox-row.ui">ui/components-loading-listbox-row.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="room-creation.ui">ui/room-creation.ui</file>
|
||||
<file compressed="true">style.css</file>
|
||||
<file preprocess="xml-stripblanks">icons/scalable/actions/send-symbolic.svg</file>
|
||||
<file preprocess="xml-stripblanks">icons/scalable/status/welcome.svg</file>
|
||||
|
|
182
data/resources/ui/room-creation.ui
Normal file
182
data/resources/ui/room-creation.ui
Normal file
|
@ -0,0 +1,182 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<template class="RoomCreation" parent="AdwWindow">
|
||||
<property name="title" translatable="yes">Create new Room</property>
|
||||
<property name="default-widget">create_button</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="default-width">380</property>
|
||||
<property name="content">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkHeaderBar">
|
||||
<property name="show-title-buttons">False</property>
|
||||
<child type="start">
|
||||
<object class="GtkButton" id="cancel_button">
|
||||
<property name="label" translatable="yes">_Cancel</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="SpinnerButton" id="create_button">
|
||||
<property name="label" translatable="yes">C_reate</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="sensitive">False</property>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRevealer" id="error_label_revealer">
|
||||
<property name="child">
|
||||
<object class="GtkLabel" id="error_label">
|
||||
<property name="wrap">True</property>
|
||||
<property name="wrap-mode">word-char</property>
|
||||
<property name="margin-top">24</property>
|
||||
<style>
|
||||
<class name="error"/>
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkListBox" id="content">
|
||||
<property name="selection-mode">none</property>
|
||||
<property name="margin-top">24</property>
|
||||
<property name="margin-bottom">24</property>
|
||||
<property name="margin-start">24</property>
|
||||
<property name="margin-end">24</property>
|
||||
<style>
|
||||
<class name="content"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Room Name</property>
|
||||
<property name="selectable">False</property>
|
||||
<property name="use_underline">True</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="room_name">
|
||||
<property name="valign">center</property>
|
||||
<property name="vexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRevealer" id="room_name_error_revealer">
|
||||
<property name="child">
|
||||
<object class="GtkLabel" id="room_name_error">
|
||||
<property name="valign">start</property>
|
||||
<property name="xalign">0.0</property>
|
||||
<property name="margin-top">6</property>
|
||||
<style>
|
||||
<class name="error"/>
|
||||
<class name="caption"/>
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="title" translatable="yes">Visibility</property>
|
||||
<property name="selectable">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="valign">center</property>
|
||||
<style>
|
||||
<class name="linked"/>
|
||||
</style>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="private_button">
|
||||
<property name="label" translatable="yes">_Private</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="active">True</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkToggleButton" id="public_button">
|
||||
<property name="label" translatable="yes">P_ublic</property>
|
||||
<property name="use_underline">True</property>
|
||||
<property name="group">private_button</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="visible" bind-source="public_button" bind-property="active" bind-flags="sync-create"/>
|
||||
<property name="title" translatable="yes">Room Address</property>
|
||||
<property name="selectable">False</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="margin-top">6</property>
|
||||
<property name="margin-bottom">6</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="valign">center</property>
|
||||
<property name="spacing">6</property>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="label">#</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkEntry" id="room_address">
|
||||
<property name="valign">center</property>
|
||||
<property name="max-width-chars">10</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="server_name">
|
||||
<property name="label">:gnome.org</property>
|
||||
<style>
|
||||
<class name="dim-label"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkRevealer" id="room_address_error_revealer">
|
||||
<property name="child">
|
||||
<object class="GtkLabel" id="room_address_error">
|
||||
<property name="valign">start</property>
|
||||
<property name="xalign">0.0</property>
|
||||
<property name="margin-top">6</property>
|
||||
<style>
|
||||
<class name="error"/>
|
||||
<class name="caption"/>
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</property>
|
||||
</template>
|
||||
</interface>
|
||||
|
|
@ -1,6 +1,12 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<menu id="primary_menu">
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_New Room</attribute>
|
||||
<attribute name="action">session.room-creation</attribute>
|
||||
</item>
|
||||
</section>
|
||||
<section>
|
||||
<item>
|
||||
<attribute name="label" translatable="yes">_Preferences</attribute>
|
||||
|
|
|
@ -27,6 +27,7 @@ data/resources/ui/context-menu-bin.ui
|
|||
data/resources/ui/event-source-dialog.ui
|
||||
data/resources/ui/login.ui
|
||||
data/resources/ui/in-app-notification.ui
|
||||
data/resources/ui/room-creation.ui
|
||||
data/resources/ui/session.ui
|
||||
data/resources/ui/shortcuts.ui
|
||||
data/resources/ui/sidebar-category-row.ui
|
||||
|
@ -54,6 +55,7 @@ src/components/pill.rs
|
|||
src/error.rs
|
||||
src/login.rs
|
||||
src/main.rs
|
||||
src/matrix_error.rs
|
||||
src/secret.rs
|
||||
src/session/account_settings/devices_page/device.rs
|
||||
src/session/account_settings/devices_page/device_item.rs
|
||||
|
@ -74,6 +76,7 @@ src/session/content/room_details/mod.rs
|
|||
src/session/content/room_history.rs
|
||||
src/session/content/state_row.rs
|
||||
src/session/mod.rs
|
||||
src/session/room_creation/mod.rs
|
||||
src/session/room_list.rs
|
||||
src/session/room/event.rs
|
||||
src/session/room/highlight_flags.rs
|
||||
|
|
|
@ -10,6 +10,7 @@ mod prelude;
|
|||
mod components;
|
||||
mod error;
|
||||
mod login;
|
||||
mod matrix_error;
|
||||
mod secret;
|
||||
mod session;
|
||||
mod utils;
|
||||
|
@ -18,6 +19,7 @@ mod window;
|
|||
use self::application::Application;
|
||||
use self::error::Error;
|
||||
use self::login::Login;
|
||||
use self::matrix_error::UserFacingMatrixError;
|
||||
use self::session::Session;
|
||||
use self::window::Window;
|
||||
|
||||
|
|
26
src/matrix_error.rs
Normal file
26
src/matrix_error.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
use matrix_sdk::{
|
||||
ruma::api::error::{FromHttpResponseError, ServerError},
|
||||
HttpError,
|
||||
};
|
||||
|
||||
use gettextrs::gettext;
|
||||
|
||||
pub trait UserFacingMatrixError {
|
||||
fn to_user_facing(self) -> String;
|
||||
}
|
||||
|
||||
impl UserFacingMatrixError for HttpError {
|
||||
fn to_user_facing(self) -> String {
|
||||
match self {
|
||||
HttpError::Reqwest(_) => {
|
||||
// TODO: Add more information based on the error
|
||||
gettext("Couldn't connect to the server.")
|
||||
}
|
||||
HttpError::ClientApi(FromHttpResponseError::Http(ServerError::Known(error))) => {
|
||||
// TODO: The server may not give us pretty enough error message. We should add our own error message.
|
||||
error.message
|
||||
}
|
||||
_ => gettext("An Unknown error occurred."),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ sources = files(
|
|||
'config.rs',
|
||||
'error.rs',
|
||||
'main.rs',
|
||||
'matrix_error.rs',
|
||||
'window.rs',
|
||||
'login.rs',
|
||||
'secret.rs',
|
||||
|
@ -69,6 +70,7 @@ sources = files(
|
|||
'session/room/room_type.rs',
|
||||
'session/room_list.rs',
|
||||
'session/room/timeline.rs',
|
||||
'session/room_creation/mod.rs',
|
||||
'session/sidebar/item_list.rs',
|
||||
'session/sidebar/category.rs',
|
||||
'session/sidebar/category_row.rs',
|
||||
|
|
|
@ -3,6 +3,7 @@ mod avatar;
|
|||
mod content;
|
||||
mod event_source_dialog;
|
||||
mod room;
|
||||
mod room_creation;
|
||||
mod room_list;
|
||||
mod sidebar;
|
||||
mod user;
|
||||
|
@ -11,6 +12,7 @@ use self::account_settings::AccountSettings;
|
|||
pub use self::avatar::Avatar;
|
||||
use self::content::Content;
|
||||
pub use self::room::Room;
|
||||
pub use self::room_creation::RoomCreation;
|
||||
use self::room_list::RoomList;
|
||||
use self::sidebar::Sidebar;
|
||||
pub use self::user::{User, UserExt};
|
||||
|
@ -82,6 +84,10 @@ mod imp {
|
|||
session.set_selected_room(None);
|
||||
});
|
||||
|
||||
klass.install_action("session.room-creation", None, move |session, _, _| {
|
||||
session.show_room_creation_dialog();
|
||||
});
|
||||
|
||||
klass.add_binding_action(
|
||||
gdk::keys::constants::Escape,
|
||||
gdk::ModifierType::empty(),
|
||||
|
@ -493,6 +499,11 @@ impl Session {
|
|||
window.show();
|
||||
}
|
||||
}
|
||||
|
||||
fn show_room_creation_dialog(&self) {
|
||||
let window = RoomCreation::new(self.parent_window().as_ref(), &self);
|
||||
window.show();
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Session {
|
||||
|
|
361
src/session/room_creation/mod.rs
Normal file
361
src/session/room_creation/mod.rs
Normal file
|
@ -0,0 +1,361 @@
|
|||
use adw::subclass::prelude::*;
|
||||
use gettextrs::gettext;
|
||||
use gtk::{gdk, glib, glib::clone, prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
use log::error;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
|
||||
use crate::components::SpinnerButton;
|
||||
use crate::session::user::UserExt;
|
||||
use crate::session::Session;
|
||||
use crate::utils::do_async;
|
||||
use matrix_sdk::{
|
||||
ruma::{
|
||||
api::{
|
||||
client::{
|
||||
error::ErrorKind as RumaClientErrorKind,
|
||||
r0::room::{create_room, Visibility},
|
||||
},
|
||||
error::{FromHttpResponseError, ServerError},
|
||||
},
|
||||
assign,
|
||||
identifiers::{Error, RoomName},
|
||||
},
|
||||
HttpError,
|
||||
};
|
||||
|
||||
use crate::UserFacingMatrixError;
|
||||
|
||||
// MAX length of room addresses
|
||||
const MAX_BYTES: usize = 255;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use glib::subclass::InitializingObject;
|
||||
use std::cell::RefCell;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[template(resource = "/org/gnome/FractalNext/room-creation.ui")]
|
||||
pub struct RoomCreation {
|
||||
pub session: RefCell<Option<Session>>,
|
||||
#[template_child]
|
||||
pub content: TemplateChild<gtk::ListBox>,
|
||||
#[template_child]
|
||||
pub create_button: TemplateChild<SpinnerButton>,
|
||||
#[template_child]
|
||||
pub cancel_button: TemplateChild<gtk::Button>,
|
||||
#[template_child]
|
||||
pub room_name: TemplateChild<gtk::Entry>,
|
||||
#[template_child]
|
||||
pub private_button: TemplateChild<gtk::ToggleButton>,
|
||||
#[template_child]
|
||||
pub room_address: TemplateChild<gtk::Entry>,
|
||||
#[template_child]
|
||||
pub room_name_error_revealer: TemplateChild<gtk::Revealer>,
|
||||
#[template_child]
|
||||
pub room_name_error: TemplateChild<gtk::Label>,
|
||||
#[template_child]
|
||||
pub room_address_error_revealer: TemplateChild<gtk::Revealer>,
|
||||
#[template_child]
|
||||
pub room_address_error: TemplateChild<gtk::Label>,
|
||||
#[template_child]
|
||||
pub server_name: TemplateChild<gtk::Label>,
|
||||
#[template_child]
|
||||
pub error_label: TemplateChild<gtk::Label>,
|
||||
#[template_child]
|
||||
pub error_label_revealer: TemplateChild<gtk::Revealer>,
|
||||
}
|
||||
|
||||
#[glib::object_subclass]
|
||||
impl ObjectSubclass for RoomCreation {
|
||||
const NAME: &'static str = "RoomCreation";
|
||||
type Type = super::RoomCreation;
|
||||
type ParentType = adw::Window;
|
||||
|
||||
fn class_init(klass: &mut Self::Class) {
|
||||
SpinnerButton::static_type();
|
||||
Self::bind_template(klass);
|
||||
|
||||
klass.add_binding(
|
||||
gdk::keys::constants::Escape,
|
||||
gdk::ModifierType::empty(),
|
||||
|obj, _| {
|
||||
obj.cancel();
|
||||
true
|
||||
},
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
fn instance_init(obj: &InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for RoomCreation {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
use once_cell::sync::Lazy;
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![glib::ParamSpec::new_object(
|
||||
"session",
|
||||
"Session",
|
||||
"The session",
|
||||
Session::static_type(),
|
||||
glib::ParamFlags::READWRITE,
|
||||
)]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(
|
||||
&self,
|
||||
obj: &Self::Type,
|
||||
_id: usize,
|
||||
value: &glib::Value,
|
||||
pspec: &glib::ParamSpec,
|
||||
) {
|
||||
match pspec.name() {
|
||||
"session" => obj.set_session(value.get().unwrap()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
match pspec.name() {
|
||||
"session" => obj.session().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn constructed(&self, obj: &Self::Type) {
|
||||
self.parent_constructed(obj);
|
||||
|
||||
self.cancel_button
|
||||
.connect_clicked(clone!(@weak obj => move |_| {
|
||||
obj.cancel();
|
||||
}));
|
||||
|
||||
self.create_button
|
||||
.connect_clicked(clone!(@weak obj => move |_| {
|
||||
obj.create_room();
|
||||
}));
|
||||
|
||||
self.room_name
|
||||
.connect_text_notify(clone!(@weak obj = > move |_| {
|
||||
obj.validate_input();
|
||||
}));
|
||||
|
||||
self.room_address
|
||||
.connect_text_notify(clone!(@weak obj = > move |_| {
|
||||
obj.validate_input();
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for RoomCreation {}
|
||||
impl WindowImpl for RoomCreation {}
|
||||
impl AdwWindowImpl for RoomCreation {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
/// Preference Window to display and update room details.
|
||||
pub struct RoomCreation(ObjectSubclass<imp::RoomCreation>)
|
||||
@extends gtk::Widget, gtk::Window, adw::Window, @implements gtk::Accessible;
|
||||
}
|
||||
|
||||
impl RoomCreation {
|
||||
pub fn new(parent_window: Option<&impl IsA<gtk::Window>>, session: &Session) -> Self {
|
||||
glib::Object::new(&[("transient-for", &parent_window), ("session", session)])
|
||||
.expect("Failed to create RoomCreation")
|
||||
}
|
||||
|
||||
pub fn session(&self) -> Option<Session> {
|
||||
let priv_ = imp::RoomCreation::from_instance(self);
|
||||
priv_.session.borrow().clone()
|
||||
}
|
||||
|
||||
fn set_session(&self, session: Option<Session>) {
|
||||
let priv_ = imp::RoomCreation::from_instance(self);
|
||||
|
||||
if self.session() == session {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(user) = session.as_ref().and_then(|session| session.user()) {
|
||||
priv_
|
||||
.server_name
|
||||
.set_label(&[":", user.user_id().server_name().as_str()].concat());
|
||||
}
|
||||
|
||||
priv_.session.replace(session);
|
||||
self.notify("session");
|
||||
}
|
||||
|
||||
fn create_room(&self) -> Option<()> {
|
||||
let priv_ = imp::RoomCreation::from_instance(self);
|
||||
|
||||
priv_.create_button.set_loading(true);
|
||||
priv_.content.set_sensitive(false);
|
||||
priv_.cancel_button.set_sensitive(false);
|
||||
priv_.error_label_revealer.set_reveal_child(false);
|
||||
|
||||
let client = self.session()?.client().clone();
|
||||
|
||||
let room_name = priv_.room_name.text().to_string();
|
||||
|
||||
let visibility = if priv_.private_button.is_active() {
|
||||
Visibility::Private
|
||||
} else {
|
||||
Visibility::Public
|
||||
};
|
||||
|
||||
let room_address = if !priv_.private_button.is_active() {
|
||||
Some(format!("#{}", priv_.room_address.text().as_str()))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
do_async(
|
||||
glib::PRIORITY_DEFAULT_IDLE,
|
||||
async move {
|
||||
// We don't allow invalid room names to be entered by the user
|
||||
let name = room_name.as_str().try_into().unwrap();
|
||||
|
||||
let request = assign!(create_room::Request::new(),
|
||||
{
|
||||
name: Some(name),
|
||||
visibility,
|
||||
room_alias_name: room_address.as_deref()
|
||||
});
|
||||
client.create_room(request).await
|
||||
},
|
||||
clone!(@weak self as obj => move |result| async move {
|
||||
match result {
|
||||
Ok(response) => {
|
||||
if let Some(session) = obj.session() {
|
||||
let room = session.room_list().get_wait(response.room_id).await;
|
||||
session.set_selected_room(room);
|
||||
}
|
||||
obj.close();
|
||||
},
|
||||
Err(error) => {
|
||||
error!("Couldn’t create a new room: {}", error);
|
||||
obj.handle_error(error);
|
||||
},
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Display the error that occured during creation
|
||||
fn handle_error(&self, error: HttpError) {
|
||||
let priv_ = imp::RoomCreation::from_instance(self);
|
||||
|
||||
priv_.create_button.set_loading(false);
|
||||
priv_.content.set_sensitive(true);
|
||||
priv_.cancel_button.set_sensitive(true);
|
||||
|
||||
// Treat the room address already taken error special
|
||||
if let HttpError::ClientApi(FromHttpResponseError::Http(ServerError::Known(
|
||||
ref client_error,
|
||||
))) = error
|
||||
{
|
||||
if client_error.kind == RumaClientErrorKind::RoomInUse {
|
||||
priv_.room_address.add_css_class("error");
|
||||
priv_
|
||||
.room_address_error
|
||||
.set_text(&gettext("The address is already taken."));
|
||||
priv_.room_address_error_revealer.set_reveal_child(true);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
priv_.error_label.set_label(&error.to_user_facing());
|
||||
|
||||
priv_.error_label_revealer.set_reveal_child(true);
|
||||
}
|
||||
|
||||
fn validate_input(&self) {
|
||||
let priv_ = imp::RoomCreation::from_instance(self);
|
||||
|
||||
// Validate room name
|
||||
let (is_name_valid, has_error) =
|
||||
match <&RoomName>::try_from(priv_.room_name.text().as_str()) {
|
||||
Ok(_) => (true, false),
|
||||
Err(Error::EmptyRoomName) => (false, false),
|
||||
Err(Error::MaximumLengthExceeded) => {
|
||||
priv_
|
||||
.room_name_error
|
||||
.set_text(&gettext("Too long. Use a shorter name."));
|
||||
(false, true)
|
||||
}
|
||||
Err(_) => unimplemented!(),
|
||||
};
|
||||
|
||||
if has_error {
|
||||
priv_.room_name.add_css_class("error");
|
||||
} else {
|
||||
priv_.room_name.remove_css_class("error");
|
||||
}
|
||||
|
||||
priv_.room_name_error_revealer.set_reveal_child(has_error);
|
||||
|
||||
// Validate room address
|
||||
|
||||
// Only public rooms have a address
|
||||
if priv_.private_button.is_active() {
|
||||
priv_.create_button.set_sensitive(is_name_valid);
|
||||
return;
|
||||
}
|
||||
|
||||
let room_address = priv_.room_address.text();
|
||||
|
||||
// We don't allow #, : in the room address
|
||||
let (is_address_valid, has_error) = if room_address.find(':').is_some() {
|
||||
priv_
|
||||
.room_address_error
|
||||
.set_text(&gettext("Can't contain `:`"));
|
||||
(false, true)
|
||||
} else if room_address.find('#').is_some() {
|
||||
priv_
|
||||
.room_address_error
|
||||
.set_text(&gettext("Can't contain `#`"));
|
||||
(false, true)
|
||||
} else if room_address.len() > MAX_BYTES {
|
||||
priv_
|
||||
.room_address_error
|
||||
.set_text(&gettext("Too long. Use a shorter address."));
|
||||
(false, true)
|
||||
} else if room_address.is_empty() {
|
||||
(false, false)
|
||||
} else {
|
||||
(true, false)
|
||||
};
|
||||
|
||||
// TODO: should we immediately check if the address is available, like element is doing?
|
||||
|
||||
if has_error {
|
||||
priv_.room_address.add_css_class("error");
|
||||
} else {
|
||||
priv_.room_address.remove_css_class("error");
|
||||
}
|
||||
|
||||
priv_
|
||||
.room_address_error_revealer
|
||||
.set_reveal_child(has_error);
|
||||
priv_
|
||||
.create_button
|
||||
.set_sensitive(is_name_valid && is_address_valid);
|
||||
}
|
||||
|
||||
fn cancel(&self) {
|
||||
let priv_ = imp::RoomCreation::from_instance(self);
|
||||
|
||||
if priv_.cancel_button.is_sensitive() {
|
||||
self.close();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue