Add account switcher
This commit is contained in:
parent
c3f7e38f30
commit
7c202b9488
17 changed files with 584 additions and 7 deletions
|
@ -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>
|
||||
|
@ -19,6 +21,7 @@
|
|||
<file compressed="true" preprocess="xml-stripblanks" alias="login.ui">ui/login.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="session.ui">ui/session.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="sidebar.ui">ui/sidebar.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="sidebar-account-switcher.ui">ui/sidebar-account-switcher.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="sidebar-item.ui">ui/sidebar-item.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="sidebar-category-row.ui">ui/sidebar-category-row.ui</file>
|
||||
<file compressed="true" preprocess="xml-stripblanks" alias="sidebar-entry-row.ui">ui/sidebar-entry-row.ui</file>
|
||||
|
|
|
@ -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;
|
||||
|
|
23
data/resources/ui/add-account-row.ui
Normal file
23
data/resources/ui/add-account-row.ui
Normal file
|
@ -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>
|
11
data/resources/ui/sidebar-account-switcher.ui
Normal file
11
data/resources/ui/sidebar-account-switcher.ui
Normal file
|
@ -0,0 +1,11 @@
|
|||
<?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>
|
||||
</child>
|
||||
</template>
|
||||
</interface>
|
|
@ -25,12 +25,16 @@
|
|||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="AdwHeaderBar" id="headerbar">
|
||||
<property name="title-widget">
|
||||
<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="GtkToggleButton" id="search_button">
|
||||
<property name="icon-name">system-search-symbolic</property>
|
||||
<property name="active" bind-source="room_search" bind-property="search-mode-enabled" bind-flags="sync-create"/>
|
||||
<property name="action-name">win.toggle-room-search</property>
|
||||
<object class="GtkMenuButton" id="accounts_button">
|
||||
<property name="icon-name">system-users-symbolic</property>
|
||||
<property name="popover">
|
||||
<object class="AccountSwitcher" id="account_switcher"></object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
|
@ -39,6 +43,13 @@
|
|||
<property name="menu-model">primary_menu</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkToggleButton" id="search_button">
|
||||
<property name="icon-name">system-search-symbolic</property>
|
||||
<property name="active" bind-source="room_search" bind-property="search-mode-enabled" bind-flags="sync-create"/>
|
||||
<property name="action-name">win.toggle-room-search</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
|
|
62
data/resources/ui/user-entry-row.ui
Normal file
62
data/resources/ui/user-entry-row.ui
Normal file
|
@ -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>
|
|
@ -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
|
||||
|
@ -64,6 +66,10 @@ src/session/room/highlight_flags.rs
|
|||
src/session/room/item.rs
|
||||
src/session/room/mod.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
|
||||
|
|
|
@ -120,6 +120,14 @@ impl Application {
|
|||
app.show_about_dialog();
|
||||
})
|
||||
);
|
||||
|
||||
action!(
|
||||
self,
|
||||
"new-login",
|
||||
clone!(@weak self as app => move |_, _| {
|
||||
app.get_main_window().switch_to_login_page();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/// Sets up keyboard shortcuts for application and window actions.
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -69,6 +69,10 @@ sources = files(
|
|||
'session/sidebar/row.rs',
|
||||
'session/sidebar/room_row.rs',
|
||||
'session/sidebar/selection.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(
|
||||
|
|
|
@ -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 {
|
||||
|
|
43
src/session/sidebar/account_switcher/add_account.rs
Normal file
43
src/session/sidebar/account_switcher/add_account.rs
Normal file
|
@ -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")
|
||||
}
|
||||
}
|
148
src/session/sidebar/account_switcher/item.rs
Normal file
148
src/session/sidebar/account_switcher/item.rs
Normal file
|
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
124
src/session/sidebar/account_switcher/mod.rs
Normal file
124
src/session/sidebar/account_switcher/mod.rs
Normal file
|
@ -0,0 +1,124 @@
|
|||
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};
|
||||
|
||||
pub mod add_account;
|
||||
pub mod item;
|
||||
pub mod user_entry;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
use glib::subclass::InitializingObject;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[template(resource = "/org/gnome/FractalNext/sidebar-account-switcher.ui")]
|
||||
pub struct AccountSwitcher {
|
||||
#[template_child]
|
||||
pub entries: TemplateChild<gtk::ListView>,
|
||||
}
|
||||
|
||||
#[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);
|
||||
}
|
||||
|
||||
fn instance_init(obj: &InitializingObject<Self>) {
|
||||
obj.init_template();
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for AccountSwitcher {
|
||||
fn constructed(&self, obj: &Self::Type) {
|
||||
self.parent_constructed(obj);
|
||||
|
||||
self.entries.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);
|
||||
}
|
||||
AccountSwitcherItem::AddAccount => {
|
||||
list_view.activate_action("app.new-login", None);
|
||||
}
|
||||
_ => {}
|
||||
});
|
||||
});
|
||||
|
||||
// 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::NONE_WIDGET);
|
||||
});
|
||||
|
||||
self.entries.set_factory(Some(factory));
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetImpl for AccountSwitcher {}
|
||||
impl PopoverImpl for AccountSwitcher {}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
pub struct AccountSwitcher(ObjectSubclass<imp::AccountSwitcher>)
|
||||
@extends gtk::Widget, gtk::Popover, @implements gtk::Accessible, gio::ListModel;
|
||||
}
|
||||
|
||||
impl AccountSwitcher {
|
||||
pub fn set_logged_in_users(&self, sessions_stack_pages: &SelectionModel) {
|
||||
let entries = imp::AccountSwitcher::from_instance(self).entries.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));
|
||||
|
||||
entries.set_model(Some(selectable_items));
|
||||
}
|
||||
}
|
91
src/session/sidebar/account_switcher/user_entry.rs
Normal file
91
src/session/sidebar/account_switcher/user_entry.rs
Normal file
|
@ -0,0 +1,91 @@
|
|||
use crate::components::Avatar;
|
||||
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(
|
||||
"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() {
|
||||
"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() {
|
||||
"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")
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
mod account_switcher;
|
||||
mod category;
|
||||
mod category_row;
|
||||
mod entry;
|
||||
|
@ -17,11 +18,12 @@ use self::row::Row;
|
|||
use self::selection::Selection;
|
||||
|
||||
use adw::subclass::prelude::BinImpl;
|
||||
use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate};
|
||||
use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate, SelectionModel};
|
||||
|
||||
use crate::session::content::ContentType;
|
||||
use crate::session::room::Room;
|
||||
use crate::session::RoomList;
|
||||
use account_switcher::AccountSwitcher;
|
||||
|
||||
mod imp {
|
||||
use super::*;
|
||||
|
@ -38,6 +40,8 @@ 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>,
|
||||
|
@ -263,6 +267,12 @@ impl Sidebar {
|
|||
priv_.selected_room.replace(selected_room);
|
||||
self.notify("selected-room");
|
||||
}
|
||||
|
||||
pub fn set_logged_in_users(&self, sessions_stack_pages: &SelectionModel) {
|
||||
imp::Sidebar::from_instance(self)
|
||||
.account_switcher
|
||||
.set_logged_in_users(sessions_stack_pages);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Sidebar {
|
||||
|
|
|
@ -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);
|
||||
|
@ -179,4 +180,9 @@ impl Window {
|
|||
let priv_ = imp::Window::from_instance(self);
|
||||
priv_.main_stack.set_visible_child(&priv_.sessions.get());
|
||||
}
|
||||
|
||||
pub fn switch_to_login_page(&self) {
|
||||
let priv_ = imp::Window::from_instance(self);
|
||||
priv_.main_stack.set_visible_child(&priv_.login.get());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue