[fractal/fractal-next] Add loading spinner for session
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] Add loading spinner for session
- Date: Tue, 11 May 2021 08:17:44 +0000 (UTC)
commit 7101c3f852923266edaf45d5c4901c20958eeb01
Author: Julian Sparber <julian sparber net>
Date: Mon May 10 19:38:37 2021 +0200
Add loading spinner for session
We won't show a loading spinner as in-app-notifcation, but we show a big
loading spinner when a new session is created (via a successful login)
and when we restore a previously created session.
Fixes: https://gitlab.gnome.org/GNOME/fractal/-/issues/775
Fixes: https://gitlab.gnome.org/GNOME/fractal/-/issues/776
data/resources/style.css | 11 +++++++++
data/resources/ui/session.ui | 55 ++++++++++++++++++++++++++++++++++++--------
src/login.rs | 31 +++++++------------------
src/session/mod.rs | 39 +++++++++++++++++++++----------
src/window.rs | 23 ++++++++++++------
5 files changed, 107 insertions(+), 52 deletions(-)
---
diff --git a/data/resources/style.css b/data/resources/style.css
index 1a795019..584ff678 100644
--- a/data/resources/style.css
+++ b/data/resources/style.css
@@ -8,6 +8,17 @@
min-width: 250px;
}
+/* Session */
+.session-loading-spinner {
+ min-width: 32px;
+ min-height: 32px;
+}
+
+headerbar.flat {
+ background: none;
+ border: none;
+}
+
/* Sidebar */
.sidebar row {
padding-left: 10px;
diff --git a/data/resources/ui/session.ui b/data/resources/ui/session.ui
index 91826c35..6cd6e86d 100644
--- a/data/resources/ui/session.ui
+++ b/data/resources/ui/session.ui
@@ -1,22 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="Session" parent="AdwBin">
- <child>
- <object class="AdwLeaflet" id="leaflet">
+ <property name="child">
+ <object class="GtkStack" id="stack">
+ <property name="visible-child">loading</property>
+ <property name="transition-type">crossfade</property>
<child>
- <object class="Sidebar" id="sidebar">
- <property name="compact" bind-source="leaflet" bind-property="folded" bind-flags="sync-create" />
- <property name="categories" bind-source="Session" bind-property="categories"
bind-flags="sync-create" />
- <property name="selected-room" bind-source="Session" bind-property="selected-room"
bind-flags="sync-create | bidirectional" />
+ <object class="GtkWindowHandle" id="loading">
+ <property name="child">
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkHeaderBar">
+ <property name="show-title-buttons">True</property>
+ <style>
+ <class name="flat"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkSpinner">
+ <property name="spinning">True</property>
+ <property name="valign">center</property>
+ <property name="halign">center</property>
+ <property name="vexpand">True</property>
+ <style>
+ <class name="session-loading-spinner"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </property>
</object>
</child>
<child>
- <object class="Content" id="content">
- <property name="compact" bind-source="leaflet" bind-property="folded" bind-flags="sync-create" />
- <property name="room" bind-source="Session" bind-property="selected-room"
bind-flags="sync-create | bidirectional" />
+ <object class="AdwLeaflet" id="content">
+ <child>
+ <object class="Sidebar">
+ <property name="compact" bind-source="content" bind-property="folded"
bind-flags="sync-create"/>
+ <property name="categories" bind-source="Session" bind-property="categories"
bind-flags="sync-create"/>
+ <property name="selected-room" bind-source="Session" bind-property="selected-room"
bind-flags="sync-create | bidirectional"/>
+ </object>
+ </child>
+ <child>
+ <object class="Content">
+ <property name="compact" bind-source="content" bind-property="folded"
bind-flags="sync-create"/>
+ <property name="room" bind-source="Session" bind-property="selected-room"
bind-flags="sync-create | bidirectional"/>
+ </object>
+ </child>
</object>
</child>
</object>
- </child>
+ </property>
</template>
</interface>
+
diff --git a/src/login.rs b/src/login.rs
index dcc45626..d8b4e727 100644
--- a/src/login.rs
+++ b/src/login.rs
@@ -1,4 +1,3 @@
-use crate::secret;
use crate::Session;
use adw;
@@ -122,28 +121,8 @@ impl Login {
self.freeze();
let session = Session::new();
- self.setup_session(&session);
- session.login_with_password(
- url::Url::parse(homeserver.as_str()).unwrap(),
- username,
- password,
- );
- }
-
- pub fn restore_sessions(&self) -> Result<(), secret_service::Error> {
- let sessions = secret::restore_sessions()?;
-
- for stored_session in sessions {
- let session = Session::new();
- self.setup_session(&session);
- session.login_with_previous_session(stored_session);
- }
- Ok(())
- }
-
- fn setup_session(&self, session: &Session) {
- session.connect_ready(clone!(@weak self as obj, @strong session => move |_| {
+ session.connect_prepared(clone!(@weak self as obj, @strong session => move |_| {
if let Some(error) = session.get_error() {
let error_message = &imp::Login::from_instance(&obj).error_message;
// TODO: show more specific error
@@ -153,11 +132,17 @@ impl Login {
obj.unfreeze();
} else {
- debug!("A new session is ready");
+ debug!("A new session was prepared");
obj.emit_by_name("new-session", &[&session]).unwrap();
obj.clean();
}
}));
+
+ session.login_with_password(
+ url::Url::parse(homeserver.as_str()).unwrap(),
+ username,
+ password,
+ );
}
fn clean(&self) {
diff --git a/src/session/mod.rs b/src/session/mod.rs
index c76282c8..34afd376 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -48,11 +48,9 @@ mod imp {
#[template(resource = "/org/gnome/FractalNext/session.ui")]
pub struct Session {
#[template_child]
- pub leaflet: TemplateChild<adw::Leaflet>,
+ pub stack: TemplateChild<gtk::Stack>,
#[template_child]
- pub sidebar: TemplateChild<Sidebar>,
- #[template_child]
- pub content: TemplateChild<Content>,
+ pub content: TemplateChild<adw::Leaflet>,
/// Contains the error if something went wrong
pub error: RefCell<Option<matrix_sdk::Error>>,
pub client: OnceCell<Client>,
@@ -60,6 +58,7 @@ mod imp {
pub categories: Categories,
pub user: OnceCell<User>,
pub selected_room: RefCell<Option<Room>>,
+ pub is_ready: OnceCell<bool>,
}
#[glib::object_subclass]
@@ -73,6 +72,8 @@ mod imp {
}
fn instance_init(obj: &InitializingObject<Self>) {
+ Sidebar::static_type();
+ Content::static_type();
obj.init_template();
}
}
@@ -127,7 +128,7 @@ mod imp {
fn signals() -> &'static [Signal] {
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
- vec![Signal::builder("ready", &[], <()>::static_type().into()).build()]
+ vec![Signal::builder("prepared", &[], <()>::static_type().into()).build()]
});
SIGNALS.as_ref()
}
@@ -162,11 +163,10 @@ impl Session {
return;
}
- let leaflet = priv_.leaflet.get();
if selected_room.is_some() {
- leaflet.navigate(adw::NavigationDirection::Forward);
+ priv_.content.navigate(adw::NavigationDirection::Forward);
} else {
- leaflet.navigate(adw::NavigationDirection::Back);
+ priv_.content.navigate(adw::NavigationDirection::Back);
}
priv_.selected_room.replace(selected_room);
@@ -271,7 +271,7 @@ impl Session {
priv_.error.replace(Some(error));
}
}
- self.emit_by_name("ready", &[]).unwrap();
+ self.emit_by_name("prepared", &[]).unwrap();
}
fn sync(&self) {
@@ -308,6 +308,17 @@ impl Session {
});
}
+ fn mark_ready(&self) {
+ let priv_ = &imp::Session::from_instance(self);
+ priv_.stack.set_visible_child(&*priv_.content);
+ priv_.is_ready.set(true).unwrap();
+ }
+
+ fn is_ready(&self) -> bool {
+ let priv_ = &imp::Session::from_instance(self);
+ priv_.is_ready.get().copied().unwrap_or_default()
+ }
+
fn set_user(&self, user: User) {
let priv_ = &imp::Session::from_instance(self);
priv_.user.set(user).unwrap();
@@ -325,7 +336,11 @@ impl Session {
receiver.attach(
None,
clone!(@weak self as obj => @default-return glib::Continue(false), move |response| {
+ if !obj.is_ready() {
+ obj.mark_ready();
+ }
obj.handle_sync_response(response);
+
glib::Continue(true)
}),
);
@@ -342,14 +357,14 @@ impl Session {
/// Returns and consumes the `error` that was generated when the session failed to login,
/// on a successful login this will be `None`.
- /// Unfortunatly it's not possible to connect the Error direclty to the `ready` signals.
+ /// Unfortunatly it's not possible to connect the Error direclty to the `prepared` signals.
pub fn get_error(&self) -> Option<matrix_sdk::Error> {
let priv_ = &imp::Session::from_instance(self);
priv_.error.take()
}
- pub fn connect_ready<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
- self.connect_local("ready", true, move |values| {
+ pub fn connect_prepared<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
+ self.connect_local("prepared", true, move |values| {
let obj = values[0].get::<Self>().unwrap();
f(&obj);
diff --git a/src/window.rs b/src/window.rs
index 3507d09f..1cd0159f 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -1,4 +1,5 @@
use crate::config::{APP_ID, PROFILE};
+use crate::secret;
use crate::Application;
use crate::Login;
use crate::Session;
@@ -59,14 +60,9 @@ mod imp {
obj.add_css_class("devel");
}
- // load latest window state
obj.load_window_size();
+ obj.restore_sessions();
- // TODO: tell user that a stored session couldn't be restored
- let result = self.login.restore_sessions();
- if let Err(error) = result {
- warn!("Failed to restore a session: {:?}", error);
- }
self.login.connect_new_session(
clone!(@weak obj => move |_login, session| obj.add_session(session)),
);
@@ -99,12 +95,25 @@ impl Window {
.expect("Failed to create Window")
}
- pub fn add_session(&self, session: &Session) {
+ fn add_session(&self, session: &Session) {
let priv_ = &imp::Window::from_instance(self);
priv_.main_stack.add_child(session);
priv_.main_stack.set_visible_child(session);
}
+ fn restore_sessions(&self) {
+ match secret::restore_sessions() {
+ Ok(sessions) => {
+ for stored_session in sessions {
+ let session = Session::new();
+ session.login_with_previous_session(stored_session);
+ self.add_session(&session);
+ }
+ }
+ Err(error) => warn!("Failed to restore previous sessions: {:?}", error),
+ }
+ }
+
pub fn save_window_size(&self) -> Result<(), glib::BoolError> {
let settings = &imp::Window::from_instance(self).settings;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]