[fractal/fractal-next] room-history: Show error page on loading errors
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] room-history: Show error page on loading errors
- Date: Tue, 15 Feb 2022 13:51:49 +0000 (UTC)
commit 762973ce19d9a6f4dfa497bab7dd29a797dd198b
Author: Julian Sparber <julian sparber net>
Date: Thu Feb 10 12:03:47 2022 +0100
room-history: Show error page on loading errors
This only shows the error page when the timeline is empty.
Adds also a enum for the timeline state.
data/resources/ui/content-room-history.ui | 21 +++++++
src/session/content/room_history/mod.rs | 46 +++++++++------
src/session/room/mod.rs | 2 +-
src/session/room/timeline.rs | 97 +++++++++++++++++--------------
4 files changed, 103 insertions(+), 63 deletions(-)
---
diff --git a/data/resources/ui/content-room-history.ui b/data/resources/ui/content-room-history.ui
index d257dd09c..abefde088 100644
--- a/data/resources/ui/content-room-history.ui
+++ b/data/resources/ui/content-room-history.ui
@@ -107,6 +107,26 @@
</style>
</object>
</child>
+ <child>
+ <object class="AdwStatusPage" id="error">
+ <property name="visible">True</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <property name="icon-name">dialog-error-symbolic</property>
+ <property name="title" translatable="yes">Unable to load room</property>
+ <property name="description" translatable="yes">Check your network connection.</property>
+ <property name="child">
+ <object class="GtkButton">
+ <property name="label" translatable="yes">Try Again</property>
+ <property name="action-name">room-history.try-again</property>
+ <property name="halign">center</property>
+ <style>
+ <class name="pill"/>
+ </style>
+ </object>
+ </property>
+ </object>
+ </child>
<child>
<object class="GtkOverlay" id="content">
<child type="overlay">
@@ -239,3 +259,4 @@
</child>
</template>
</interface>
+
diff --git a/src/session/content/room_history/mod.rs b/src/session/content/room_history/mod.rs
index 7fdb60749..aaefc2fc1 100644
--- a/src/session/content/room_history/mod.rs
+++ b/src/session/content/room_history/mod.rs
@@ -26,7 +26,7 @@ use crate::{
components::{CustomEntry, Pill, RoomTitle},
session::{
content::{MarkdownPopover, RoomDetails},
- room::{Item, Room, RoomType, Timeline},
+ room::{Item, Room, RoomType, Timeline, TimelineState},
user::UserExt,
},
};
@@ -46,7 +46,7 @@ mod imp {
pub room: RefCell<Option<Room>>,
pub category_handler: RefCell<Option<SignalHandlerId>>,
pub empty_timeline_handler: RefCell<Option<SignalHandlerId>>,
- pub loading_timeline_handler: RefCell<Option<SignalHandlerId>>,
+ pub state_timeline_handler: RefCell<Option<SignalHandlerId>>,
pub md_enabled: Cell<bool>,
pub is_auto_scrolling: Cell<bool>,
pub sticky: Cell<bool>,
@@ -73,6 +73,8 @@ mod imp {
#[template_child]
pub loading: TemplateChild<gtk::Spinner>,
#[template_child]
+ pub error: TemplateChild<adw::StatusPage>,
+ #[template_child]
pub stack: TemplateChild<gtk::Stack>,
}
@@ -101,6 +103,10 @@ mod imp {
widget.leave();
});
+ klass.install_action("room-history.try-again", None, move |widget, _, _| {
+ widget.try_again();
+ });
+
klass.install_action("room-history.details", None, move |widget, _, _| {
widget.open_room_details("general");
});
@@ -324,9 +330,9 @@ impl RoomHistory {
}
}
- if let Some(loading_timeline_handler) = priv_.loading_timeline_handler.take() {
- if let Some(room) = self.room() {
- room.timeline().disconnect(loading_timeline_handler);
+ if let Some(room) = self.room() {
+ if let Some(state_timeline_handler) = priv_.state_timeline_handler.take() {
+ room.timeline().disconnect(state_timeline_handler);
}
}
@@ -343,24 +349,20 @@ impl RoomHistory {
let handler_id = room.timeline().connect_notify_local(
Some("empty"),
clone!(@weak self as obj => move |_, _| {
- obj.set_empty_timeline();
+ obj.update_view();
}),
);
priv_.empty_timeline_handler.replace(Some(handler_id));
let handler_id = room.timeline().connect_notify_local(
- Some("loading"),
- clone!(@weak self as obj => move |timeline, _| {
- // We need to make sure that we loaded enough events to fill the `ScrolledWindow`
- if !timeline.loading() {
- let adj = obj.imp().listview.vadjustment().unwrap();
- obj.load_more_messages(&adj);
- }
+ Some("state"),
+ clone!(@weak self as obj => move |_, _| {
+ obj.update_view();
}),
);
- priv_.loading_timeline_handler.replace(Some(handler_id));
+ priv_.state_timeline_handler.replace(Some(handler_id));
room.load_members();
}
@@ -374,8 +376,8 @@ impl RoomHistory {
priv_.room.replace(room);
let adj = priv_.listview.vadjustment().unwrap();
self.load_more_messages(&adj);
+ self.update_view();
self.update_room_state();
- self.set_empty_timeline();
self.notify("room");
self.notify("empty");
}
@@ -519,12 +521,16 @@ impl RoomHistory {
}
}
- fn set_empty_timeline(&self) {
+ fn update_view(&self) {
let priv_ = self.imp();
if let Some(room) = &*priv_.room.borrow() {
if room.timeline().is_empty() {
- priv_.stack.set_visible_child(&*priv_.loading);
+ if room.timeline().state() == TimelineState::Error {
+ priv_.stack.set_visible_child(&*priv_.error);
+ } else {
+ priv_.stack.set_visible_child(&*priv_.loading);
+ }
} else {
priv_.stack.set_visible_child(&*priv_.content);
}
@@ -577,6 +583,12 @@ impl RoomHistory {
.scrolled_window
.emit_by_name::<bool>("scroll-child", &[>k::ScrollType::End, &false]);
}
+
+ fn try_again(&self) {
+ if let Some(room) = self.room() {
+ room.timeline().load_previous_events();
+ }
+ }
}
impl Default for RoomHistory {
diff --git a/src/session/room/mod.rs b/src/session/room/mod.rs
index 6e447364f..ff201db9f 100644
--- a/src/session/room/mod.rs
+++ b/src/session/room/mod.rs
@@ -54,7 +54,7 @@ pub use self::{
reaction_group::ReactionGroup,
reaction_list::ReactionList,
room_type::RoomType,
- timeline::Timeline,
+ timeline::{Timeline, TimelineState},
};
use crate::{
components::{LabelWithWidgets, Pill},
diff --git a/src/session/room/timeline.rs b/src/session/room/timeline.rs
index 197051b14..899e59e99 100644
--- a/src/session/room/timeline.rs
+++ b/src/session/room/timeline.rs
@@ -23,6 +23,23 @@ use crate::{
spawn, spawn_tokio,
};
+#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy, glib::Enum)]
+#[repr(u32)]
+#[enum_type(name = "TimelineState")]
+pub enum TimelineState {
+ Initial,
+ Loading,
+ Ready,
+ Error,
+ Complete,
+}
+
+impl Default for TimelineState {
+ fn default() -> Self {
+ TimelineState::Initial
+ }
+}
+
mod imp {
use std::{
cell::{Cell, RefCell},
@@ -48,9 +65,8 @@ mod imp {
pub pending_events: RefCell<HashMap<String, Box<EventId>>>,
/// A Hashset of `EventId`s that where just redacted.
pub redacted_events: RefCell<HashSet<Box<EventId>>>,
- pub loading: Cell<bool>,
- pub complete: Cell<bool>,
pub oldest_event: RefCell<Option<Box<EventId>>>,
+ pub state: Cell<TimelineState>,
/// The most recent verification request event
pub verification: RefCell<Option<IdentityVerification>>,
}
@@ -74,13 +90,6 @@ mod imp {
Room::static_type(),
glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
),
- glib::ParamSpecBoolean::new(
- "loading",
- "Loading",
- "Whether a response is loaded or not",
- false,
- glib::ParamFlags::READABLE,
- ),
glib::ParamSpecBoolean::new(
"empty",
"Empty",
@@ -88,11 +97,12 @@ mod imp {
false,
glib::ParamFlags::READABLE,
),
- glib::ParamSpecBoolean::new(
- "complete",
- "Complete",
- "Whether the full timeline is loaded",
- false,
+ glib::ParamSpecEnum::new(
+ "state",
+ "State",
+ "The state the timeline is in",
+ TimelineState::static_type(),
+ TimelineState::default() as i32,
glib::ParamFlags::READABLE,
),
glib::ParamSpecObject::new(
@@ -127,9 +137,8 @@ mod imp {
fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"room" => obj.room().to_value(),
- "loading" => obj.loading().to_value(),
"empty" => obj.is_empty().to_value(),
- "complete" => obj.is_complete().to_value(),
+ "state" => obj.state().to_value(),
"verification" => obj.verification().to_value(),
_ => unimplemented!(),
}
@@ -680,41 +689,27 @@ impl Timeline {
self.imp().room.get().unwrap().upgrade().unwrap()
}
- fn set_loading(&self, loading: bool) {
+ fn set_state(&self, state: TimelineState) {
let priv_ = self.imp();
- if loading == priv_.loading.get() {
+ if state == self.state() {
return;
}
- priv_.loading.set(loading);
+ priv_.state.set(state);
- self.notify("loading");
+ self.notify("state");
}
- fn set_complete(&self, complete: bool) {
- let priv_ = self.imp();
-
- if complete == priv_.complete.get() {
- return;
- }
-
- priv_.complete.set(complete);
- self.notify("complete");
- }
-
- // Whether the timeline is fully loaded
- pub fn is_complete(&self) -> bool {
- self.imp().complete.get()
- }
-
- pub fn loading(&self) -> bool {
- self.imp().loading.get()
+ // The state of the timeline
+ pub fn state(&self) -> TimelineState {
+ self.imp().state.get()
}
pub fn is_empty(&self) -> bool {
let priv_ = self.imp();
- priv_.list.borrow().is_empty() || (priv_.list.borrow().len() == 1 && self.loading())
+ priv_.list.borrow().is_empty()
+ || (priv_.list.borrow().len() == 1 && self.state() == TimelineState::Loading)
}
fn oldest_event(&self) -> Option<Box<EventId>> {
@@ -734,11 +729,14 @@ impl Timeline {
}
pub fn load_previous_events(&self) {
- if self.loading() || self.is_complete() {
+ if matches!(
+ self.state(),
+ TimelineState::Loading | TimelineState::Complete
+ ) {
return;
}
- self.set_loading(true);
+ self.set_state(TimelineState::Loading);
self.add_loading_spinner();
let matrix_room = self.room().matrix_room();
@@ -770,15 +768,24 @@ impl Timeline {
.into_iter()
.map(|event| Event::new(event, &obj.room())).collect()
};
- obj.set_complete(events.iter().any(|event| matches!(event.matrix_event(),
Some(AnySyncRoomEvent::State(AnySyncStateEvent::RoomCreate(_))))));
- obj.prepend(events)
+
+ if events.iter().any(|event| matches!(event.matrix_event(),
Some(AnySyncRoomEvent::State(AnySyncStateEvent::RoomCreate(_))))) {
+ obj.set_state(TimelineState::Complete);
+ } else {
+ obj.set_state(TimelineState::Ready);
+ }
+
+ obj.prepend(events);
},
Ok(None) => {
error!("The start event wasn't found in the timeline for room {}.",
obj.room().room_id());
+ obj.set_state(TimelineState::Error);
},
- Err(error) => error!("Couldn't load previous events for room {}: {}", error,
obj.room().room_id()),
+ Err(error) => {
+ error!("Couldn't load previous events for room {}: {}", error,
obj.room().room_id());
+ obj.set_state(TimelineState::Error);
+ }
}
- obj.set_loading(false);
})
);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]