diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml index 5acbb7e1..f83e2946 100644 --- a/data/resources/resources.gresource.xml +++ b/data/resources/resources.gresource.xml @@ -17,6 +17,7 @@ ui/sidebar-room-row.ui ui/window.ui ui/context-menu-bin.ui + ui/user-pill.ui style.css icons/scalable/actions/send-symbolic.svg icons/scalable/status/welcome.svg diff --git a/data/resources/style.css b/data/resources/style.css index 584ff678..5d46ab2c 100644 --- a/data/resources/style.css +++ b/data/resources/style.css @@ -3,6 +3,12 @@ font-weight: bold; } +.user-pill { + border-radius: 9999px; + background-color: alpha(@theme_text_color, 0.1); + padding-right: 6px; +} + /* Login */ .login { min-width: 250px; diff --git a/data/resources/ui/user-pill.ui b/data/resources/ui/user-pill.ui new file mode 100644 index 00000000..aff200ae --- /dev/null +++ b/data/resources/ui/user-pill.ui @@ -0,0 +1,32 @@ + + + + diff --git a/po/POTFILES.in b/po/POTFILES.in index 1ef516a9..28385a3c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -21,12 +21,14 @@ data/resources/ui/sidebar-category-row.ui data/resources/ui/sidebar-item.ui data/resources/ui/sidebar-room-row.ui data/resources/ui/sidebar.ui +data/resources/ui/user-pill.ui data/resources/ui/window.ui # Rust files src/application.rs src/components/context_menu_bin.rs src/components/mod.rs +src/components/user_pill.rs src/login.rs src/main.rs src/secret.rs diff --git a/src/components/mod.rs b/src/components/mod.rs index 8ea2852e..05615c7f 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -1,3 +1,5 @@ mod context_menu_bin; +mod user_pill; pub use self::context_menu_bin::{ContextMenuBin, ContextMenuBinImpl}; +pub use self::user_pill::UserPill; diff --git a/src/components/user_pill.rs b/src/components/user_pill.rs new file mode 100644 index 00000000..cfe92d4e --- /dev/null +++ b/src/components/user_pill.rs @@ -0,0 +1,111 @@ +use adw::subclass::prelude::*; +use gtk::prelude::*; +use gtk::subclass::prelude::*; +use gtk::{glib, CompositeTemplate}; + +use crate::session::User; + +mod imp { + use super::*; + use glib::subclass::InitializingObject; + use std::cell::RefCell; + + #[derive(Debug, Default, CompositeTemplate)] + #[template(resource = "/org/gnome/FractalNext/user-pill.ui")] + pub struct UserPill { + /// The user displayed by this widget + pub user: RefCell>, + #[template_child] + pub display_name: TemplateChild, + #[template_child] + pub avatar: TemplateChild, + } + + #[glib::object_subclass] + impl ObjectSubclass for UserPill { + const NAME: &'static str = "UserPill"; + type Type = super::UserPill; + type ParentType = adw::Bin; + + fn class_init(klass: &mut Self::Class) { + Self::bind_template(klass); + } + + fn instance_init(obj: &InitializingObject) { + obj.init_template(); + } + } + + impl ObjectImpl for UserPill { + fn properties() -> &'static [glib::ParamSpec] { + use once_cell::sync::Lazy; + static PROPERTIES: Lazy> = Lazy::new(|| { + vec![glib::ParamSpec::new_object( + "user", + "User", + "The user displayed by this widget", + User::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() { + "user" => { + let user = value.get().unwrap(); + obj.set_user(user); + } + _ => unimplemented!(), + } + } + + fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value { + match pspec.name() { + "user" => obj.user().to_value(), + _ => unimplemented!(), + } + } + } + + impl WidgetImpl for UserPill {} + + impl BinImpl for UserPill {} +} + +glib::wrapper! { + pub struct UserPill(ObjectSubclass) + @extends gtk::Widget, adw::Bin, @implements gtk::Accessible; +} + +/// A widget displaying a `User` +impl UserPill { + pub fn new() -> Self { + glib::Object::new(&[]).expect("Failed to create UserPill") + } + + pub fn set_user(&self, user: Option) { + let priv_ = imp::UserPill::from_instance(self); + + if *priv_.user.borrow() == user { + return; + } + + priv_.user.replace(user); + + self.notify("user"); + } + + pub fn user(&self) -> Option { + let priv_ = imp::UserPill::from_instance(self); + priv_.user.borrow().clone() + } +} diff --git a/src/meson.build b/src/meson.build index fa656726..d91b6343 100644 --- a/src/meson.build +++ b/src/meson.build @@ -22,6 +22,7 @@ sources = files( 'application.rs', 'components/context_menu_bin.rs', 'components/mod.rs', + 'components/user_pill.rs', 'config.rs', 'main.rs', 'window.rs', diff --git a/src/session/mod.rs b/src/session/mod.rs index c6b6147c..fd4038e9 100644 --- a/src/session/mod.rs +++ b/src/session/mod.rs @@ -8,7 +8,7 @@ use self::categories::Categories; use self::content::Content; use self::room::Room; use self::sidebar::Sidebar; -use self::user::User; +pub use self::user::User; use crate::event_from_sync_event; use crate::secret;