Browse Source
Rename CategoryType to SidebarSectionName and remove unused variants. Rename CategoryFilter to RoomCategoryFilter. Use Option<RoomCategory> instead of CategoryType for drag-n-drop operations, preventing us from using GObject properties.fractal-9
20 changed files with 728 additions and 738 deletions
@ -1,63 +0,0 @@
|
||||
use std::fmt; |
||||
|
||||
use gettextrs::gettext; |
||||
use gtk::glib; |
||||
|
||||
use crate::session::model::RoomCategory; |
||||
|
||||
#[derive(Debug, Default, Hash, Eq, PartialEq, Clone, Copy, glib::Enum)] |
||||
#[repr(i32)] |
||||
#[enum_type(name = "CategoryType")] |
||||
pub enum CategoryType { |
||||
#[default] |
||||
None = -1, |
||||
VerificationRequest = 0, |
||||
Invited = 1, |
||||
Favorite = 2, |
||||
Normal = 3, |
||||
LowPriority = 4, |
||||
Left = 5, |
||||
Outdated = 6, |
||||
Space = 7, |
||||
Ignored = 8, |
||||
} |
||||
|
||||
impl fmt::Display for CategoryType { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
let label = match self { |
||||
CategoryType::None => unimplemented!(), |
||||
CategoryType::VerificationRequest => gettext("Verifications"), |
||||
CategoryType::Invited => gettext("Invited"), |
||||
CategoryType::Favorite => gettext("Favorites"), |
||||
CategoryType::Normal => gettext("Rooms"), |
||||
CategoryType::LowPriority => gettext("Low Priority"), |
||||
CategoryType::Left => gettext("Historical"), |
||||
// These categories are hidden.
|
||||
CategoryType::Outdated | CategoryType::Space | CategoryType::Ignored => { |
||||
unimplemented!() |
||||
} |
||||
}; |
||||
f.write_str(&label) |
||||
} |
||||
} |
||||
|
||||
impl From<RoomCategory> for CategoryType { |
||||
fn from(category: RoomCategory) -> Self { |
||||
Self::from(&category) |
||||
} |
||||
} |
||||
|
||||
impl From<&RoomCategory> for CategoryType { |
||||
fn from(category: &RoomCategory) -> Self { |
||||
match category { |
||||
RoomCategory::Invited => Self::Invited, |
||||
RoomCategory::Favorite => Self::Favorite, |
||||
RoomCategory::Normal => Self::Normal, |
||||
RoomCategory::LowPriority => Self::LowPriority, |
||||
RoomCategory::Left => Self::Left, |
||||
RoomCategory::Outdated => Self::Outdated, |
||||
RoomCategory::Space => Self::Space, |
||||
RoomCategory::Ignored => Self::Ignored, |
||||
} |
||||
} |
||||
} |
||||
@ -1,15 +1,15 @@
|
||||
mod category; |
||||
mod icon_item; |
||||
mod item; |
||||
mod item_list; |
||||
mod list_model; |
||||
mod section; |
||||
mod selection; |
||||
|
||||
pub use self::{ |
||||
category::{Category, CategoryType}, |
||||
icon_item::{SidebarIconItem, SidebarIconItemType}, |
||||
item::SidebarItem, |
||||
item_list::SidebarItemList, |
||||
list_model::SidebarListModel, |
||||
section::{SidebarSection, SidebarSectionName}, |
||||
selection::Selection, |
||||
}; |
||||
|
||||
@ -0,0 +1,73 @@
|
||||
use std::fmt; |
||||
|
||||
use gettextrs::gettext; |
||||
use gtk::glib; |
||||
use serde::{Deserialize, Serialize}; |
||||
|
||||
use crate::session::model::RoomCategory; |
||||
|
||||
/// The possible names of the sections in the sidebar.
|
||||
#[derive(
|
||||
Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, glib::Enum, Serialize, Deserialize, |
||||
)] |
||||
#[enum_type(name = "SidebarSectionName")] |
||||
#[serde(rename_all = "kebab-case")] |
||||
pub enum SidebarSectionName { |
||||
/// The section for verification requests.
|
||||
VerificationRequest, |
||||
/// The section for room invites.
|
||||
Invited, |
||||
/// The section for favorite rooms.
|
||||
Favorite, |
||||
/// The section for joined rooms without a tag.
|
||||
#[default] |
||||
Normal, |
||||
/// The section for low-priority rooms.
|
||||
LowPriority, |
||||
/// The section for room that were left.
|
||||
Left, |
||||
} |
||||
|
||||
impl SidebarSectionName { |
||||
/// Convert the given `RoomCategory` to a `SidebarSectionName`, if possible.
|
||||
pub fn from_room_category(category: RoomCategory) -> Option<Self> { |
||||
let name = match category { |
||||
RoomCategory::Invited => Self::Invited, |
||||
RoomCategory::Favorite => Self::Favorite, |
||||
RoomCategory::Normal => Self::Normal, |
||||
RoomCategory::LowPriority => Self::LowPriority, |
||||
RoomCategory::Left => Self::Left, |
||||
RoomCategory::Outdated | RoomCategory::Space | RoomCategory::Ignored => return None, |
||||
}; |
||||
|
||||
Some(name) |
||||
} |
||||
|
||||
/// Convert this `SidebarSectionName` to a `RoomCategory`, if possible.
|
||||
pub fn as_room_category(&self) -> Option<RoomCategory> { |
||||
let category = match self { |
||||
Self::VerificationRequest => return None, |
||||
Self::Invited => RoomCategory::Invited, |
||||
Self::Favorite => RoomCategory::Favorite, |
||||
Self::Normal => RoomCategory::Normal, |
||||
Self::LowPriority => RoomCategory::LowPriority, |
||||
Self::Left => RoomCategory::Left, |
||||
}; |
||||
|
||||
Some(category) |
||||
} |
||||
} |
||||
|
||||
impl fmt::Display for SidebarSectionName { |
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
||||
let label = match self { |
||||
SidebarSectionName::VerificationRequest => gettext("Verifications"), |
||||
SidebarSectionName::Invited => gettext("Invited"), |
||||
SidebarSectionName::Favorite => gettext("Favorites"), |
||||
SidebarSectionName::Normal => gettext("Rooms"), |
||||
SidebarSectionName::LowPriority => gettext("Low Priority"), |
||||
SidebarSectionName::Left => gettext("Historical"), |
||||
}; |
||||
f.write_str(&label) |
||||
} |
||||
} |
||||
@ -1,212 +0,0 @@
|
||||
use adw::subclass::prelude::BinImpl; |
||||
use gettextrs::gettext; |
||||
use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate}; |
||||
|
||||
use crate::session::model::{Category, CategoryType}; |
||||
|
||||
mod imp { |
||||
use std::{ |
||||
cell::{Cell, RefCell}, |
||||
marker::PhantomData, |
||||
}; |
||||
|
||||
use glib::subclass::InitializingObject; |
||||
|
||||
use super::*; |
||||
|
||||
#[derive(Debug, Default, CompositeTemplate, glib::Properties)] |
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/sidebar/category_row.ui")] |
||||
#[properties(wrapper_type = super::CategoryRow)] |
||||
pub struct CategoryRow { |
||||
/// The category of this row.
|
||||
#[property(get, set = Self::set_category, explicit_notify, nullable)] |
||||
pub category: RefCell<Option<Category>>, |
||||
category_binding: RefCell<Option<glib::Binding>>, |
||||
/// The expanded state of this row.
|
||||
#[property(get, set = Self::set_expanded, explicit_notify, construct, default = true)] |
||||
pub expanded: Cell<bool>, |
||||
/// The label to show for this row.
|
||||
#[property(get = Self::label)] |
||||
pub label: PhantomData<Option<String>>, |
||||
/// The `CategoryType` to show a label for during a drag-and-drop
|
||||
/// operation.
|
||||
///
|
||||
/// This will change the label according to the action that can be
|
||||
/// performed when changing from the `CategoryType` to this
|
||||
/// row's `Category`.
|
||||
#[property(get, set = Self::set_show_label_for_category, explicit_notify, builder(CategoryType::default()))] |
||||
pub show_label_for_category: Cell<CategoryType>, |
||||
/// The label showing the category name.
|
||||
#[template_child] |
||||
pub display_name: TemplateChild<gtk::Label>, |
||||
} |
||||
|
||||
#[glib::object_subclass] |
||||
impl ObjectSubclass for CategoryRow { |
||||
const NAME: &'static str = "SidebarCategoryRow"; |
||||
type Type = super::CategoryRow; |
||||
type ParentType = adw::Bin; |
||||
|
||||
fn class_init(klass: &mut Self::Class) { |
||||
Self::bind_template(klass); |
||||
klass.set_css_name("category"); |
||||
} |
||||
|
||||
fn instance_init(obj: &InitializingObject<Self>) { |
||||
obj.init_template(); |
||||
} |
||||
} |
||||
|
||||
#[glib::derived_properties] |
||||
impl ObjectImpl for CategoryRow { |
||||
fn constructed(&self) { |
||||
self.parent_constructed(); |
||||
|
||||
self.obj().connect_parent_notify(|obj| { |
||||
obj.set_expanded_accessibility_state(obj.expanded()); |
||||
}); |
||||
} |
||||
|
||||
fn dispose(&self) { |
||||
if let Some(binding) = self.category_binding.take() { |
||||
binding.unbind(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl WidgetImpl for CategoryRow {} |
||||
impl BinImpl for CategoryRow {} |
||||
|
||||
impl CategoryRow { |
||||
/// Set the category represented by this row.
|
||||
fn set_category(&self, category: Option<Category>) { |
||||
if *self.category.borrow() == category { |
||||
return; |
||||
} |
||||
|
||||
if let Some(binding) = self.category_binding.take() { |
||||
binding.unbind(); |
||||
} |
||||
let obj = self.obj(); |
||||
|
||||
if let Some(category) = &category { |
||||
let category_binding = category |
||||
.bind_property("is-expanded", &*obj, "expanded") |
||||
.sync_create() |
||||
.build(); |
||||
self.category_binding.replace(Some(category_binding)); |
||||
} |
||||
|
||||
self.category.replace(category); |
||||
|
||||
obj.notify_category(); |
||||
obj.notify_label(); |
||||
} |
||||
|
||||
/// The label to show for this row.
|
||||
fn label(&self) -> Option<String> { |
||||
let to_type = self.category.borrow().as_ref()?.category_type(); |
||||
let from_type = self.show_label_for_category.get(); |
||||
|
||||
let label = match from_type { |
||||
CategoryType::Invited => match to_type { |
||||
// Translators: This is an action to join a room and put it in the "Favorites"
|
||||
// section.
|
||||
CategoryType::Favorite => gettext("Join Room as Favorite"), |
||||
CategoryType::Normal => gettext("Join Room"), |
||||
// Translators: This is an action to join a room and put it in the "Low
|
||||
// Priority" section.
|
||||
CategoryType::LowPriority => gettext("Join Room as Low Priority"), |
||||
CategoryType::Left => gettext("Reject Invite"), |
||||
_ => to_type.to_string(), |
||||
}, |
||||
CategoryType::Favorite => match to_type { |
||||
CategoryType::Normal => gettext("Move to Rooms"), |
||||
CategoryType::LowPriority => gettext("Move to Low Priority"), |
||||
CategoryType::Left => gettext("Leave Room"), |
||||
_ => to_type.to_string(), |
||||
}, |
||||
CategoryType::Normal => match to_type { |
||||
CategoryType::Favorite => gettext("Move to Favorites"), |
||||
CategoryType::LowPriority => gettext("Move to Low Priority"), |
||||
CategoryType::Left => gettext("Leave Room"), |
||||
_ => to_type.to_string(), |
||||
}, |
||||
CategoryType::LowPriority => match to_type { |
||||
CategoryType::Favorite => gettext("Move to Favorites"), |
||||
CategoryType::Normal => gettext("Move to Rooms"), |
||||
CategoryType::Left => gettext("Leave Room"), |
||||
_ => to_type.to_string(), |
||||
}, |
||||
CategoryType::Left => match to_type { |
||||
// Translators: This is an action to rejoin a room and put it in the "Favorites"
|
||||
// section.
|
||||
CategoryType::Favorite => gettext("Rejoin Room as Favorite"), |
||||
CategoryType::Normal => gettext("Rejoin Room"), |
||||
// Translators: This is an action to rejoin a room and put it in the "Low
|
||||
// Priority" section.
|
||||
CategoryType::LowPriority => gettext("Rejoin Room as Low Priority"), |
||||
_ => to_type.to_string(), |
||||
}, |
||||
_ => to_type.to_string(), |
||||
}; |
||||
|
||||
Some(label) |
||||
} |
||||
|
||||
/// Set the expanded state of this row.
|
||||
fn set_expanded(&self, expanded: bool) { |
||||
if self.expanded.get() == expanded { |
||||
return; |
||||
} |
||||
let obj = self.obj(); |
||||
|
||||
if expanded { |
||||
obj.set_state_flags(gtk::StateFlags::CHECKED, false); |
||||
} else { |
||||
obj.unset_state_flags(gtk::StateFlags::CHECKED); |
||||
} |
||||
|
||||
self.expanded.set(expanded); |
||||
obj.set_expanded_accessibility_state(expanded); |
||||
obj.notify_expanded(); |
||||
} |
||||
|
||||
/// Set the `CategoryType` to show a label for.
|
||||
fn set_show_label_for_category(&self, category: CategoryType) { |
||||
if category == self.show_label_for_category.get() { |
||||
return; |
||||
} |
||||
|
||||
self.show_label_for_category.set(category); |
||||
|
||||
let obj = self.obj(); |
||||
obj.notify_show_label_for_category(); |
||||
obj.notify_label(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
glib::wrapper! { |
||||
/// A sidebar row representing a category.
|
||||
pub struct CategoryRow(ObjectSubclass<imp::CategoryRow>) |
||||
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible; |
||||
} |
||||
|
||||
impl CategoryRow { |
||||
pub fn new() -> Self { |
||||
glib::Object::new() |
||||
} |
||||
|
||||
/// Set the expanded state of this row for a11y.
|
||||
fn set_expanded_accessibility_state(&self, expanded: bool) { |
||||
if let Some(row) = self.parent() { |
||||
row.update_state(&[gtk::accessible::State::Expanded(Some(expanded))]); |
||||
} |
||||
} |
||||
|
||||
/// The descendant that labels this row for a11y.
|
||||
pub fn labelled_by(&self) -> >k::Accessible { |
||||
self.imp().display_name.upcast_ref() |
||||
} |
||||
} |
||||
@ -0,0 +1,213 @@
|
||||
use adw::subclass::prelude::BinImpl; |
||||
use gettextrs::gettext; |
||||
use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate}; |
||||
|
||||
use crate::session::model::{RoomCategory, SidebarSection, SidebarSectionName}; |
||||
|
||||
mod imp { |
||||
use std::{ |
||||
cell::{Cell, RefCell}, |
||||
marker::PhantomData, |
||||
}; |
||||
|
||||
use glib::subclass::InitializingObject; |
||||
|
||||
use super::*; |
||||
|
||||
#[derive(Debug, Default, CompositeTemplate, glib::Properties)] |
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/sidebar/section_row.ui")] |
||||
#[properties(wrapper_type = super::SidebarSectionRow)] |
||||
pub struct SidebarSectionRow { |
||||
/// The section of this row.
|
||||
#[property(get, set = Self::set_section, explicit_notify, nullable)] |
||||
section: RefCell<Option<SidebarSection>>, |
||||
section_binding: RefCell<Option<glib::Binding>>, |
||||
/// Whether this row is expanded.
|
||||
#[property(get, set = Self::set_is_expanded, explicit_notify, construct, default = true)] |
||||
is_expanded: Cell<bool>, |
||||
/// The label to show for this row.
|
||||
#[property(get = Self::label)] |
||||
label: PhantomData<Option<String>>, |
||||
/// The room category to show a label for during a drag-and-drop
|
||||
/// operation.
|
||||
///
|
||||
/// This will change the label according to the action that can be
|
||||
/// performed when dropping a room with the given category.
|
||||
show_label_for_room_category: Cell<Option<RoomCategory>>, |
||||
/// The label showing the category name.
|
||||
#[template_child] |
||||
pub(super) display_name: TemplateChild<gtk::Label>, |
||||
} |
||||
|
||||
#[glib::object_subclass] |
||||
impl ObjectSubclass for SidebarSectionRow { |
||||
const NAME: &'static str = "SidebarSectionRow"; |
||||
type Type = super::SidebarSectionRow; |
||||
type ParentType = adw::Bin; |
||||
|
||||
fn class_init(klass: &mut Self::Class) { |
||||
Self::bind_template(klass); |
||||
klass.set_css_name("sidebar-section"); |
||||
} |
||||
|
||||
fn instance_init(obj: &InitializingObject<Self>) { |
||||
obj.init_template(); |
||||
} |
||||
} |
||||
|
||||
#[glib::derived_properties] |
||||
impl ObjectImpl for SidebarSectionRow { |
||||
fn constructed(&self) { |
||||
self.parent_constructed(); |
||||
|
||||
self.obj().connect_parent_notify(|obj| { |
||||
obj.set_expanded_accessibility_state(obj.is_expanded()); |
||||
}); |
||||
} |
||||
|
||||
fn dispose(&self) { |
||||
if let Some(binding) = self.section_binding.take() { |
||||
binding.unbind(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
impl WidgetImpl for SidebarSectionRow {} |
||||
impl BinImpl for SidebarSectionRow {} |
||||
|
||||
impl SidebarSectionRow { |
||||
/// Set the section represented by this row.
|
||||
fn set_section(&self, section: Option<SidebarSection>) { |
||||
if *self.section.borrow() == section { |
||||
return; |
||||
} |
||||
|
||||
if let Some(binding) = self.section_binding.take() { |
||||
binding.unbind(); |
||||
} |
||||
let obj = self.obj(); |
||||
|
||||
if let Some(section) = §ion { |
||||
let section_binding = section |
||||
.bind_property("is-expanded", &*obj, "is-expanded") |
||||
.sync_create() |
||||
.build(); |
||||
self.section_binding.replace(Some(section_binding)); |
||||
} |
||||
|
||||
self.section.replace(section); |
||||
|
||||
obj.notify_section(); |
||||
obj.notify_label(); |
||||
} |
||||
|
||||
/// The label to show for this row.
|
||||
fn label(&self) -> Option<String> { |
||||
let target_section_name = self.section.borrow().as_ref()?.name(); |
||||
let source_room_category = self.show_label_for_room_category.get(); |
||||
|
||||
let label = match source_room_category { |
||||
Some(RoomCategory::Invited) => match target_section_name { |
||||
// Translators: This is an action to join a room and put it in the "Favorites"
|
||||
// section.
|
||||
SidebarSectionName::Favorite => gettext("Join Room as Favorite"), |
||||
SidebarSectionName::Normal => gettext("Join Room"), |
||||
// Translators: This is an action to join a room and put it in the "Low
|
||||
// Priority" section.
|
||||
SidebarSectionName::LowPriority => gettext("Join Room as Low Priority"), |
||||
SidebarSectionName::Left => gettext("Reject Invite"), |
||||
_ => target_section_name.to_string(), |
||||
}, |
||||
Some(RoomCategory::Favorite) => match target_section_name { |
||||
SidebarSectionName::Normal => gettext("Move to Rooms"), |
||||
SidebarSectionName::LowPriority => gettext("Move to Low Priority"), |
||||
SidebarSectionName::Left => gettext("Leave Room"), |
||||
_ => target_section_name.to_string(), |
||||
}, |
||||
Some(RoomCategory::Normal) => match target_section_name { |
||||
SidebarSectionName::Favorite => gettext("Move to Favorites"), |
||||
SidebarSectionName::LowPriority => gettext("Move to Low Priority"), |
||||
SidebarSectionName::Left => gettext("Leave Room"), |
||||
_ => target_section_name.to_string(), |
||||
}, |
||||
Some(RoomCategory::LowPriority) => match target_section_name { |
||||
SidebarSectionName::Favorite => gettext("Move to Favorites"), |
||||
SidebarSectionName::Normal => gettext("Move to Rooms"), |
||||
SidebarSectionName::Left => gettext("Leave Room"), |
||||
_ => target_section_name.to_string(), |
||||
}, |
||||
Some(RoomCategory::Left) => match target_section_name { |
||||
// Translators: This is an action to rejoin a room and put it in the "Favorites"
|
||||
// section.
|
||||
SidebarSectionName::Favorite => gettext("Rejoin Room as Favorite"), |
||||
SidebarSectionName::Normal => gettext("Rejoin Room"), |
||||
// Translators: This is an action to rejoin a room and put it in the "Low
|
||||
// Priority" section.
|
||||
SidebarSectionName::LowPriority => gettext("Rejoin Room as Low Priority"), |
||||
_ => target_section_name.to_string(), |
||||
}, |
||||
_ => target_section_name.to_string(), |
||||
}; |
||||
|
||||
Some(label) |
||||
} |
||||
|
||||
/// Set whether this row is expanded.
|
||||
fn set_is_expanded(&self, is_expanded: bool) { |
||||
if self.is_expanded.get() == is_expanded { |
||||
return; |
||||
} |
||||
let obj = self.obj(); |
||||
|
||||
if is_expanded { |
||||
obj.set_state_flags(gtk::StateFlags::CHECKED, false); |
||||
} else { |
||||
obj.unset_state_flags(gtk::StateFlags::CHECKED); |
||||
} |
||||
|
||||
self.is_expanded.set(is_expanded); |
||||
obj.set_expanded_accessibility_state(is_expanded); |
||||
obj.notify_is_expanded(); |
||||
} |
||||
|
||||
/// Set the room category to show the label for.
|
||||
pub(super) fn set_show_label_for_room_category(&self, category: Option<RoomCategory>) { |
||||
if self.show_label_for_room_category.get() == category { |
||||
return; |
||||
} |
||||
|
||||
self.show_label_for_room_category.set(category); |
||||
|
||||
self.obj().notify_label(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
glib::wrapper! { |
||||
/// A sidebar row representing a category.
|
||||
pub struct SidebarSectionRow(ObjectSubclass<imp::SidebarSectionRow>) |
||||
@extends gtk::Widget, adw::Bin, @implements gtk::Accessible; |
||||
} |
||||
|
||||
impl SidebarSectionRow { |
||||
pub fn new() -> Self { |
||||
glib::Object::new() |
||||
} |
||||
|
||||
/// Set the room category to show the label for.
|
||||
pub fn set_show_label_for_room_category(&self, category: Option<RoomCategory>) { |
||||
self.imp().set_show_label_for_room_category(category); |
||||
} |
||||
|
||||
/// Set the expanded state of this row for a11y.
|
||||
fn set_expanded_accessibility_state(&self, is_expanded: bool) { |
||||
if let Some(row) = self.parent() { |
||||
row.update_state(&[gtk::accessible::State::Expanded(Some(is_expanded))]); |
||||
} |
||||
} |
||||
|
||||
/// The descendant that labels this row for a11y.
|
||||
pub fn labelled_by(&self) -> >k::Accessible { |
||||
self.imp().display_name.upcast_ref() |
||||
} |
||||
} |
||||
Loading…
Reference in new issue