Merge branch 'session-view-properties' into 'main'
session-view: Port more modules to glib::Properties macro See merge request GNOME/fractal!1499
This commit is contained in:
commit
51d9978dc5
|
@ -8,12 +8,13 @@ use crate::{
|
|||
};
|
||||
|
||||
mod imp {
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug, Default, glib::Properties)]
|
||||
#[properties(wrapper_type = super::DmUser)]
|
||||
pub struct DmUser {
|
||||
/// The direct chat with this user, if any.
|
||||
#[property(get, set = Self::set_direct_chat, explicit_notify, nullable)]
|
||||
pub direct_chat: glib::WeakRef<Room>,
|
||||
}
|
||||
|
||||
|
@ -24,36 +25,30 @@ mod imp {
|
|||
type ParentType = User;
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for DmUser {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![glib::ParamSpecObject::builder::<Room>("direct-chat")
|
||||
.read_only()
|
||||
.build()]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
let obj = self.obj();
|
||||
|
||||
match pspec.name() {
|
||||
"direct-chat" => obj.direct_chat().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
let obj = self.obj();
|
||||
|
||||
spawn!(clone!(@weak obj => async move {
|
||||
let direct_chat = obj.upcast_ref::<User>().direct_chat().await;
|
||||
obj.set_direct_chat(direct_chat.as_ref());
|
||||
obj.set_direct_chat(direct_chat);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
impl DmUser {
|
||||
/// Set the direct chat with this user.
|
||||
fn set_direct_chat(&self, direct_chat: Option<Room>) {
|
||||
if self.direct_chat.upgrade() == direct_chat {
|
||||
return;
|
||||
}
|
||||
|
||||
self.direct_chat.set(direct_chat.as_ref());
|
||||
self.obj().notify_direct_chat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
|
@ -77,19 +72,4 @@ impl DmUser {
|
|||
obj.set_avatar_url(avatar_url.map(std::borrow::ToOwned::to_owned));
|
||||
obj
|
||||
}
|
||||
|
||||
/// Get the direct chat with this user, if any.
|
||||
pub fn direct_chat(&self) -> Option<Room> {
|
||||
self.imp().direct_chat.upgrade()
|
||||
}
|
||||
|
||||
/// Set the direct chat with this user.
|
||||
fn set_direct_chat(&self, direct_chat: Option<&Room>) {
|
||||
if self.direct_chat().as_ref() == direct_chat {
|
||||
return;
|
||||
}
|
||||
|
||||
self.imp().direct_chat.set(direct_chat);
|
||||
self.notify("direct-chat");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,21 @@ mod imp {
|
|||
use std::cell::{Cell, RefCell};
|
||||
|
||||
use futures_util::future::AbortHandle;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug, Default, glib::Properties)]
|
||||
#[properties(wrapper_type = super::DmUserList)]
|
||||
pub struct DmUserList {
|
||||
pub list: RefCell<Vec<DmUser>>,
|
||||
/// The current session.
|
||||
#[property(get, construct_only)]
|
||||
pub session: glib::WeakRef<Session>,
|
||||
/// The state of the list.
|
||||
#[property(get, builder(DmUserListState::default()))]
|
||||
pub state: Cell<DmUserListState>,
|
||||
/// The search term.
|
||||
#[property(get, set = Self::set_search_term, explicit_notify, nullable)]
|
||||
pub search_term: RefCell<Option<String>>,
|
||||
pub abort_handle: RefCell<Option<AbortHandle>>,
|
||||
}
|
||||
|
@ -41,52 +47,18 @@ mod imp {
|
|||
type Interfaces = (gio::ListModel,);
|
||||
}
|
||||
|
||||
impl ObjectImpl for DmUserList {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![
|
||||
glib::ParamSpecObject::builder::<Session>("session")
|
||||
.construct_only()
|
||||
.build(),
|
||||
glib::ParamSpecString::builder("search-term")
|
||||
.explicit_notify()
|
||||
.build(),
|
||||
glib::ParamSpecEnum::builder::<DmUserListState>("state")
|
||||
.read_only()
|
||||
.build(),
|
||||
]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
match pspec.name() {
|
||||
"session" => self.session.set(value.get().unwrap()),
|
||||
"search-term" => self.obj().set_search_term(value.get().unwrap()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
let obj = self.obj();
|
||||
|
||||
match pspec.name() {
|
||||
"session" => obj.session().to_value(),
|
||||
"search-term" => obj.search_term().to_value(),
|
||||
"state" => obj.state().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for DmUserList {}
|
||||
|
||||
impl ListModelImpl for DmUserList {
|
||||
fn item_type(&self) -> glib::Type {
|
||||
DmUser::static_type()
|
||||
}
|
||||
|
||||
fn n_items(&self) -> u32 {
|
||||
self.list.borrow().len() as u32
|
||||
}
|
||||
|
||||
fn item(&self, position: u32) -> Option<glib::Object> {
|
||||
self.list
|
||||
.borrow()
|
||||
|
@ -95,6 +67,26 @@ mod imp {
|
|||
.and_upcast()
|
||||
}
|
||||
}
|
||||
|
||||
impl DmUserList {
|
||||
/// Set the search term.
|
||||
fn set_search_term(&self, search_term: Option<String>) {
|
||||
let search_term = search_term.filter(|s| !s.is_empty());
|
||||
|
||||
if search_term.as_ref() == self.search_term.borrow().as_ref() {
|
||||
return;
|
||||
}
|
||||
let obj = self.obj();
|
||||
|
||||
self.search_term.replace(search_term);
|
||||
|
||||
spawn!(clone!(@weak obj => async move {
|
||||
obj.search_users().await;
|
||||
}));
|
||||
|
||||
obj.notify_search_term();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
|
@ -108,34 +100,6 @@ impl DmUserList {
|
|||
glib::Object::builder().property("session", session).build()
|
||||
}
|
||||
|
||||
/// The session this list refers to.
|
||||
pub fn session(&self) -> Session {
|
||||
self.imp().session.upgrade().unwrap()
|
||||
}
|
||||
|
||||
/// Set the search term.
|
||||
pub fn set_search_term(&self, search_term: Option<String>) {
|
||||
let imp = self.imp();
|
||||
let search_term = search_term.filter(|s| !s.is_empty());
|
||||
|
||||
if search_term.as_ref() == imp.search_term.borrow().as_ref() {
|
||||
return;
|
||||
}
|
||||
|
||||
imp.search_term.replace(search_term);
|
||||
|
||||
spawn!(clone!(@weak self as obj => async move {
|
||||
obj.search_users().await;
|
||||
}));
|
||||
|
||||
self.notify("search_term");
|
||||
}
|
||||
|
||||
/// The search term.
|
||||
fn search_term(&self) -> Option<String> {
|
||||
self.imp().search_term.borrow().clone()
|
||||
}
|
||||
|
||||
/// Set the state of the list.
|
||||
fn set_state(&self, state: DmUserListState) {
|
||||
let imp = self.imp();
|
||||
|
@ -148,11 +112,6 @@ impl DmUserList {
|
|||
self.notify("state");
|
||||
}
|
||||
|
||||
/// The state of the list.
|
||||
pub fn state(&self) -> DmUserListState {
|
||||
self.imp().state.get()
|
||||
}
|
||||
|
||||
fn set_list(&self, users: Vec<DmUser>) {
|
||||
let added = users.len();
|
||||
|
||||
|
@ -166,7 +125,9 @@ impl DmUserList {
|
|||
}
|
||||
|
||||
async fn search_users(&self) {
|
||||
let session = self.session();
|
||||
let Some(session) = self.session() else {
|
||||
return;
|
||||
};
|
||||
let client = session.client();
|
||||
let Some(search_term) = self.search_term() else {
|
||||
self.set_state(DmUserListState::Initial);
|
||||
|
|
|
@ -6,13 +6,15 @@ mod imp {
|
|||
use std::cell::RefCell;
|
||||
|
||||
use glib::subclass::InitializingObject;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
|
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/create_dm_dialog/dm_user_row.ui")]
|
||||
#[properties(wrapper_type = super::DmUserRow)]
|
||||
pub struct DmUserRow {
|
||||
/// The user displayed by this row.
|
||||
#[property(get, set = Self::set_user, explicit_notify)]
|
||||
pub user: RefCell<Option<DmUser>>,
|
||||
}
|
||||
|
||||
|
@ -31,36 +33,27 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for DmUserRow {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![glib::ParamSpecObject::builder::<DmUser>("user")
|
||||
.explicit_notify()
|
||||
.build()]
|
||||
});
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for DmUserRow {}
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
match pspec.name() {
|
||||
"user" => self.obj().set_user(value.get().unwrap()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
match pspec.name() {
|
||||
"user" => self.obj().user().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl WidgetImpl for DmUserRow {}
|
||||
impl ListBoxRowImpl for DmUserRow {}
|
||||
|
||||
impl DmUserRow {
|
||||
/// Set the user displayed by this row.
|
||||
fn set_user(&self, user: Option<DmUser>) {
|
||||
if self.user.borrow().clone() == user {
|
||||
return;
|
||||
}
|
||||
|
||||
self.user.replace(user);
|
||||
self.obj().notify_user();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
/// A row of the DM user list.
|
||||
pub struct DmUserRow(ObjectSubclass<imp::DmUserRow>)
|
||||
@extends gtk::Widget, gtk::ListBoxRow, @implements gtk::Accessible;
|
||||
}
|
||||
|
@ -69,22 +62,4 @@ impl DmUserRow {
|
|||
pub fn new(user: &DmUser) -> Self {
|
||||
glib::Object::builder().property("user", user).build()
|
||||
}
|
||||
|
||||
/// The user displayed by this row.
|
||||
pub fn user(&self) -> Option<DmUser> {
|
||||
self.imp().user.borrow().clone()
|
||||
}
|
||||
|
||||
/// Set the user displayed by this row.
|
||||
pub fn set_user(&self, user: Option<DmUser>) {
|
||||
let imp = self.imp();
|
||||
let prev_user = self.user();
|
||||
|
||||
if prev_user == user {
|
||||
return;
|
||||
}
|
||||
|
||||
imp.user.replace(user);
|
||||
self.notify("user");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,14 +17,17 @@ use crate::{
|
|||
};
|
||||
|
||||
mod imp {
|
||||
use glib::{object::WeakRef, subclass::InitializingObject};
|
||||
use glib::subclass::InitializingObject;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
|
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/create_dm_dialog/mod.ui")]
|
||||
#[properties(wrapper_type = super::CreateDmDialog)]
|
||||
pub struct CreateDmDialog {
|
||||
pub session: WeakRef<Session>,
|
||||
/// The current session.
|
||||
#[property(get, set = Self::set_session, explicit_notify)]
|
||||
pub session: glib::WeakRef<Session>,
|
||||
#[template_child]
|
||||
pub list_box: TemplateChild<gtk::ListBox>,
|
||||
#[template_child]
|
||||
|
@ -59,40 +62,56 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for CreateDmDialog {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
use once_cell::sync::Lazy;
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![glib::ParamSpecObject::builder::<Session>("session")
|
||||
.explicit_notify()
|
||||
.build()]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
match pspec.name() {
|
||||
"session" => self.obj().set_session(value.get().unwrap()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
match pspec.name() {
|
||||
"session" => self.obj().session().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for CreateDmDialog {}
|
||||
|
||||
impl WidgetImpl for CreateDmDialog {}
|
||||
impl WindowImpl for CreateDmDialog {}
|
||||
impl AdwWindowImpl for CreateDmDialog {}
|
||||
|
||||
impl CreateDmDialog {
|
||||
/// Set the current session.
|
||||
pub fn set_session(&self, session: Option<Session>) {
|
||||
if self.session.upgrade() == session {
|
||||
return;
|
||||
}
|
||||
let obj = self.obj();
|
||||
|
||||
if let Some(session) = &session {
|
||||
let user_list = DmUserList::new(session);
|
||||
|
||||
// We don't need to disconnect this signal since the `DmUserList` will be
|
||||
// disposed once unbound from the `gtk::ListBox`
|
||||
user_list.connect_state_notify(clone!(@weak obj => move |model| {
|
||||
obj.update_view(model);
|
||||
}));
|
||||
|
||||
self.search_entry
|
||||
.bind_property("text", &user_list, "search-term")
|
||||
.sync_create()
|
||||
.build();
|
||||
|
||||
self.list_box.bind_model(Some(&user_list), |user| {
|
||||
DmUserRow::new(
|
||||
user.downcast_ref::<DmUser>()
|
||||
.expect("DmUserList must contain only `DmUser`"),
|
||||
)
|
||||
.upcast()
|
||||
});
|
||||
|
||||
obj.update_view(&user_list);
|
||||
} else {
|
||||
self.list_box.unbind_model();
|
||||
}
|
||||
|
||||
self.session.set(session.as_ref());
|
||||
obj.notify_session();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
/// Preference Window to display and update room details.
|
||||
/// Dialog to create a new direct chat.
|
||||
pub struct CreateDmDialog(ObjectSubclass<imp::CreateDmDialog>)
|
||||
@extends gtk::Widget, gtk::Window, adw::Window, adw::Bin, @implements gtk::Accessible;
|
||||
}
|
||||
|
@ -106,53 +125,6 @@ impl CreateDmDialog {
|
|||
.build()
|
||||
}
|
||||
|
||||
/// The current session.
|
||||
pub fn session(&self) -> Option<Session> {
|
||||
self.imp().session.upgrade()
|
||||
}
|
||||
|
||||
/// Set the current session.
|
||||
pub fn set_session(&self, session: Option<Session>) {
|
||||
let imp = self.imp();
|
||||
|
||||
if self.session() == session {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(ref session) = session {
|
||||
let user_list = DmUserList::new(session);
|
||||
|
||||
// We don't need to disconnect this signal since the `DmUserList` will be
|
||||
// disposed once unbound from the `gtk::ListBox`
|
||||
user_list.connect_notify_local(
|
||||
Some("state"),
|
||||
clone!(@weak self as obj => move |model, _| {
|
||||
obj.update_view(model);
|
||||
}),
|
||||
);
|
||||
|
||||
imp.search_entry
|
||||
.bind_property("text", &user_list, "search-term")
|
||||
.sync_create()
|
||||
.build();
|
||||
|
||||
imp.list_box.bind_model(Some(&user_list), |user| {
|
||||
DmUserRow::new(
|
||||
user.downcast_ref::<DmUser>()
|
||||
.expect("DmUserList must contain only `DmUser`"),
|
||||
)
|
||||
.upcast()
|
||||
});
|
||||
|
||||
self.update_view(&user_list);
|
||||
} else {
|
||||
imp.list_box.unbind_model();
|
||||
}
|
||||
|
||||
imp.session.set(session.as_ref());
|
||||
self.notify("session");
|
||||
}
|
||||
|
||||
fn update_view(&self, model: &DmUserList) {
|
||||
let visible_child_name = match model.state() {
|
||||
DmUserListState::Initial => "no-search-page",
|
||||
|
|
|
@ -5,15 +5,19 @@ use sourceview::prelude::*;
|
|||
use crate::session::model::Event;
|
||||
|
||||
mod imp {
|
||||
use std::cell::RefCell;
|
||||
|
||||
use glib::subclass::InitializingObject;
|
||||
use once_cell::unsync::OnceCell;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
|
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/event_source_dialog.ui")]
|
||||
#[properties(wrapper_type = super::EventSourceDialog)]
|
||||
pub struct EventSourceDialog {
|
||||
pub event: OnceCell<Event>,
|
||||
/// The event that is displayed in the dialog.
|
||||
#[property(get, construct_only)]
|
||||
pub event: RefCell<Option<Event>>,
|
||||
#[template_child]
|
||||
pub source_view: TemplateChild<sourceview::View>,
|
||||
}
|
||||
|
@ -43,34 +47,8 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for EventSourceDialog {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
use once_cell::sync::Lazy;
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![glib::ParamSpecObject::builder::<Event>("event")
|
||||
.construct_only()
|
||||
.build()]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
match pspec.name() {
|
||||
"event" => {
|
||||
let _ = self.event.set(value.get().unwrap());
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
match pspec.name() {
|
||||
"event" => self.obj().event().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn constructed(&self) {
|
||||
let buffer = self
|
||||
.source_view
|
||||
|
@ -104,11 +82,6 @@ impl EventSourceDialog {
|
|||
.build()
|
||||
}
|
||||
|
||||
/// The event that is displayed in the dialog.
|
||||
pub fn event(&self) -> Option<&Event> {
|
||||
self.imp().event.get()
|
||||
}
|
||||
|
||||
pub fn copy_to_clipboard(&self) {
|
||||
let clipboard = self.clipboard();
|
||||
let buffer = self.imp().source_view.buffer();
|
||||
|
|
|
@ -9,14 +9,17 @@ use ruma::{
|
|||
use crate::{session::model::Session, spawn, toast, Window};
|
||||
|
||||
mod imp {
|
||||
use glib::{object::WeakRef, subclass::InitializingObject};
|
||||
use glib::subclass::InitializingObject;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
|
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/join_room_dialog.ui")]
|
||||
#[properties(wrapper_type = super::JoinRoomDialog)]
|
||||
pub struct JoinRoomDialog {
|
||||
pub session: WeakRef<Session>,
|
||||
/// The current session.
|
||||
#[property(get, set = Self::set_session, explicit_notify)]
|
||||
pub session: glib::WeakRef<Session>,
|
||||
#[template_child]
|
||||
pub entry: TemplateChild<gtk::Entry>,
|
||||
}
|
||||
|
@ -44,32 +47,8 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for JoinRoomDialog {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
use once_cell::sync::Lazy;
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![glib::ParamSpecObject::builder::<Session>("session")
|
||||
.explicit_notify()
|
||||
.build()]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
match pspec.name() {
|
||||
"session" => self.obj().set_session(value.get().unwrap()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
match pspec.name() {
|
||||
"session" => self.obj().session().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for JoinRoomDialog {}
|
||||
|
||||
impl WidgetImpl for JoinRoomDialog {}
|
||||
impl WindowImpl for JoinRoomDialog {}
|
||||
|
@ -83,6 +62,18 @@ mod imp {
|
|||
self.parent_response(response)
|
||||
}
|
||||
}
|
||||
|
||||
impl JoinRoomDialog {
|
||||
/// Set the current session.
|
||||
fn set_session(&self, session: Option<Session>) {
|
||||
if self.session.upgrade() == session {
|
||||
return;
|
||||
}
|
||||
|
||||
self.session.set(session.as_ref());
|
||||
self.obj().notify_session();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
|
@ -100,23 +91,6 @@ impl JoinRoomDialog {
|
|||
.build()
|
||||
}
|
||||
|
||||
/// The current session.
|
||||
pub fn session(&self) -> Option<Session> {
|
||||
self.imp().session.upgrade()
|
||||
}
|
||||
|
||||
/// Set the current session.
|
||||
pub fn set_session(&self, session: Option<&Session>) {
|
||||
let imp = self.imp();
|
||||
|
||||
if self.session().as_ref() == session {
|
||||
return;
|
||||
}
|
||||
|
||||
imp.session.set(session);
|
||||
self.notify("session");
|
||||
}
|
||||
|
||||
/// Handle when the entry text changed.
|
||||
#[template_callback]
|
||||
fn entry_changed(&self, entry: >k::Entry) {
|
||||
|
|
|
@ -19,25 +19,31 @@ const CANCEL_SWIPE_ANIMATION_DURATION: u32 = 400;
|
|||
|
||||
mod imp {
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
cell::{Cell, OnceCell, RefCell},
|
||||
collections::HashMap,
|
||||
};
|
||||
|
||||
use glib::{object::WeakRef, subclass::InitializingObject};
|
||||
use once_cell::{sync::Lazy, unsync::OnceCell};
|
||||
use glib::subclass::InitializingObject;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
|
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/media_viewer.ui")]
|
||||
#[properties(wrapper_type = super::MediaViewer)]
|
||||
pub struct MediaViewer {
|
||||
/// Whether the viewer is fullscreened.
|
||||
#[property(get, set = Self::set_fullscreened, explicit_notify)]
|
||||
pub fullscreened: Cell<bool>,
|
||||
/// The room containing the media message.
|
||||
pub room: WeakRef<Room>,
|
||||
#[property(get)]
|
||||
pub room: glib::WeakRef<Room>,
|
||||
/// The ID of the event containing the media message.
|
||||
#[property(get = Self::event_id, type = Option<String>)]
|
||||
pub event_id: RefCell<Option<OwnedEventId>>,
|
||||
/// The media message to display.
|
||||
pub message: RefCell<Option<MessageType>>,
|
||||
/// The body of the media event.
|
||||
#[property(get)]
|
||||
pub body: RefCell<Option<String>>,
|
||||
pub animation: OnceCell<adw::TimedAnimation>,
|
||||
pub swipe_tracker: OnceCell<adw::SwipeTracker>,
|
||||
|
@ -113,47 +119,8 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for MediaViewer {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![
|
||||
glib::ParamSpecBoolean::builder("fullscreened")
|
||||
.explicit_notify()
|
||||
.build(),
|
||||
glib::ParamSpecObject::builder::<Room>("room")
|
||||
.read_only()
|
||||
.build(),
|
||||
glib::ParamSpecString::builder("event-id")
|
||||
.read_only()
|
||||
.build(),
|
||||
glib::ParamSpecString::builder("body").read_only().build(),
|
||||
]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
let obj = self.obj();
|
||||
|
||||
match pspec.name() {
|
||||
"fullscreened" => obj.set_fullscreened(value.get().unwrap()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
let obj = self.obj();
|
||||
|
||||
match pspec.name() {
|
||||
"fullscreened" => obj.fullscreened().to_value(),
|
||||
"room" => obj.room().to_value(),
|
||||
"event-id" => obj.event_id().as_ref().map(|e| e.as_str()).to_value(),
|
||||
"body" => obj.body().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
|
||||
|
@ -277,9 +244,38 @@ mod imp {
|
|||
gdk::Rectangle::new(0, 0, self.obj().width(), self.obj().height())
|
||||
}
|
||||
}
|
||||
|
||||
impl MediaViewer {
|
||||
/// Set whether the viewer is fullscreened.
|
||||
fn set_fullscreened(&self, fullscreened: bool) {
|
||||
if fullscreened == self.fullscreened.get() {
|
||||
return;
|
||||
}
|
||||
|
||||
self.fullscreened.set(fullscreened);
|
||||
|
||||
if fullscreened {
|
||||
// Upscale the media on fullscreen
|
||||
self.media.set_halign(gtk::Align::Fill);
|
||||
self.toolbar_view
|
||||
.set_top_bar_style(adw::ToolbarStyle::Raised);
|
||||
} else {
|
||||
self.media.set_halign(gtk::Align::Center);
|
||||
self.toolbar_view.set_top_bar_style(adw::ToolbarStyle::Flat);
|
||||
}
|
||||
|
||||
self.obj().notify_fullscreened();
|
||||
}
|
||||
|
||||
/// The ID of the event containing the media message.
|
||||
fn event_id(&self) -> Option<String> {
|
||||
self.event_id.borrow().as_ref().map(ToString::to_string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
/// A widget allowing to view a media file.
|
||||
pub struct MediaViewer(ObjectSubclass<imp::MediaViewer>)
|
||||
@extends gtk::Widget, @implements gtk::Accessible, adw::Swipeable;
|
||||
}
|
||||
|
@ -308,16 +304,6 @@ impl MediaViewer {
|
|||
animation.play();
|
||||
}
|
||||
|
||||
/// The room containing the media message.
|
||||
pub fn room(&self) -> Option<Room> {
|
||||
self.imp().room.upgrade()
|
||||
}
|
||||
|
||||
/// The ID of the event containing the media message.
|
||||
pub fn event_id(&self) -> Option<OwnedEventId> {
|
||||
self.imp().event_id.borrow().clone()
|
||||
}
|
||||
|
||||
/// The media message to display.
|
||||
pub fn message(&self) -> Option<MessageType> {
|
||||
self.imp().message.borrow().clone()
|
||||
|
@ -333,13 +319,8 @@ impl MediaViewer {
|
|||
|
||||
self.update_menu_actions();
|
||||
self.build();
|
||||
self.notify("room");
|
||||
self.notify("event-id");
|
||||
}
|
||||
|
||||
/// The body of the media event.
|
||||
pub fn body(&self) -> Option<String> {
|
||||
self.imp().body.borrow().clone()
|
||||
self.notify_room();
|
||||
self.notify_event_id();
|
||||
}
|
||||
|
||||
/// Set the body of the media event.
|
||||
|
@ -349,35 +330,7 @@ impl MediaViewer {
|
|||
}
|
||||
|
||||
self.imp().body.replace(body);
|
||||
self.notify("body");
|
||||
}
|
||||
|
||||
/// Whether the viewer is fullscreened.
|
||||
pub fn fullscreened(&self) -> bool {
|
||||
self.imp().fullscreened.get()
|
||||
}
|
||||
|
||||
/// Set whether the viewer is fullscreened.
|
||||
pub fn set_fullscreened(&self, fullscreened: bool) {
|
||||
let imp = self.imp();
|
||||
|
||||
if fullscreened == self.fullscreened() {
|
||||
return;
|
||||
}
|
||||
|
||||
imp.fullscreened.set(fullscreened);
|
||||
|
||||
if fullscreened {
|
||||
// Upscale the media on fullscreen
|
||||
imp.media.set_halign(gtk::Align::Fill);
|
||||
imp.toolbar_view
|
||||
.set_top_bar_style(adw::ToolbarStyle::Raised);
|
||||
} else {
|
||||
imp.media.set_halign(gtk::Align::Center);
|
||||
imp.toolbar_view.set_top_bar_style(adw::ToolbarStyle::Flat);
|
||||
}
|
||||
|
||||
self.notify("fullscreened");
|
||||
self.notify_body();
|
||||
}
|
||||
|
||||
/// Update the actions of the menu according to the current message.
|
||||
|
@ -566,7 +519,7 @@ impl MediaViewer {
|
|||
let Some(room) = self.room() else {
|
||||
return;
|
||||
};
|
||||
let Some(event_id) = self.event_id() else {
|
||||
let Some(event_id) = self.imp().event_id.borrow().clone() else {
|
||||
return;
|
||||
};
|
||||
let matrix_room = room.matrix_room();
|
||||
|
|
|
@ -25,14 +25,17 @@ use crate::{
|
|||
const MAX_BYTES: usize = 255;
|
||||
|
||||
mod imp {
|
||||
use glib::{object::WeakRef, subclass::InitializingObject};
|
||||
use glib::subclass::InitializingObject;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
|
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/room_creation.ui")]
|
||||
#[properties(wrapper_type = super::RoomCreation)]
|
||||
pub struct RoomCreation {
|
||||
pub session: WeakRef<Session>,
|
||||
/// The current session.
|
||||
#[property(get, set = Self::set_session, explicit_notify, nullable)]
|
||||
pub session: glib::WeakRef<Session>,
|
||||
#[template_child]
|
||||
pub create_button: TemplateChild<SpinnerButton>,
|
||||
#[template_child]
|
||||
|
@ -78,41 +81,34 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
impl ObjectImpl for RoomCreation {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
use once_cell::sync::Lazy;
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![glib::ParamSpecObject::builder::<Session>("session")
|
||||
.explicit_notify()
|
||||
.build()]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
match pspec.name() {
|
||||
"session" => self.obj().set_session(value.get().unwrap()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
match pspec.name() {
|
||||
"session" => self.obj().session().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for RoomCreation {}
|
||||
|
||||
impl WidgetImpl for RoomCreation {}
|
||||
impl WindowImpl for RoomCreation {}
|
||||
impl AdwWindowImpl for RoomCreation {}
|
||||
impl ToastableWindowImpl for RoomCreation {}
|
||||
|
||||
impl RoomCreation {
|
||||
/// Set the current session.
|
||||
fn set_session(&self, session: Option<Session>) {
|
||||
if self.session.upgrade() == session {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(session) = &session {
|
||||
self.server_name
|
||||
.set_label(&format!(":{}", session.user_id().server_name()));
|
||||
}
|
||||
|
||||
self.session.set(session.as_ref());
|
||||
self.obj().notify_session();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
/// Preference Window to display and update room details.
|
||||
/// Dialog to create a new room.
|
||||
pub struct RoomCreation(ObjectSubclass<imp::RoomCreation>)
|
||||
@extends gtk::Widget, gtk::Window, adw::Window, ToastableWindow, @implements gtk::Accessible;
|
||||
}
|
||||
|
@ -126,28 +122,6 @@ impl RoomCreation {
|
|||
.build()
|
||||
}
|
||||
|
||||
/// The current session.
|
||||
pub fn session(&self) -> Option<Session> {
|
||||
self.imp().session.upgrade()
|
||||
}
|
||||
|
||||
/// Set the current session.
|
||||
pub fn set_session(&self, session: Option<&Session>) {
|
||||
let imp = self.imp();
|
||||
|
||||
if self.session().as_ref() == session {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(session) = session {
|
||||
imp.server_name
|
||||
.set_label(&format!(":{}", session.user_id().server_name()));
|
||||
}
|
||||
|
||||
imp.session.set(session);
|
||||
self.notify("session");
|
||||
}
|
||||
|
||||
/// Create the room, if it is allowed.
|
||||
#[template_callback]
|
||||
fn create_room(&self) {
|
||||
|
|
|
@ -17,12 +17,12 @@ mod imp {
|
|||
use std::cell::RefCell;
|
||||
|
||||
use glib::subclass::InitializingObject;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
|
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/session_view.ui")]
|
||||
#[properties(wrapper_type = super::SessionView)]
|
||||
pub struct SessionView {
|
||||
#[template_child]
|
||||
pub stack: TemplateChild<gtk::Stack>,
|
||||
|
@ -36,6 +36,8 @@ mod imp {
|
|||
pub content: TemplateChild<Content>,
|
||||
#[template_child]
|
||||
pub media_viewer: TemplateChild<MediaViewer>,
|
||||
/// The current session.
|
||||
#[property(get, set = Self::set_session, explicit_notify, nullable)]
|
||||
pub session: glib::WeakRef<Session>,
|
||||
pub window_active_handler_id: RefCell<Option<SignalHandlerId>>,
|
||||
}
|
||||
|
@ -115,35 +117,8 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for SessionView {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![glib::ParamSpecObject::builder::<Session>("session")
|
||||
.explicit_notify()
|
||||
.build()]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
let obj = self.obj();
|
||||
|
||||
match pspec.name() {
|
||||
"session" => obj.set_session(value.get().unwrap()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
let obj = self.obj();
|
||||
|
||||
match pspec.name() {
|
||||
"session" => obj.session().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn constructed(&self) {
|
||||
self.parent_constructed();
|
||||
let obj = self.obj();
|
||||
|
@ -206,6 +181,18 @@ mod imp {
|
|||
|
||||
impl WidgetImpl for SessionView {}
|
||||
impl BinImpl for SessionView {}
|
||||
|
||||
impl SessionView {
|
||||
/// Set the current session.
|
||||
fn set_session(&self, session: Option<Session>) {
|
||||
if self.session.upgrade() == session {
|
||||
return;
|
||||
}
|
||||
|
||||
self.session.set(session.as_ref());
|
||||
self.obj().notify_session();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
|
@ -215,26 +202,11 @@ glib::wrapper! {
|
|||
}
|
||||
|
||||
impl SessionView {
|
||||
/// Create a new session.
|
||||
/// Create a new session view.
|
||||
pub async fn new() -> Self {
|
||||
glib::Object::new()
|
||||
}
|
||||
|
||||
/// The Matrix user session.
|
||||
pub fn session(&self) -> Option<Session> {
|
||||
self.imp().session.upgrade()
|
||||
}
|
||||
|
||||
/// Set the Matrix user session.
|
||||
pub fn set_session(&self, session: Option<&Session>) {
|
||||
if self.session().as_ref() == session {
|
||||
return;
|
||||
}
|
||||
|
||||
self.imp().session.set(session);
|
||||
self.notify("session");
|
||||
}
|
||||
|
||||
/// The currently selected room, if any.
|
||||
pub fn selected_room(&self) -> Option<Room> {
|
||||
self.imp().content.item().and_downcast()
|
||||
|
|
|
@ -18,8 +18,9 @@ mod imp {
|
|||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default, CompositeTemplate)]
|
||||
#[derive(Debug, Default, CompositeTemplate, glib::Properties)]
|
||||
#[template(resource = "/org/gnome/Fractal/ui/session/view/user_page.ui")]
|
||||
#[properties(wrapper_type = super::UserPage)]
|
||||
pub struct UserPage {
|
||||
#[template_child]
|
||||
pub avatar: TemplateChild<Avatar>,
|
||||
|
@ -32,6 +33,7 @@ mod imp {
|
|||
#[template_child]
|
||||
pub verify_button: TemplateChild<SpinnerButton>,
|
||||
/// The current user.
|
||||
#[property(get, set = Self::set_user, construct_only)]
|
||||
pub user: BoundObject<User>,
|
||||
pub bindings: RefCell<Vec<glib::Binding>>,
|
||||
}
|
||||
|
@ -63,32 +65,8 @@ mod imp {
|
|||
}
|
||||
}
|
||||
|
||||
#[glib::derived_properties]
|
||||
impl ObjectImpl for UserPage {
|
||||
fn properties() -> &'static [glib::ParamSpec] {
|
||||
use once_cell::sync::Lazy;
|
||||
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
|
||||
vec![glib::ParamSpecObject::builder::<User>("user")
|
||||
.construct_only()
|
||||
.build()]
|
||||
});
|
||||
|
||||
PROPERTIES.as_ref()
|
||||
}
|
||||
|
||||
fn set_property(&self, _id: usize, value: &glib::Value, pspec: &glib::ParamSpec) {
|
||||
match pspec.name() {
|
||||
"user" => self.obj().set_user(value.get().unwrap()),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn property(&self, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
|
||||
match pspec.name() {
|
||||
"user" => self.obj().user().to_value(),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn dispose(&self) {
|
||||
for binding in self.bindings.take() {
|
||||
binding.unbind();
|
||||
|
@ -98,6 +76,38 @@ mod imp {
|
|||
|
||||
impl WidgetImpl for UserPage {}
|
||||
impl NavigationPageImpl for UserPage {}
|
||||
|
||||
impl UserPage {
|
||||
/// Set the current user.
|
||||
fn set_user(&self, user: User) {
|
||||
let obj = self.obj();
|
||||
|
||||
let title_binding = user
|
||||
.bind_property("display-name", &*obj, "title")
|
||||
.sync_create()
|
||||
.build();
|
||||
let avatar_binding = user
|
||||
.bind_property("avatar-data", &*self.avatar, "data")
|
||||
.sync_create()
|
||||
.build();
|
||||
self.bindings.replace(vec![title_binding, avatar_binding]);
|
||||
|
||||
let is_verified_handler = user.connect_verified_notify(clone!(@weak obj => move |_| {
|
||||
obj.update_verified();
|
||||
}));
|
||||
|
||||
// We don't need to listen to changes of the property, it never changes after
|
||||
// construction.
|
||||
self.direct_chat_button.set_visible(!user.is_own_user());
|
||||
|
||||
self.user.set(user, vec![is_verified_handler]);
|
||||
|
||||
spawn!(clone!(@weak obj => async move {
|
||||
obj.load_direct_chat().await;
|
||||
}));
|
||||
obj.update_verified();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glib::wrapper! {
|
||||
|
@ -112,48 +122,6 @@ impl UserPage {
|
|||
glib::Object::builder().property("user", user).build()
|
||||
}
|
||||
|
||||
/// The current user.
|
||||
pub fn user(&self) -> Option<User> {
|
||||
self.imp().user.obj()
|
||||
}
|
||||
|
||||
/// Set the current user.
|
||||
fn set_user(&self, user: Option<User>) {
|
||||
let Some(user) = user else {
|
||||
// Ignore missing user.
|
||||
return;
|
||||
};
|
||||
let imp = self.imp();
|
||||
|
||||
let title_binding = user
|
||||
.bind_property("display-name", self, "title")
|
||||
.sync_create()
|
||||
.build();
|
||||
let avatar_binding = user
|
||||
.bind_property("avatar-data", &*imp.avatar, "data")
|
||||
.sync_create()
|
||||
.build();
|
||||
imp.bindings.replace(vec![title_binding, avatar_binding]);
|
||||
|
||||
let is_verified_handler = user.connect_notify_local(
|
||||
Some("is-verified"),
|
||||
clone!(@weak self as obj => move |_, _| {
|
||||
obj.update_verified();
|
||||
}),
|
||||
);
|
||||
|
||||
// We don't need to listen to changes of the property, it never changes after
|
||||
// construction.
|
||||
imp.direct_chat_button.set_visible(!user.is_own_user());
|
||||
|
||||
imp.user.set(user, vec![is_verified_handler]);
|
||||
|
||||
spawn!(clone!(@weak self as obj => async move {
|
||||
obj.load_direct_chat().await;
|
||||
}));
|
||||
self.update_verified();
|
||||
}
|
||||
|
||||
/// Load whether the current user has a direct chat or not.
|
||||
async fn load_direct_chat(&self) {
|
||||
self.set_direct_chat_loading(true);
|
||||
|
|
|
@ -343,7 +343,7 @@ impl Window {
|
|||
self.switch_to_loading_page();
|
||||
}
|
||||
|
||||
imp.session.set_session(None);
|
||||
imp.session.set_session(None::<Session>);
|
||||
}
|
||||
|
||||
pub fn save_window_size(&self) -> Result<(), glib::BoolError> {
|
||||
|
|
Loading…
Reference in New Issue