[fractal/multi-account: 5/9] Add account switcher
- From: Alejandro Domínguez <aledomu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/multi-account: 5/9] Add account switcher
- Date: Tue, 24 Aug 2021 20:05:58 +0000 (UTC)
commit 418998ad4bc63cb5a52a3497a79fb6d3b7341a18
Author: Alejandro Domínguez <adomu net-c com>
Date: Tue Jul 13 15:34:37 2021 +0200
Add account switcher
data/resources/resources.gresource.xml | 2 +
data/resources/style.css | 22 +++
data/resources/ui/add-account-row.ui | 23 ++++
data/resources/ui/sidebar.ui | 15 +++
data/resources/ui/user-entry-row.ui | 62 +++++++++
po/POTFILES.in | 6 +
src/components/avatar.rs | 2 +-
src/meson.build | 4 +
src/session/mod.rs | 7 +-
.../sidebar/account_switcher/add_account.rs | 43 ++++++
src/session/sidebar/account_switcher/item.rs | 148 ++++++++++++++++++++
src/session/sidebar/account_switcher/mod.rs | 3 +
src/session/sidebar/account_switcher/user_entry.rs | 150 +++++++++++++++++++++
src/session/sidebar/mod.rs | 1 +
src/session/sidebar/sidebar.rs | 78 ++++++++++-
src/window.rs | 1 +
16 files changed, 564 insertions(+), 3 deletions(-)
---
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index 58479c3c..1dcb63b9 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/FractalNext/">
+ <file compressed="true" preprocess="xml-stripblanks"
alias="add-account-row.ui">ui/add-account-row.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks"
alias="user-entry-row.ui">ui/user-entry-row.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="shortcuts.ui">ui/shortcuts.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="content.ui">ui/content.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="content-room-history.ui">ui/content-room-history.ui</file>
diff --git a/data/resources/style.css b/data/resources/style.css
index 95bae3f1..bb55f443 100644
--- a/data/resources/style.css
+++ b/data/resources/style.css
@@ -78,6 +78,28 @@ headerbar.flat {
border: none;
}
+/* Account switcher */
+#account-switcher row {
+ border-radius: 10px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ padding-top: 7px;
+ padding-bottom: 7px;
+}
+
+#account-switcher .user-id {
+ font-size: 12px;
+}
+
+#new-login-icon {
+ /*
+ * 2 * padding + pixel-size = size (of avatar)
+ */
+ padding: 10px;
+ background-color: lightgrey;
+ border-radius: 9999px;
+}
+
/* Sidebar */
.sidebar row {
padding-left: 10px;
diff --git a/data/resources/ui/add-account-row.ui b/data/resources/ui/add-account-row.ui
new file mode 100644
index 00000000..367fe5ca
--- /dev/null
+++ b/data/resources/ui/add-account-row.ui
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="AddAccountRow" parent="AdwBin">
+ <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">20</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel">
+ <property name="use-underline">true</property>
+ <property name="label">_Add Account</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/data/resources/ui/sidebar.ui b/data/resources/ui/sidebar.ui
index 5de728b5..eb9f13d3 100644
--- a/data/resources/ui/sidebar.ui
+++ b/data/resources/ui/sidebar.ui
@@ -29,6 +29,21 @@
<object class="AdwWindowTitle"></object>
</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="icon-name">system-users-symbolic</property>
+ <property name="popover">
+ <object class="GtkPopover">
+ <child>
+ <object class="GtkListView" id="account_switcher">
+ <property name="name">account-switcher</property>
+ <property name="single-click-activate">true</property>
+ </object>
+ </child>
+ </object>
+ </property>
+ </object>
+ </child>
<child type="end">
<object class="GtkMenuButton" id="appmenu_button">
<property name="icon-name">open-menu-symbolic</property>
diff --git a/data/resources/ui/user-entry-row.ui b/data/resources/ui/user-entry-row.ui
new file mode 100644
index 00000000..611fc607
--- /dev/null
+++ b/data/resources/ui/user-entry-row.ui
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="UserEntryRow" parent="AdwBin">
+ <child>
+ <object class="GtkBox">
+ <property name="spacing">10</property>
+ <child>
+ <object class="ComponentsAvatar" id="avatar_component">
+ <property name="size">40</property>
+ <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>
+ </lookup>
+ </binding>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="spacing">5</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="display_name">
+ <property name="xalign">0.0</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>
+ </lookup>
+ </binding>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="user_id">
+ <property name="xalign">0.0</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>
+ </lookup>
+ </binding>
+ <style>
+ <class name="dim-label" />
+ <class name="user-id" />
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d4a8fc10..554422f7 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -5,6 +5,7 @@ data/org.gnome.FractalNext.gschema.xml.in
data/org.gnome.FractalNext.metainfo.xml.in.in
# UI files
+data/resources/ui/add_account.ui
data/resources/ui/components-avatar.ui
data/resources/ui/content-divider-row.ui
data/resources/ui/content-item-row-menu.ui
@@ -29,6 +30,7 @@ data/resources/ui/sidebar-room-row.ui
data/resources/ui/sidebar.ui
data/resources/ui/spinner-button.ui
data/resources/ui/pill.ui
+data/resources/ui/user-entry-row.ui
data/resources/ui/window.ui
# Rust files
@@ -68,6 +70,10 @@ src/session/room/item.rs
src/session/room/mod.rs
src/session/room/room.rs
src/session/room/timeline.rs
+src/session/sidebar/account_switcher/add_account.rs
+src/session/sidebar/account_switcher/item.rs
+src/session/sidebar/account_switcher/mod.rs
+src/session/sidebar/account_switcher/user_entry.rs
src/session/sidebar/category_row.rs
src/session/sidebar/entry.rs
src/session/sidebar/mod.rs
diff --git a/src/components/avatar.rs b/src/components/avatar.rs
index 49e3e90b..20e478f0 100644
--- a/src/components/avatar.rs
+++ b/src/components/avatar.rs
@@ -6,6 +6,7 @@ use crate::session::Avatar as AvatarItem;
mod imp {
use super::*;
use glib::subclass::InitializingObject;
+ use once_cell::sync::Lazy;
use std::cell::RefCell;
#[derive(Debug, Default, CompositeTemplate)]
@@ -34,7 +35,6 @@ mod imp {
impl ObjectImpl for Avatar {
fn properties() -> &'static [glib::ParamSpec] {
- use once_cell::sync::Lazy;
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![
glib::ParamSpec::new_object(
diff --git a/src/meson.build b/src/meson.build
index 5ce9765a..193238ca 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -74,6 +74,10 @@ sources = files(
'session/sidebar/room_row.rs',
'session/sidebar/selection.rs',
'session/sidebar/sidebar.rs',
+ 'session/sidebar/account_switcher/add_account.rs',
+ 'session/sidebar/account_switcher/item.rs',
+ 'session/sidebar/account_switcher/mod.rs',
+ 'session/sidebar/account_switcher/user_entry.rs',
)
custom_target(
diff --git a/src/session/mod.rs b/src/session/mod.rs
index 3084f7cd..436fa2f6 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -25,7 +25,7 @@ use crate::session::content::ContentType;
use adw::subclass::prelude::BinImpl;
use gtk::subclass::prelude::*;
use gtk::{self, prelude::*};
-use gtk::{gio, glib, glib::clone, glib::SyncSender, CompositeTemplate};
+use gtk::{gio, glib, glib::clone, glib::SyncSender, CompositeTemplate, SelectionModel};
use gtk_macros::send;
use log::error;
use matrix_sdk::ruma::{
@@ -449,6 +449,11 @@ impl Session {
fn handle_sync_response(&self, response: SyncResponse) {
self.room_list().handle_response_rooms(response.rooms);
}
+
+ pub fn set_logged_in_users(&self, sessions_stack_pages: &SelectionModel) {
+ let priv_ = &imp::Session::from_instance(self);
+ priv_.sidebar.set_logged_in_users(sessions_stack_pages);
+ }
}
impl Default for Session {
diff --git a/src/session/sidebar/account_switcher/add_account.rs
b/src/session/sidebar/account_switcher/add_account.rs
new file mode 100644
index 00000000..abf9ccff
--- /dev/null
+++ b/src/session/sidebar/account_switcher/add_account.rs
@@ -0,0 +1,43 @@
+use adw::subclass::prelude::BinImpl;
+use gtk::subclass::prelude::*;
+use gtk::{self, prelude::*};
+use gtk::{glib, CompositeTemplate};
+
+mod imp {
+ use super::*;
+ use glib::subclass::InitializingObject;
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/FractalNext/add-account-row.ui")]
+ pub struct AddAccountRow;
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for AddAccountRow {
+ const NAME: &'static str = "AddAccountRow";
+ type Type = super::AddAccountRow;
+ type ParentType = adw::Bin;
+
+ fn class_init(klass: &mut Self::Class) {
+ Self::bind_template(klass);
+ }
+
+ fn instance_init(obj: &InitializingObject<Self>) {
+ obj.init_template();
+ }
+ }
+
+ impl ObjectImpl for AddAccountRow {}
+ impl WidgetImpl for AddAccountRow {}
+ impl BinImpl for AddAccountRow {}
+}
+
+glib::wrapper! {
+ pub struct AddAccountRow(ObjectSubclass<imp::AddAccountRow>)
+ @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
+}
+
+impl AddAccountRow {
+ pub fn new() -> Self {
+ glib::Object::new(&[]).expect("Failed to create AddAccountRow")
+ }
+}
diff --git a/src/session/sidebar/account_switcher/item.rs b/src/session/sidebar/account_switcher/item.rs
new file mode 100644
index 00000000..332fa3e8
--- /dev/null
+++ b/src/session/sidebar/account_switcher/item.rs
@@ -0,0 +1,148 @@
+use super::add_account::AddAccountRow;
+use super::user_entry::UserEntryRow;
+use gtk::{gio::ListStore, glib, prelude::*, subclass::prelude::*};
+use std::convert::TryFrom;
+
+mod imp {
+ use super::*;
+ use once_cell::sync::Lazy;
+ use std::cell::Cell;
+
+ #[derive(Debug, Default)]
+ pub struct ExtraItemObj(pub Cell<super::ExtraItem>);
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for ExtraItemObj {
+ const NAME: &'static str = "ExtraItemObj";
+ type Type = super::ExtraItemObj;
+ type ParentType = glib::Object;
+ }
+
+ impl ObjectImpl for ExtraItemObj {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::new_enum(
+ "inner",
+ "Inner",
+ "Inner value of ExtraItem",
+ super::ExtraItem::static_type(),
+ 0,
+ glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "inner" => obj.get().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.name() {
+ "inner" => self.0.set(value.get().unwrap()),
+ _ => unimplemented!(),
+ }
+ }
+ }
+}
+
+#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy, glib::GEnum)]
+#[repr(u32)]
+#[genum(type_name = "ExtraItem")]
+pub enum ExtraItem {
+ Separator = 0,
+ AddAccount = 1,
+}
+
+impl ExtraItem {
+ const VALUES: [Self; 2] = [Self::Separator, Self::AddAccount];
+}
+
+impl Default for ExtraItem {
+ fn default() -> Self {
+ Self::Separator
+ }
+}
+
+glib::wrapper! {
+ pub struct ExtraItemObj(ObjectSubclass<imp::ExtraItemObj>);
+}
+
+impl From<&ExtraItem> for ExtraItemObj {
+ fn from(item: &ExtraItem) -> Self {
+ glib::Object::new(&[("inner", item)]).expect("Failed to create ExtraItem")
+ }
+}
+
+impl ExtraItemObj {
+ pub fn list_store() -> ListStore {
+ ExtraItem::VALUES.iter().map(ExtraItemObj::from).fold(
+ ListStore::new(ExtraItemObj::static_type()),
+ |list_items, item| {
+ list_items.append(&item);
+ list_items
+ },
+ )
+ }
+
+ pub fn get(&self) -> ExtraItem {
+ let priv_ = imp::ExtraItemObj::from_instance(self);
+
+ priv_.0.get()
+ }
+
+ pub fn is_separator(&self) -> bool {
+ self.get() == ExtraItem::Separator
+ }
+
+ pub fn is_add_account(&self) -> bool {
+ self.get() == ExtraItem::AddAccount
+ }
+}
+
+#[derive(Debug, Clone)]
+pub enum Item {
+ User(gtk::StackPage),
+ Separator,
+ AddAccount,
+}
+
+impl From<ExtraItem> for Item {
+ fn from(extra_item: ExtraItem) -> Self {
+ match extra_item {
+ ExtraItem::Separator => Self::Separator,
+ ExtraItem::AddAccount => Self::AddAccount,
+ }
+ }
+}
+
+impl TryFrom<glib::Object> for Item {
+ type Error = glib::Object;
+
+ fn try_from(object: glib::Object) -> Result<Self, Self::Error> {
+ object
+ .downcast::<gtk::StackPage>()
+ .map(Self::User)
+ .or_else(|object| object.downcast::<ExtraItemObj>().map(|it| it.get().into()))
+ }
+}
+
+impl Item {
+ pub fn build_widget(&self) -> gtk::Widget {
+ match self {
+ Self::User(ref session_page) => UserEntryRow::new(session_page).upcast(),
+ Self::Separator => gtk::Separator::new(gtk::Orientation::Vertical).upcast(),
+ Self::AddAccount => AddAccountRow::new().upcast(),
+ }
+ }
+}
diff --git a/src/session/sidebar/account_switcher/mod.rs b/src/session/sidebar/account_switcher/mod.rs
new file mode 100644
index 00000000..d244c4b3
--- /dev/null
+++ b/src/session/sidebar/account_switcher/mod.rs
@@ -0,0 +1,3 @@
+pub mod add_account;
+pub mod item;
+pub mod user_entry;
diff --git a/src/session/sidebar/account_switcher/user_entry.rs
b/src/session/sidebar/account_switcher/user_entry.rs
new file mode 100644
index 00000000..c60a0f69
--- /dev/null
+++ b/src/session/sidebar/account_switcher/user_entry.rs
@@ -0,0 +1,150 @@
+use crate::{components::Avatar, session::Avatar as AvatarItem};
+use adw::subclass::prelude::BinImpl;
+use gtk::{self, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
+
+mod imp {
+ use super::*;
+ use glib::subclass::InitializingObject;
+ use once_cell::sync::Lazy;
+ use std::cell::RefCell;
+
+ #[derive(Debug, Default, CompositeTemplate)]
+ #[template(resource = "/org/gnome/FractalNext/user-entry-row.ui")]
+ pub struct UserEntryRow {
+ #[template_child]
+ pub avatar_component: TemplateChild<Avatar>,
+ #[template_child]
+ pub display_name: TemplateChild<gtk::Label>,
+ #[template_child]
+ pub user_id: TemplateChild<gtk::Label>,
+ pub session_page: RefCell<Option<gtk::StackPage>>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for UserEntryRow {
+ const NAME: &'static str = "UserEntryRow";
+ type Type = super::UserEntryRow;
+ type ParentType = adw::Bin;
+
+ fn class_init(klass: &mut Self::Class) {
+ Avatar::static_type();
+ Self::bind_template(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::ParamSpec::new_object(
+ "avatar",
+ "Avatar",
+ "The avatar of the user",
+ AvatarItem::static_type(),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::new_string(
+ "display-name",
+ "Display name",
+ "The display name of the user",
+ Some(""),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::new_string(
+ "user-id",
+ "User ID",
+ "The user ID",
+ Some(""),
+ glib::ParamFlags::READWRITE,
+ ),
+ glib::ParamSpec::new_object(
+ "session-page",
+ "Session StackPage",
+ "The stack page of the session that this entry represents",
+ gtk::StackPage::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() {
+ "avatar" => {
+ let avatar = value.get().unwrap();
+ obj.set_avatar(avatar);
+ }
+ "display-name" => {
+ let display_name = value.get().unwrap();
+ obj.set_display_name(display_name);
+ }
+ "user-id" => {
+ let user_id = value.get().unwrap();
+ obj.set_user_id(user_id);
+ }
+ "session-page" => {
+ let session_page = value.get().unwrap();
+ self.session_page.replace(Some(session_page));
+ }
+ _ => unimplemented!(),
+ }
+ }
+
+ fn property(&self, _obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "avatar" => self.avatar_component.item().to_value(),
+ "display-name" => self.display_name.label().to_value(),
+ "user-id" => self.user_id.label().to_value(),
+ "session-page" => self.session_page.borrow().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+ }
+
+ impl WidgetImpl for UserEntryRow {}
+ impl BinImpl for UserEntryRow {}
+}
+
+glib::wrapper! {
+ pub struct UserEntryRow(ObjectSubclass<imp::UserEntryRow>)
+ @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
+}
+
+impl UserEntryRow {
+ pub fn new(session_page: >k::StackPage) -> Self {
+ glib::Object::new(&[("session-page", session_page)]).expect("Failed to create UserEntryRow")
+ }
+
+ pub fn set_avatar(&self, avatar_item: AvatarItem) {
+ let priv_ = imp::UserEntryRow::from_instance(self);
+
+ priv_.avatar_component.set_item(Some(avatar_item));
+ }
+
+ pub fn set_display_name(&self, display_name: String) {
+ let priv_ = imp::UserEntryRow::from_instance(self);
+
+ priv_.display_name.set_label(&display_name);
+ if let Some(item) = priv_.avatar_component.item() {
+ item.set_display_name(Some(display_name));
+ }
+ }
+
+ pub fn set_user_id(&self, user_id: String) {
+ let priv_ = imp::UserEntryRow::from_instance(self);
+
+ priv_.user_id.set_label(&user_id);
+ }
+}
diff --git a/src/session/sidebar/mod.rs b/src/session/sidebar/mod.rs
index e9cc2def..ac8dc48d 100644
--- a/src/session/sidebar/mod.rs
+++ b/src/session/sidebar/mod.rs
@@ -1,3 +1,4 @@
+mod account_switcher;
mod category;
mod category_row;
mod entry;
diff --git a/src/session/sidebar/sidebar.rs b/src/session/sidebar/sidebar.rs
index 19fe5a82..0f073d88 100644
--- a/src/session/sidebar/sidebar.rs
+++ b/src/session/sidebar/sidebar.rs
@@ -1,6 +1,14 @@
use adw::subclass::prelude::BinImpl;
-use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
+use gtk::{
+ gio::{self, ListModel, ListStore},
+ glib,
+ prelude::*,
+ subclass::prelude::*,
+ CompositeTemplate, SelectionModel,
+};
+use std::convert::TryFrom;
+use super::account_switcher::item::{ExtraItemObj, Item as AccountSwitcherItem};
use crate::session::{
content::ContentType,
room::Room,
@@ -23,6 +31,8 @@ mod imp {
#[template_child]
pub headerbar: TemplateChild<adw::HeaderBar>,
#[template_child]
+ pub account_switcher: TemplateChild<gtk::ListView>,
+ #[template_child]
pub listview: TemplateChild<gtk::ListView>,
#[template_child]
pub room_search_entry: TemplateChild<gtk::SearchEntry>,
@@ -142,6 +152,59 @@ mod imp {
_ => {}
}
});
+
+ // Account switcher setup
+
+ self.account_switcher.connect_activate(|list_view, index| {
+ list_view
+ .model()
+ .and_then(|model| model.item(index))
+ .map(AccountSwitcherItem::try_from)
+ .and_then(Result::ok)
+ .map(|item| match item {
+ AccountSwitcherItem::User(session_page) => {
+ let session_widget = session_page.child();
+ session_widget
+ .parent()
+ .unwrap()
+ .downcast::<gtk::Stack>()
+ .unwrap()
+ .set_visible_child(&session_widget);
+ }
+ _ => {}
+ });
+ });
+
+ // There is no permanent stuff to take care of,
+ // so only bind and unbind are connected.
+ let ref factory = gtk::SignalListItemFactory::new();
+ factory.connect_bind(|_, list_item| {
+ list_item.set_selectable(false);
+ let child = list_item
+ .item()
+ .map(AccountSwitcherItem::try_from)
+ .and_then(Result::ok)
+ .as_ref()
+ .map(|item| {
+ match item {
+ AccountSwitcherItem::Separator => {
+ list_item.set_activatable(false);
+ }
+ _ => {}
+ }
+
+ item
+ })
+ .map(AccountSwitcherItem::build_widget);
+
+ list_item.set_child(child.as_ref());
+ });
+
+ factory.connect_unbind(|_, list_item| {
+ list_item.set_child::<gtk::Widget>(None);
+ });
+
+ self.account_switcher.set_factory(Some(factory));
}
}
@@ -248,6 +311,19 @@ impl Sidebar {
priv_.selected_room.replace(selected_room);
self.notify("selected-room");
}
+
+ pub fn set_logged_in_users(&self, sessions_stack_pages: &SelectionModel) {
+ let account_switcher = imp::Sidebar::from_instance(self).account_switcher.get();
+
+ let ref end_items = ExtraItemObj::list_store();
+ let ref items_split = ListStore::new(ListModel::static_type());
+ items_split.append(sessions_stack_pages);
+ items_split.append(end_items);
+ let ref items = gtk::FlattenListModel::new(Some(items_split));
+ let ref selectable_items = gtk::NoSelection::new(Some(items));
+
+ account_switcher.set_model(Some(selectable_items));
+ }
}
impl Default for Sidebar {
diff --git a/src/window.rs b/src/window.rs
index b15df917..7e6f25da 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -99,6 +99,7 @@ impl Window {
fn add_session(&self, session: &Session) {
let priv_ = &imp::Window::from_instance(self);
+ session.set_logged_in_users(&priv_.sessions.pages());
priv_.sessions.add_child(session);
priv_.sessions.set_visible_child(session);
self.install_session_actions(session);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]