[fractal] session: Replace listview with listbox in AccountSwitcher
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal] session: Replace listview with listbox in AccountSwitcher
- Date: Wed, 20 Apr 2022 08:03:19 +0000 (UTC)
commit e069053cdae78006373db4d60bc906d7c1c3d48b
Author: Julian Sparber <julian sparber net>
Date: Tue Apr 19 15:07:55 2022 +0200
session: Replace listview with listbox in AccountSwitcher
This reworks the entiere account switcher.
Fixes: https://gitlab.gnome.org/GNOME/fractal/-/issues/931
Fixes: https://gitlab.gnome.org/GNOME/fractal/-/issues/898
data/resources/resources.gresource.xml | 1 -
data/resources/style.css | 16 +-
data/resources/ui/add-account-row.ui | 23 ---
data/resources/ui/avatar-with-selection.ui | 6 +-
data/resources/ui/sidebar-account-switcher.ui | 45 ++++-
data/resources/ui/sidebar.ui | 5 +-
data/resources/ui/user-entry-row.ui | 23 +--
.../account_switcher/avatar_with_selection.rs | 15 +-
src/account_switcher/mod.rs | 215 +++++++++++++++++++++
src/account_switcher/user_entry.rs | 145 ++++++++++++++
src/main.rs | 1 +
src/session/mod.rs | 8 +-
.../sidebar/account_switcher/add_account.rs | 48 -----
src/session/sidebar/account_switcher/item.rs | 163 ----------------
src/session/sidebar/account_switcher/mod.rs | 141 --------------
src/session/sidebar/account_switcher/user_entry.rs | 140 --------------
src/session/sidebar/mod.rs | 41 ++--
src/window.rs | 9 +-
18 files changed, 477 insertions(+), 568 deletions(-)
---
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index a364c6e5a..308ca019d 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -27,7 +27,6 @@
<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="account-settings-user-page.ui">ui/account-settings-user-page.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="account-settings.ui">ui/account-settings.ui</file>
- <file compressed="true" preprocess="xml-stripblanks"
alias="add-account-row.ui">ui/add-account-row.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="attachment-dialog.ui">ui/attachment-dialog.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="avatar-with-selection.ui">ui/avatar-with-selection.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="components-action-button.ui">ui/components-action-button.ui</file>
diff --git a/data/resources/style.css b/data/resources/style.css
index ee2cb0867..436166817 100644
--- a/data/resources/style.css
+++ b/data/resources/style.css
@@ -207,12 +207,18 @@ login {
/* Account switcher */
-#account-switcher row {
+.account-switcher .account-switcher-row {
border-radius: 10px;
- margin-top: 2px;
- margin-bottom: 2px;
- padding-top: 7px;
- padding-bottom: 7px;
+ margin: 3px 0px;
+ padding: 6px 12px;
+}
+
+.account-switcher .account-switcher-row:first-child {
+ margin-top: 0px;
+}
+
+.account-switcher .account-switcher-row:last-child {
+ margin-bottom: 0px;
}
#new-login-icon {
diff --git a/data/resources/ui/avatar-with-selection.ui b/data/resources/ui/avatar-with-selection.ui
index 5ae059530..b94d668cc 100644
--- a/data/resources/ui/avatar-with-selection.ui
+++ b/data/resources/ui/avatar-with-selection.ui
@@ -8,13 +8,13 @@
</child>
<child type="overlay">
<object class="GtkImage" id="checkmark">
- <style>
- <class name="blue-checkmark" />
- </style>
<property name="visible">false</property>
<property name="halign">end</property>
<property name="valign">end</property>
<property name="icon-name">emblem-ok-symbolic</property>
+ <style>
+ <class name="blue-checkmark" />
+ </style>
</object>
</child>
</object>
diff --git a/data/resources/ui/sidebar-account-switcher.ui b/data/resources/ui/sidebar-account-switcher.ui
index 74dace8d0..14f9f4044 100644
--- a/data/resources/ui/sidebar-account-switcher.ui
+++ b/data/resources/ui/sidebar-account-switcher.ui
@@ -1,11 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<template class="AccountSwitcher" parent="GtkPopover">
- <property name="name">account-switcher</property>
<child>
- <object class="GtkListView" id="entries">
- <property name="single-click-activate">true</property>
+ <object class="GtkListBox" id="entries">
+ <property name="activate_on_single_click">true</property>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="selectable">false</property>
+ <property name="activatable">false</property>
+ <property name="child">
+ <object class="GtkSeparator"/>
+ </property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkListBoxRow">
+ <property name="selectable">false</property>
+ <property name="action-name">app.new-session</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="spacing">10</property>
+ <child>
+ <object class="GtkImage">
+ <property name="name">new-login-icon</property>
+ <property name="icon-name">list-add-symbolic</property>
+ <property name="pixel-size">16</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="use-underline">true</property>
+ <property name="label">_Add Account</property>
+ </object>
+ </child>
+ </object>
+ </property>
+ <style>
+ <class name="account-switcher-row"/>
+ </style>
+ </object>
+ </child>
</object>
</child>
+ <style>
+ <class name="account-switcher"/>
+ </style>
</template>
</interface>
+
diff --git a/data/resources/ui/sidebar.ui b/data/resources/ui/sidebar.ui
index 2fe1a64ef..9a3d73fa3 100644
--- a/data/resources/ui/sidebar.ui
+++ b/data/resources/ui/sidebar.ui
@@ -86,10 +86,7 @@
</property>
<property name="show-end-title-buttons" bind-source="Sidebar" bind-property="compact"
bind-flags="sync-create"/>
<child type="start">
- <object class="GtkMenuButton" id="accounts_button">
- <property name="popover">
- <object class="AccountSwitcher" id="account_switcher"/>
- </property>
+ <object class="GtkMenuButton" id="account_switcher_button">
<accessibility>
<property name="label" translatable="yes">Switch Accounts</property>
</accessibility>
diff --git a/data/resources/ui/user-entry-row.ui b/data/resources/ui/user-entry-row.ui
index a7a7b619a..b44237402 100644
--- a/data/resources/ui/user-entry-row.ui
+++ b/data/resources/ui/user-entry-row.ui
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <template class="UserEntryRow" parent="AdwBin">
+ <template class="UserEntryRow" parent="GtkListBoxRow">
+ <property name="selectable">false</property>
+ <style>
+ <class name="account-switcher-row"/>
+ </style>
<child>
<object class="GtkBox">
<property name="spacing">10</property>
@@ -10,9 +14,7 @@
<binding name="item">
<lookup name="avatar" type="User">
<lookup name="user" type="Session">
- <lookup name="child" type="GtkStackPage">
- <lookup name="session-page">UserEntryRow</lookup>
- </lookup>
+ <lookup name="session">UserEntryRow</lookup>
</lookup>
</lookup>
</binding>
@@ -25,12 +27,11 @@
<child>
<object class="GtkLabel" id="display_name">
<property name="xalign">0.0</property>
+ <property name="hexpand">True</property>
<binding name="label">
<lookup name="display-name" type="User">
<lookup name="user" type="Session">
- <lookup name="child" type="GtkStackPage">
- <lookup name="session-page">UserEntryRow</lookup>
- </lookup>
+ <lookup name="session">UserEntryRow</lookup>
</lookup>
</lookup>
</binding>
@@ -39,12 +40,11 @@
<child>
<object class="GtkLabel" id="user_id">
<property name="xalign">0.0</property>
+ <property name="hexpand">True</property>
<binding name="label">
<lookup name="user-id" type="User">
<lookup name="user" type="Session">
- <lookup name="child" type="GtkStackPage">
- <lookup name="session-page">UserEntryRow</lookup>
- </lookup>
+ <lookup name="session">UserEntryRow</lookup>
</lookup>
</lookup>
</binding>
@@ -59,9 +59,9 @@
<child>
<object class="GtkButton">
<property name="icon-name">applications-system-symbolic</property>
- <property name="action-name">user-entry-row.open-account-settings</property>
<property name="valign">center</property>
<property name="halign">center</property>
+ <signal name="clicked" handler="show_account_settings" swapped="true"/>
<style>
<class name="circular"/>
</style>
@@ -71,3 +71,4 @@
</child>
</template>
</interface>
+
diff --git a/src/session/sidebar/account_switcher/avatar_with_selection.rs
b/src/account_switcher/avatar_with_selection.rs
similarity index 89%
rename from src/session/sidebar/account_switcher/avatar_with_selection.rs
rename to src/account_switcher/avatar_with_selection.rs
index 45f55fcea..ed133cb6f 100644
--- a/src/session/sidebar/account_switcher/avatar_with_selection.rs
+++ b/src/account_switcher/avatar_with_selection.rs
@@ -59,7 +59,7 @@ mod imp {
"Selected",
"Style helper for the inner Avatar",
false,
- glib::ParamFlags::WRITABLE,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
]
});
@@ -82,10 +82,11 @@ mod imp {
}
}
- fn property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
"item" => self.child_avatar.item().to_value(),
"size" => self.child_avatar.size().to_value(),
+ "selected" => obj.is_selected().to_value(),
_ => unimplemented!(),
}
}
@@ -109,6 +110,10 @@ impl AvatarWithSelection {
pub fn set_selected(&self, selected: bool) {
let priv_ = self.imp();
+ if self.is_selected() == selected {
+ return;
+ }
+
priv_.checkmark.set_visible(selected);
if selected {
@@ -116,6 +121,12 @@ impl AvatarWithSelection {
} else {
priv_.child_avatar.remove_css_class("selected-avatar");
}
+
+ self.notify("selected");
+ }
+
+ pub fn is_selected(&self) -> bool {
+ self.imp().checkmark.get_visible()
}
pub fn avatar(&self) -> &Avatar {
diff --git a/src/account_switcher/mod.rs b/src/account_switcher/mod.rs
new file mode 100644
index 000000000..477ed72b4
--- /dev/null
+++ b/src/account_switcher/mod.rs
@@ -0,0 +1,215 @@
+use gtk::{
+ glib::{self, clone},
+ prelude::*,
+ subclass::prelude::*,
+ CompositeTemplate, SelectionModel,
+};
+
+use crate::session::Session;
+
+mod avatar_with_selection;
+mod user_entry;
+
+use user_entry::UserEntryRow;
+
+mod imp {
+ use std::cell::RefCell;
+
+ use glib::subclass::InitializingObject;
+ use once_cell::sync::Lazy;
+
+ use super::*;
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/Fractal/sidebar-account-switcher.ui")]
+ pub struct AccountSwitcher {
+ #[template_child]
+ pub entries: TemplateChild<gtk::ListBox>,
+ pub pages: RefCell<Option<gtk::SelectionModel>>,
+ pub pages_handler: RefCell<Option<glib::SignalHandlerId>>,
+ pub selection_handler: RefCell<Option<glib::SignalHandlerId>>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for AccountSwitcher {
+ const NAME: &'static str = "AccountSwitcher";
+ type Type = super::AccountSwitcher;
+ type ParentType = gtk::Popover;
+
+ fn class_init(klass: &mut Self::Class) {
+ Self::bind_template(klass);
+
+ klass.install_action("account-switcher.close", None, move |item, _, _| {
+ item.popdown();
+ });
+ }
+
+ fn instance_init(obj: &InitializingObject<Self>) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for AccountSwitcher {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpecObject::new(
+ "pages",
+ "Pages",
+ "A model containing the stack pages for each logged in account",
+ gtk::SelectionModel::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.name() {
+ "pages" => obj.set_pages(value.get().unwrap()),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "pages" => obj.pages().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn constructed(&self, obj: &Self::Type) {
+ self.parent_constructed(obj);
+
+ self.entries.connect_row_activated(move |_, row| {
+ row.activate_action("account-switcher.close", None).unwrap();
+
+ if let Some(session) = row
+ .downcast_ref::<UserEntryRow>()
+ .and_then(|row| row.session())
+ {
+ session
+ .parent()
+ .unwrap()
+ .downcast::<gtk::Stack>()
+ .unwrap()
+ .set_visible_child(&session);
+ }
+ });
+ }
+ }
+
+ impl WidgetImpl for AccountSwitcher {}
+ impl PopoverImpl for AccountSwitcher {}
+}
+
+glib::wrapper! {
+ pub struct AccountSwitcher(ObjectSubclass<imp::AccountSwitcher>)
+ @extends gtk::Widget, gtk::Popover, @implements gtk::Accessible;
+}
+
+impl AccountSwitcher {
+ pub fn new() -> Self {
+ glib::Object::new(&[]).expect("Failed to create UserEntryRow")
+ }
+
+ pub fn set_pages(&self, pages: Option<gtk::SelectionModel>) {
+ let priv_ = self.imp();
+ let prev_pages = self.pages();
+
+ if pages == prev_pages {
+ return;
+ }
+ if let Some(prev_pages) = prev_pages {
+ if let Some(handler) = priv_.pages_handler.take() {
+ prev_pages.disconnect(handler);
+ }
+
+ if let Some(handler) = priv_.selection_handler.take() {
+ prev_pages.disconnect(handler);
+ }
+ }
+
+ if let Some(ref pages) = pages {
+ let handler = pages.connect_items_changed(
+ clone!(@weak self as obj => move |model, position, removed, added| {
+ obj.update_rows(model, position, removed, added);
+ }),
+ );
+
+ priv_.pages_handler.replace(Some(handler));
+
+ let handler = pages.connect_selection_changed(
+ clone!(@weak self as obj => move |_, position, n_items| {
+ obj.update_selection(position, n_items);
+ }),
+ );
+
+ priv_.selection_handler.replace(Some(handler));
+
+ self.update_rows(pages, 0, 0, pages.n_items());
+ }
+
+ self.imp().pages.replace(pages);
+ self.notify("pages");
+ }
+
+ pub fn pages(&self) -> Option<gtk::SelectionModel> {
+ self.imp().pages.borrow().clone()
+ }
+
+ fn update_rows(&self, model: &SelectionModel, position: u32, removed: u32, added: u32) {
+ let listbox = self.imp().entries.get();
+ for _ in 0..removed {
+ if let Some(row) = listbox.row_at_index(position as i32) {
+ listbox.remove(&row);
+ }
+ }
+ for i in position..(position + added) {
+ let row = UserEntryRow::new(
+ &model
+ .item(i)
+ .unwrap()
+ .downcast::<gtk::StackPage>()
+ .unwrap()
+ .child()
+ .downcast::<Session>()
+ .unwrap(),
+ );
+ row.set_selected(model.is_selected(i));
+ listbox.insert(&row, i as i32);
+ }
+ }
+
+ fn update_selection(&self, position: u32, n_items: u32) {
+ let priv_ = self.imp();
+ let pages = priv_.pages.borrow();
+ let pages = if let Some(pages) = &*pages {
+ pages
+ } else {
+ return;
+ };
+
+ for i in position..(position + n_items) {
+ if let Some(row) = priv_
+ .entries
+ .row_at_index(i as i32)
+ .and_then(|row| row.downcast::<UserEntryRow>().ok())
+ {
+ row.set_selected(pages.is_selected(i));
+ }
+ }
+ }
+}
+
+impl Default for AccountSwitcher {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/src/account_switcher/user_entry.rs b/src/account_switcher/user_entry.rs
new file mode 100644
index 000000000..bceb1bc9a
--- /dev/null
+++ b/src/account_switcher/user_entry.rs
@@ -0,0 +1,145 @@
+use adw::subclass::prelude::BinImpl;
+use gtk::{self, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
+
+use super::avatar_with_selection::AvatarWithSelection;
+use crate::session::Session;
+
+mod imp {
+ use glib::subclass::InitializingObject;
+ use once_cell::sync::Lazy;
+
+ use super::*;
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/Fractal/user-entry-row.ui")]
+ pub struct UserEntryRow {
+ #[template_child]
+ pub account_avatar: TemplateChild<AvatarWithSelection>,
+ #[template_child]
+ pub display_name: TemplateChild<gtk::Label>,
+ #[template_child]
+ pub user_id: TemplateChild<gtk::Label>,
+ pub session: glib::WeakRef<Session>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for UserEntryRow {
+ const NAME: &'static str = "UserEntryRow";
+ type Type = super::UserEntryRow;
+ type ParentType = gtk::ListBoxRow;
+
+ fn class_init(klass: &mut Self::Class) {
+ AvatarWithSelection::static_type();
+ Self::bind_template(klass);
+ Self::Type::bind_template_callbacks(klass);
+ }
+
+ fn instance_init(obj: &InitializingObject<Self>) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for UserEntryRow {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![
+ glib::ParamSpecObject::new(
+ "session",
+ "Session",
+ "The session this entry represents",
+ Session::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+ ),
+ glib::ParamSpecBoolean::new(
+ "selected",
+ "Selected",
+ "Whether this session is selected",
+ false,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
+ ]
+ });
+
+ 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()),
+ "selected" => obj.set_selected(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(),
+ "selected" => obj.is_selected().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+ }
+
+ impl WidgetImpl for UserEntryRow {}
+ impl BinImpl for UserEntryRow {}
+ impl ListBoxRowImpl for UserEntryRow {}
+}
+
+glib::wrapper! {
+ pub struct UserEntryRow(ObjectSubclass<imp::UserEntryRow>)
+ @extends gtk::Widget, gtk::ListBoxRow, @implements gtk::Accessible;
+}
+
+#[gtk::template_callbacks]
+impl UserEntryRow {
+ pub fn new(session: &Session) -> Self {
+ glib::Object::new(&[("session", session)]).expect("Failed to create UserEntryRow")
+ }
+
+ pub fn set_selected(&self, selected: bool) {
+ let priv_ = self.imp();
+
+ if priv_.account_avatar.is_selected() == selected {
+ return;
+ }
+
+ priv_.account_avatar.set_selected(selected);
+
+ if selected {
+ priv_.display_name.add_css_class("bold");
+ } else {
+ priv_.display_name.remove_css_class("bold");
+ }
+
+ self.notify("selected");
+ }
+
+ pub fn is_selected(&self) -> bool {
+ self.imp().account_avatar.is_selected()
+ }
+
+ #[template_callback]
+ pub fn show_account_settings(&self) {
+ if let Some(session) = self.session() {
+ self.activate_action("account-switcher.close", None)
+ .unwrap();
+ session
+ .activate_action("session.open-account-settings", None)
+ .unwrap();
+ }
+ }
+
+ pub fn session(&self) -> Option<Session> {
+ self.imp().session.upgrade()
+ }
+
+ pub fn set_session(&self, session: Option<&Session>) {
+ self.imp().session.set(session);
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 3efd8ca87..5030ee645 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,6 +8,7 @@ mod application;
mod config;
mod prelude;
+mod account_switcher;
mod components;
mod contrib;
mod error_page;
diff --git a/src/session/mod.rs b/src/session/mod.rs
index 30b152b33..2b8e61e96 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -20,7 +20,7 @@ use gtk::{
glib::{clone, source::SourceId, SyncSender},
prelude::*,
subclass::prelude::*,
- CompositeTemplate, SelectionModel,
+ CompositeTemplate,
};
use log::{debug, error, warn};
use matrix_sdk::{
@@ -710,12 +710,6 @@ impl Session {
}
}
- pub fn set_logged_in_users(&self, sessions_stack_pages: &SelectionModel) {
- self.imp()
- .sidebar
- .set_logged_in_users(sessions_stack_pages, self);
- }
-
/// Returns the parent GtkWindow containing this widget.
fn parent_window(&self) -> Option<Window> {
self.root()?.downcast().ok()
diff --git a/src/session/sidebar/mod.rs b/src/session/sidebar/mod.rs
index 199ac91f1..3686e77c7 100644
--- a/src/session/sidebar/mod.rs
+++ b/src/session/sidebar/mod.rs
@@ -1,4 +1,3 @@
-mod account_switcher;
mod category;
mod category_row;
mod category_type;
@@ -12,13 +11,12 @@ mod selection;
mod sidebar_item;
mod verification_row;
-use account_switcher::AccountSwitcher;
use adw::{prelude::*, subclass::prelude::*};
use gtk::{
gio, glib,
glib::{clone, closure},
subclass::prelude::*,
- CompositeTemplate, SelectionModel,
+ CompositeTemplate,
};
pub use self::{
@@ -38,8 +36,9 @@ use crate::{
session::{
room::{Room, RoomType},
verification::IdentityVerification,
- Session, User,
+ User,
},
+ Window,
};
mod imp {
@@ -61,14 +60,14 @@ mod imp {
#[template_child]
pub headerbar: TemplateChild<adw::HeaderBar>,
#[template_child]
- pub account_switcher: TemplateChild<AccountSwitcher>,
- #[template_child]
pub listview: TemplateChild<gtk::ListView>,
#[template_child]
pub room_search_entry: TemplateChild<gtk::SearchEntry>,
#[template_child]
pub room_search: TemplateChild<gtk::SearchBar>,
#[template_child]
+ pub account_switcher_button: TemplateChild<gtk::MenuButton>,
+ #[template_child]
pub room_row_menu: TemplateChild<gio::MenuModel>,
pub room_row_popover: OnceCell<gtk::PopoverMenu>,
pub user: RefCell<Option<User>>,
@@ -242,6 +241,21 @@ mod imp {
_ => {}
}
});
+
+ self.account_switcher_button.set_create_popup_func(clone!(@weak obj => move |btn| {
+ if let Some(window) = obj.parent_window() {
+ let account_switcher = window.account_switcher();
+ // We need to remove the popover from the previous MenuButton, if any
+ if let Some(prev_parent) = account_switcher.parent().and_then(|btn|
btn.downcast::<gtk::MenuButton>().ok()) {
+ if &prev_parent == btn {
+ return;
+ } else {
+ prev_parent.set_popover(gtk::Widget::NONE);
+ }
+ }
+ btn.set_popover(Some(account_switcher));
+ }
+ }));
}
}
@@ -362,16 +376,6 @@ impl Sidebar {
self.notify("user");
}
- pub fn set_logged_in_users(
- &self,
- sessions_stack_pages: &SelectionModel,
- session_root: &Session,
- ) {
- self.imp()
- .account_switcher
- .set_logged_in_users(sessions_stack_pages, session_root);
- }
-
pub fn drop_source_type(&self) -> Option<RoomType> {
self.imp().drop_source_type.get()
}
@@ -488,6 +492,11 @@ impl Sidebar {
.room_row_popover
.get_or_init(|| gtk::PopoverMenu::from_model(Some(&*priv_.room_row_menu)))
}
+
+ /// Returns the parent `Window` containing the `Sidebar`
+ fn parent_window(&self) -> Option<Window> {
+ self.root()?.downcast().ok()
+ }
}
impl Default for Sidebar {
diff --git a/src/window.rs b/src/window.rs
index a53fe7b5f..3f911e4bc 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -5,6 +5,7 @@ use gtk::{self, gio, glib, glib::clone, prelude::*, subclass::prelude::*, Compos
use log::warn;
use crate::{
+ account_switcher::AccountSwitcher,
components::{InAppNotification, Toast},
config::{APP_ID, PROFILE},
secret::{self, SecretError},
@@ -34,6 +35,7 @@ mod imp {
pub sessions: TemplateChild<gtk::Stack>,
#[template_child]
pub error_list: TemplateChild<gio::ListStore>,
+ pub account_switcher: AccountSwitcher,
}
#[glib::object_subclass]
@@ -103,6 +105,8 @@ mod imp {
spawn!(clone!(@weak obj => async move {
obj.restore_sessions().await;
}));
+
+ self.account_switcher.set_pages(Some(self.sessions.pages()));
}
}
@@ -136,7 +140,6 @@ impl Window {
let priv_ = &self.imp();
let prev_has_sessions = self.has_sessions();
- session.set_logged_in_users(&priv_.sessions.pages());
priv_.sessions.add_child(session);
priv_.sessions.set_visible_child(session);
// We need to grab the focus so that keyboard shortcuts work
@@ -290,4 +293,8 @@ impl Window {
pub fn add_toast(&self, toast: &Toast) {
self.imp().error_list.append(toast);
}
+
+ pub fn account_switcher(&self) -> &AccountSwitcher {
+ &self.imp().account_switcher
+ }
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]