[fractal/fractal-next] room-history: Add automatic scrolling and scroll down button
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] room-history: Add automatic scrolling and scroll down button
- Date: Mon, 6 Sep 2021 16:33:57 +0000 (UTC)
commit 19d71dd96a9094e08c865c2379bd7fd2e4b1c9ec
Author: Julian Sparber <julian sparber net>
Date: Mon Sep 6 17:07:34 2021 +0200
room-history: Add automatic scrolling and scroll down button
data/resources/ui/content-room-history.ui | 70 ++++++++++++++++++++---------
src/session/content/room_history.rs | 73 ++++++++++++++++++++++++++++++-
2 files changed, 120 insertions(+), 23 deletions(-)
---
diff --git a/data/resources/ui/content-room-history.ui b/data/resources/ui/content-room-history.ui
index 397d2bd0..947064fc 100644
--- a/data/resources/ui/content-room-history.ui
+++ b/data/resources/ui/content-room-history.ui
@@ -90,33 +90,60 @@
</object>
</child>
<child>
- <object class="GtkScrolledWindow" id="scrolled_window">
- <property name="vexpand">True</property>
- <property name="hscrollbar-policy">never</property>
- <style>
- <class name="room-history"/>
- </style>
- <property name="child">
- <object class="AdwClampScrollable">
- <property name="vexpand">True</property>
- <property name="hexpand">True</property>
- <property name="child">
- <object class="GtkListView" id="listview">
+ <object class="GtkOverlay" id="content">
+ <child type="overlay">
+ <object class="GtkRevealer" id="scroll_btn_revealer">
+ <property name="transition_type">crossfade</property>
+ <property name="reveal_child" bind-source="ContentRoomHistory" bind-property="sticky"
bind-flags="sync-create | invert-boolean"/>
+ <property name="valign">end</property>
+ <property name="halign">end</property>
+ <property name="margin-end">24</property>
+ <property name="margin-bottom">24</property>
+ <child>
+ <object class="GtkButton" id="scroll_btn">
+ <property name="icon-name">go-bottom-symbolic</property>
+ <property name="action-name">room-history.scroll-down</property>
+ <accessibility>
+ <property name="label" translatable="yes">Scroll to bottom</property>
+ </accessibility>
<style>
- <class name="navigation-sidebar"/>
+ <class name="osd"/>
+ <class name="circular"/>
</style>
- <property name="factory">
- <object class="GtkBuilderListItemFactory">
- <property name="resource">/org/gnome/FractalNext/content-item.ui</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolled_window">
+ <property name="vexpand">True</property>
+ <property name="hscrollbar-policy">never</property>
+ <style>
+ <class name="room-history"/>
+ </style>
+ <property name="child">
+ <object class="AdwClampScrollable">
+ <property name="vexpand">True</property>
+ <property name="hexpand">True</property>
+ <property name="child">
+ <object class="GtkListView" id="listview">
+ <style>
+ <class name="navigation-sidebar"/>
+ </style>
+ <property name="factory">
+ <object class="GtkBuilderListItemFactory">
+ <property name="resource">/org/gnome/FractalNext/content-item.ui</property>
+ </object>
+ </property>
+ <accessibility>
+ <property name="label" translatable="yes">Room History</property>
+ </accessibility>
</object>
</property>
- <accessibility>
- <property name="label" translatable="yes">Room History</property>
- </accessibility>
</object>
</property>
</object>
- </property>
+ </child>
</object>
</child>
</object>
@@ -155,7 +182,7 @@
<child>
<object class="CustomEntry">
<style>
- <class name="message-entry" />
+ <class name="message-entry"/>
</style>
<child>
<object class="GtkScrolledWindow">
@@ -193,3 +220,4 @@
</child>
</template>
</interface>
+
diff --git a/src/session/content/room_history.rs b/src/session/content/room_history.rs
index 3830de98..af972145 100644
--- a/src/session/content/room_history.rs
+++ b/src/session/content/room_history.rs
@@ -23,6 +23,8 @@ mod imp {
pub category_handler: RefCell<Option<SignalHandlerId>>,
pub empty_timeline_handler: RefCell<Option<SignalHandlerId>>,
pub md_enabled: Cell<bool>,
+ pub is_auto_scrolling: Cell<bool>,
+ pub sticky: Cell<bool>,
#[template_child]
pub headerbar: TemplateChild<adw::HeaderBar>,
#[template_child]
@@ -32,8 +34,14 @@ mod imp {
#[template_child]
pub listview: TemplateChild<gtk::ListView>,
#[template_child]
+ pub content: TemplateChild<gtk::Widget>,
+ #[template_child]
pub scrolled_window: TemplateChild<gtk::ScrolledWindow>,
#[template_child]
+ pub scroll_btn: TemplateChild<gtk::Button>,
+ #[template_child]
+ pub scroll_btn_revealer: TemplateChild<gtk::Revealer>,
+ #[template_child]
pub message_entry: TemplateChild<sourceview::View>,
#[template_child]
pub markdown_button: TemplateChild<gtk::MenuButton>,
@@ -65,9 +73,14 @@ mod imp {
klass.install_action("room-history.leave", None, move |widget, _, _| {
widget.leave();
});
+
klass.install_action("room-history.details", None, move |widget, _, _| {
widget.open_room_details();
});
+
+ klass.install_action("room-history.scroll-down", None, move |widget, _, _| {
+ widget.scroll_down();
+ });
}
fn instance_init(obj: &InitializingObject<Self>) {
@@ -108,6 +121,13 @@ mod imp {
false,
glib::ParamFlags::READWRITE,
),
+ glib::ParamSpec::new_boolean(
+ "sticky",
+ "Sticky",
+ "Whether the room history should stick to the newest message in the timeline",
+ true,
+ glib::ParamFlags::READWRITE,
+ ),
]
});
@@ -139,6 +159,7 @@ mod imp {
"format-justify-left-symbolic"
});
}
+ "sticky" => obj.set_sticky(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -149,15 +170,32 @@ mod imp {
"room" => obj.room().to_value(),
"empty" => obj.room().is_none().to_value(),
"markdown-enabled" => self.md_enabled.get().to_value(),
+ "sticky" => obj.sticky().to_value(),
_ => unimplemented!(),
}
}
fn constructed(&self, obj: &Self::Type) {
+ obj.set_sticky(true);
let adj = self.listview.vadjustment().unwrap();
adj.connect_value_changed(clone!(@weak obj => move |adj| {
- obj.load_more_messages(adj);
+ let priv_ = imp::RoomHistory::from_instance(&obj);
+
+ if priv_.is_auto_scrolling.get() {
+ if adj.value() + adj.page_size() == adj.upper() {
+ priv_.is_auto_scrolling.set(false);
+ obj.set_sticky(true);
+ }
+ } else {
+ obj.set_sticky(adj.value() + adj.page_size() == adj.upper());
+ obj.load_more_messages(adj);
+ }
+ }));
+ adj.connect_upper_notify(clone!(@weak obj => move |_| {
+ if obj.sticky() {
+ obj.scroll_down();
+ }
}));
let key_events = gtk::EventControllerKey::new();
@@ -326,7 +364,7 @@ impl RoomHistory {
if room.timeline().empty() {
priv_.stack.set_visible_child(&*priv_.loading);
} else {
- priv_.stack.set_visible_child(&*priv_.scrolled_window);
+ priv_.stack.set_visible_child(&*priv_.content);
}
}
}
@@ -345,6 +383,37 @@ impl RoomHistory {
fn parent_window(&self) -> Option<gtk::Window> {
self.root()?.downcast().ok()
}
+
+ pub fn sticky(&self) -> bool {
+ let priv_ = imp::RoomHistory::from_instance(self);
+
+ priv_.sticky.get()
+ }
+
+ pub fn set_sticky(&self, sticky: bool) {
+ let priv_ = imp::RoomHistory::from_instance(self);
+
+ if self.sticky() == sticky {
+ return;
+ }
+
+ priv_.scroll_btn_revealer.set_reveal_child(!sticky);
+
+ priv_.sticky.set(sticky);
+ self.notify("sticky");
+ }
+
+ /// Scroll to the newest message in the timeline
+ pub fn scroll_down(&self) {
+ let priv_ = imp::RoomHistory::from_instance(self);
+
+ priv_.is_auto_scrolling.set(true);
+
+ priv_
+ .scrolled_window
+ .emit_by_name("scroll-child", &[>k::ScrollType::End, &false])
+ .unwrap();
+ }
}
impl Default for RoomHistory {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]