[fractal/fractal-next] Add login requests to the sidebar and remove `ContentType`
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] Add login requests to the sidebar and remove `ContentType`
- Date: Fri, 19 Nov 2021 11:37:58 +0000 (UTC)
commit 3514fcdbcab4edad49d102f3d47b18a7d248be2b
Author: Julian Sparber <julian sparber net>
Date: Wed Nov 10 14:34:33 2021 +0100
Add login requests to the sidebar and remove `ContentType`
The `ContentType` could be removed because the needed information is
already contained in the `selected-item`. This also addes `EntryType` to
differentiat between different `Entry`s even tought we currently have
only "Explore". This also cleans up how the selected-item is passed
between `Content` and `Sidebar`
This also replaces the `ToDeviceHandler` with `VerificationList` that's
used to track verifications.
data/resources/resources.gresource.xml | 1 +
data/resources/ui/content.ui | 2 -
data/resources/ui/session.ui | 7 +-
data/resources/ui/sidebar-verification-row.ui | 39 ++++++
po/POTFILES.in | 7 +-
src/meson.build | 7 +-
src/session/content/content_type.rs | 27 ----
src/session/content/explore/public_room.rs | 2 +-
src/session/content/mod.rs | 111 +++++++----------
src/session/mod.rs | 145 +++++++---------------
src/session/room/room_type.rs | 10 +-
src/session/room_creation/mod.rs | 2 +-
src/session/sidebar/category.rs | 75 ++++++-----
src/session/sidebar/category_type.rs | 58 +++++++++
src/session/sidebar/entry.rs | 21 ++--
src/session/sidebar/entry_type.rs | 23 ++++
src/session/sidebar/item_list.rs | 103 ++++++++++-----
src/session/sidebar/mod.rs | 96 +++++---------
src/session/sidebar/row.rs | 19 ++-
src/session/sidebar/selection.rs | 83 -------------
src/session/sidebar/verification_row.rs | 104 ++++++++++++++++
src/session/verification/identity_verification.rs | 13 ++
src/session/verification/mod.rs | 4 +-
src/session/verification/to_device_handler.rs | 95 --------------
src/session/verification/verification_list.rs | 123 ++++++++++++++++++
25 files changed, 648 insertions(+), 529 deletions(-)
---
diff --git a/data/resources/resources.gresource.xml b/data/resources/resources.gresource.xml
index cea9d767..c613e5f8 100644
--- a/data/resources/resources.gresource.xml
+++ b/data/resources/resources.gresource.xml
@@ -27,6 +27,7 @@
<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>
<file compressed="true" preprocess="xml-stripblanks"
alias="sidebar-room-row.ui">ui/sidebar-room-row.ui</file>
+ <file compressed="true" preprocess="xml-stripblanks"
alias="sidebar-verification-row.ui">ui/sidebar-verification-row.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="window.ui">ui/window.ui</file>
<file compressed="true" preprocess="xml-stripblanks"
alias="context-menu-bin.ui">ui/context-menu-bin.ui</file>
<file compressed="true" preprocess="xml-stripblanks" alias="pill.ui">ui/pill.ui</file>
diff --git a/data/resources/ui/content.ui b/data/resources/ui/content.ui
index 748f4a21..9a56762c 100644
--- a/data/resources/ui/content.ui
+++ b/data/resources/ui/content.ui
@@ -41,13 +41,11 @@
<child>
<object class="ContentRoomHistory" id="room_history">
<property name="compact" bind-source="Content" bind-property="compact" bind-flags="sync-create"/>
- <property name="room" bind-source="Content" bind-property="room" bind-flags="sync-create"/>
</object>
</child>
<child>
<object class="ContentInvite" id="invite">
<property name="compact" bind-source="Content" bind-property="compact" bind-flags="sync-create"/>
- <property name="room" bind-source="Content" bind-property="room" bind-flags="sync-create"/>
</object>
</child>
<child>
diff --git a/data/resources/ui/session.ui b/data/resources/ui/session.ui
index f20a4630..f8dee1d9 100644
--- a/data/resources/ui/session.ui
+++ b/data/resources/ui/session.ui
@@ -41,9 +41,7 @@
<object class="Sidebar" id="sidebar">
<property name="compact" bind-source="content" bind-property="folded"
bind-flags="sync-create"/>
<property name="user" bind-source="Session" bind-property="user" bind-flags="sync-create"/>
- <property name="room-list" bind-source="Session" bind-property="room-list"
bind-flags="sync-create"/>
- <property name="selected-room" bind-source="Session" bind-property="selected-room"
bind-flags="sync-create | bidirectional"/>
- <property name="selected-type" bind-source="Session" bind-property="selected-content-type"
bind-flags="sync-create | bidirectional"/>
+ <property name="item-list" bind-source="Session" bind-property="item-list"
bind-flags="sync-create"/>
</object>
</child>
<child>
@@ -57,8 +55,7 @@
<child>
<object class="Content">
<property name="compact" bind-source="content" bind-property="folded"
bind-flags="sync-create"/>
- <property name="room" bind-source="Session" bind-property="selected-room"
bind-flags="sync-create | bidirectional"/>
- <property name="content-type" bind-source="Session" bind-property="selected-content-type"
bind-flags="sync-create | bidirectional"/>
+ <property name="item" bind-source="sidebar" bind-property="selected-item"
bind-flags="sync-create | bidirectional"/>
<property name="session">Session</property>
</object>
</child>
diff --git a/data/resources/ui/sidebar-verification-row.ui b/data/resources/ui/sidebar-verification-row.ui
new file mode 100644
index 00000000..545b0179
--- /dev/null
+++ b/data/resources/ui/sidebar-verification-row.ui
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="SidebarVerificationRow" parent="AdwBin">
+ <child>
+ <object class="GtkBox">
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkImage">
+ <property name="icon-name">devices-symbolic</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="display_name">
+ <property name="ellipsize">end</property>
+ <binding name="label">
+ <lookup name="display-name" type="IdentityVerification">
+ <lookup name="identity-verification">SidebarVerificationRow</lookup>
+ </lookup>
+ </binding>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkLabel">
+ <property name="hexpand">True</property>
+ <property name="halign">end</property>
+ <property name="valign">center</property>
+ <property name="yalign">1.0</property>
+ <property name="label">•</property>
+ <style>
+ <class name="notification_count"/>
+ <class name="highlight"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+</interface>
+
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 1e9de487..c1579fb3 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -36,6 +36,7 @@ data/resources/ui/sidebar-category-row.ui
data/resources/ui/sidebar-entry-row.ui
data/resources/ui/sidebar-item.ui
data/resources/ui/sidebar-room-row.ui
+data/resources/ui/sidebar-verification-row.ui
data/resources/ui/sidebar.ui
data/resources/ui/spinner-button.ui
data/resources/ui/pill.ui
@@ -96,7 +97,11 @@ 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/category_type.rs
src/session/sidebar/entry.rs
+src/session/sidebar/entry_row.rs,
+src/session/sidebar/entry_type.rs,
+src/session/sidebar/verification_row.rs,
src/session/sidebar/mod.rs
src/session/sidebar/room_row.rs
src/session/sidebar/row.rs
@@ -105,7 +110,7 @@ src/session/verification/emoji.rs
src/session/verification/identity_verification.rs
src/session/verification/mod.rs
src/session/verification/session_verification.rs
-src/session/verification/to_device_handler.rs
+src/session/verification/verification_list.rs
src/session/user.rs
src/utils.rs
src/window.rs
diff --git a/src/meson.build b/src/meson.build
index 6a9f04cb..bd5b9bad 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -80,17 +80,22 @@ sources = files(
'session/sidebar/mod.rs',
'session/sidebar/row.rs',
'session/sidebar/room_row.rs',
+ 'session/sidebar/entry.rs',
+ 'session/sidebar/entry_row.rs',
+ 'session/sidebar/entry_type.rs',
+ 'session/sidebar/verification_row.rs',
'session/sidebar/selection.rs',
'session/sidebar/account_switcher/add_account.rs',
'session/sidebar/account_switcher/avatar_with_selection.rs',
'session/sidebar/account_switcher/item.rs',
'session/sidebar/account_switcher/mod.rs',
'session/sidebar/account_switcher/user_entry.rs',
+ 'session/sidebar/category_type.rs',
'session/verification/mod.rs',
'session/verification/emoji.rs',
'session/verification/identity_verification.rs',
'session/verification/session_verification.rs',
- 'session/verification/to_device_handler.rs',
+ 'session/verification/verification_list.rs',
)
custom_target(
diff --git a/src/session/content/explore/public_room.rs b/src/session/content/explore/public_room.rs
index ec1aa5d1..23edc1e4 100644
--- a/src/session/content/explore/public_room.rs
+++ b/src/session/content/explore/public_room.rs
@@ -205,7 +205,7 @@ impl PublicRoom {
pub fn join_or_view(&self) {
let session = self.session();
if let Some(room) = self.room() {
- session.set_selected_room(Some(room.clone()));
+ session.select_room(Some(room.clone()));
} else if let Some(matrix_public_room) = self.matrix_public_room() {
session
.room_list()
diff --git a/src/session/content/mod.rs b/src/session/content/mod.rs
index 12bf3fb5..1b0ecbd2 100644
--- a/src/session/content/mod.rs
+++ b/src/session/content/mod.rs
@@ -1,4 +1,3 @@
-mod content_type;
mod divider_row;
mod explore;
mod invite;
@@ -9,7 +8,6 @@ mod room_details;
mod room_history;
mod state_row;
-pub use self::content_type::ContentType;
use self::divider_row::DividerRow;
use self::explore::Explore;
use self::invite::Invite;
@@ -18,6 +16,9 @@ use self::markdown_popover::MarkdownPopover;
use self::room_details::RoomDetails;
use self::room_history::RoomHistory;
use self::state_row::StateRow;
+use crate::session::sidebar::{Entry, EntryType};
+
+use crate::session::verification::IdentityVerification;
use adw::subclass::prelude::*;
use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*, CompositeTemplate};
@@ -37,8 +38,7 @@ mod imp {
pub struct Content {
pub compact: Cell<bool>,
pub session: RefCell<Option<WeakRef<Session>>>,
- pub room: RefCell<Option<Room>>,
- pub content_type: Cell<ContentType>,
+ pub item: RefCell<Option<glib::Object>>,
pub error_list: RefCell<Option<gio::ListStore>>,
pub category_handler: RefCell<Option<SignalHandlerId>>,
#[template_child]
@@ -67,7 +67,7 @@ mod imp {
klass.set_accessible_role(gtk::AccessibleRole::Group);
klass.install_action("content.go-back", None, move |widget, _, _| {
- widget.set_content_type(ContentType::None);
+ widget.set_item(None);
});
}
@@ -95,10 +95,10 @@ mod imp {
glib::ParamFlags::READWRITE,
),
glib::ParamSpec::new_object(
- "room",
- "Room",
- "The room currently shown",
- Room::static_type(),
+ "item",
+ "Item",
+ "The item currently shown",
+ glib::Object::static_type(),
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
glib::ParamSpec::new_object(
@@ -108,14 +108,6 @@ mod imp {
gio::ListStore::static_type(),
glib::ParamFlags::READWRITE,
),
- glib::ParamSpec::new_enum(
- "content-type",
- "Content Type",
- "The type of content currently displayed",
- ContentType::static_type(),
- ContentType::default() as i32,
- glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
- ),
]
});
@@ -135,14 +127,10 @@ mod imp {
self.compact.set(compact);
}
"session" => obj.set_session(value.get().unwrap()),
- "room" => {
- let room = value.get().unwrap();
- obj.set_room(room);
- }
+ "item" => obj.set_item(value.get().unwrap()),
"error-list" => {
self.error_list.replace(value.get().unwrap());
}
- "content-type" => obj.set_content_type(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -151,9 +139,8 @@ mod imp {
match pspec.name() {
"compact" => self.compact.get().to_value(),
"session" => obj.session().to_value(),
- "room" => obj.room().to_value(),
+ "item" => obj.item().to_value(),
"error-list" => self.error_list.borrow().to_value(),
- "content-type" => obj.content_type().to_value(),
_ => unimplemented!(),
}
}
@@ -195,78 +182,76 @@ impl Content {
self.notify("session");
}
- pub fn content_type(&self) -> ContentType {
- let priv_ = imp::Content::from_instance(self);
- priv_.content_type.get()
- }
-
- pub fn set_content_type(&self, content_type: ContentType) {
- let priv_ = imp::Content::from_instance(self);
-
- if self.content_type() == content_type {
- return;
- }
-
- priv_.content_type.set(content_type);
- self.set_visible_child();
-
- self.notify("content-type");
- }
-
- pub fn set_room(&self, room: Option<Room>) {
+ pub fn set_item(&self, item: Option<glib::Object>) {
let priv_ = imp::Content::from_instance(self);
- if self.room() == room {
+ if self.item() == item {
return;
}
if let Some(category_handler) = priv_.category_handler.take() {
- if let Some(room) = self.room() {
- room.disconnect(category_handler);
+ if let Some(item) = self.item() {
+ item.disconnect(category_handler);
}
}
- if let Some(ref room) = room {
- let handler_id = room.connect_notify_local(
- Some("category"),
- clone!(@weak self as obj => move |_, _| {
- obj.set_visible_child();
- }),
- );
+ if let Some(ref room) = item {
+ if room.is::<Room>() {
+ let handler_id = room.connect_notify_local(
+ Some("category"),
+ clone!(@weak self as obj => move |_, _| {
+ obj.set_visible_child();
+ }),
+ );
- priv_.category_handler.replace(Some(handler_id));
+ priv_.category_handler.replace(Some(handler_id));
+ }
}
- priv_.room.replace(room);
+ priv_.item.replace(item);
self.set_visible_child();
- self.notify("room");
+ self.notify("item");
}
- pub fn room(&self) -> Option<Room> {
+ pub fn item(&self) -> Option<glib::Object> {
let priv_ = imp::Content::from_instance(self);
- priv_.room.borrow().clone()
+ priv_.item.borrow().clone()
}
fn set_visible_child(&self) {
let priv_ = imp::Content::from_instance(self);
- match self.content_type() {
- ContentType::None => {
+ match self.item() {
+ None => {
priv_.stack.set_visible_child(&*priv_.empty_page);
}
- ContentType::Room => {
- if let Some(room) = &*priv_.room.borrow() {
+ Some(o) if o.is::<Room>() => {
+ if let Some(room) = priv_
+ .item
+ .borrow()
+ .as_ref()
+ .and_then(|item| item.downcast_ref::<Room>())
+ {
if room.category() == RoomType::Invited {
+ priv_.invite.set_room(Some(room.clone()));
priv_.stack.set_visible_child(&*priv_.invite);
} else {
+ priv_.room_history.set_room(Some(room.clone()));
priv_.stack.set_visible_child(&*priv_.room_history);
}
}
}
- ContentType::Explore => {
+ Some(o)
+ if o.is::<Entry>()
+ && o.downcast_ref::<Entry>().unwrap().type_() == EntryType::Explore =>
+ {
priv_.explore.init();
priv_.stack.set_visible_child(&*priv_.explore);
}
+ Some(o) if o.is::<IdentityVerification>() => {
+ todo!("Incoming verifications arn't implemented yet");
+ }
+ _ => {}
}
}
}
diff --git a/src/session/mod.rs b/src/session/mod.rs
index 250b5837..eae03535 100644
--- a/src/session/mod.rs
+++ b/src/session/mod.rs
@@ -7,7 +7,7 @@ mod room_creation;
mod room_list;
mod sidebar;
mod user;
-mod verification;
+pub mod verification;
use self::account_settings::AccountSettings;
pub use self::avatar::Avatar;
@@ -17,7 +17,8 @@ pub use self::room_creation::RoomCreation;
use self::room_list::RoomList;
use self::sidebar::Sidebar;
pub use self::user::{User, UserExt};
-pub use self::verification::{IdentityVerification, SessionVerification, ToDeviceHandler};
+use self::verification::{IdentityVerification, SessionVerification, VerificationList};
+use crate::session::sidebar::ItemList;
use crate::secret;
use crate::secret::StoredSession;
@@ -26,7 +27,6 @@ use crate::Window;
use crate::{spawn, spawn_tokio};
use crate::matrix_error::UserFacingError;
-use crate::session::content::ContentType;
use adw::subclass::prelude::BinImpl;
use futures::StreamExt;
use gettextrs::gettext;
@@ -76,16 +76,13 @@ mod imp {
#[template_child]
pub sidebar: TemplateChild<Sidebar>,
pub client: RefCell<Option<Client>>,
- pub room_list: OnceCell<RoomList>,
+ pub item_list: OnceCell<ItemList>,
pub user: OnceCell<User>,
- pub selected_room: RefCell<Option<Room>>,
- pub selected_content_type: Cell<ContentType>,
pub is_ready: Cell<bool>,
pub logout_on_dispose: Cell<bool>,
pub info: OnceCell<StoredSession>,
pub source_id: RefCell<Option<SourceId>>,
pub sync_tokio_handle: RefCell<Option<JoinHandle<()>>>,
- pub to_device_handler: OnceCell<ToDeviceHandler>,
}
#[glib::object_subclass]
@@ -98,7 +95,7 @@ mod imp {
Self::bind_template(klass);
klass.install_action("session.close-room", None, move |session, _, _| {
- session.set_selected_room(None);
+ session.select_room(None);
});
klass.install_action("session.logout", None, move |session, _, _| {
@@ -156,27 +153,12 @@ mod imp {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
vec![
glib::ParamSpec::new_object(
- "room-list",
- "Room List",
- "The list of rooms",
- RoomList::static_type(),
+ "item-list",
+ "Item List",
+ "The list of items in the sidebar",
+ ItemList::static_type(),
glib::ParamFlags::READABLE,
),
- glib::ParamSpec::new_object(
- "selected-room",
- "Selected Room",
- "The selected room in this session",
- Room::static_type(),
- glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
- ),
- glib::ParamSpec::new_enum(
- "selected-content-type",
- "Selected Content Type",
- "The current content type selected",
- ContentType::static_type(),
- ContentType::default() as i32,
- glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
- ),
glib::ParamSpec::new_object(
"user",
"User",
@@ -190,29 +172,10 @@ mod imp {
PROPERTIES.as_ref()
}
- fn set_property(
- &self,
- obj: &Self::Type,
- _id: usize,
- value: &glib::Value,
- pspec: &glib::ParamSpec,
- ) {
- match pspec.name() {
- "selected-room" => {
- let selected_room = value.get().unwrap();
- obj.set_selected_room(selected_room);
- }
- "selected-content-type" => obj.set_selected_content_type(value.get().unwrap()),
- _ => unimplemented!(),
- }
- }
-
fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
match pspec.name() {
- "room-list" => obj.room_list().to_value(),
- "selected-room" => obj.selected_room().to_value(),
+ "item-list" => obj.item_list().to_value(),
"user" => obj.user().to_value(),
- "selected-content-type" => obj.selected_content_type().to_value(),
_ => unimplemented!(),
}
}
@@ -233,6 +196,23 @@ mod imp {
SIGNALS.as_ref()
}
+ fn constructed(&self, obj: &Self::Type) {
+ self.parent_constructed(obj);
+
+ self.sidebar.connect_notify_local(
+ Some("selected-item"),
+ clone!(@weak obj => move |_, _| {
+ let priv_ = imp::Session::from_instance(&obj);
+
+ if priv_.sidebar.selected_item().is_none() {
+ priv_.content.navigate(adw::NavigationDirection::Back);
+ } else {
+ priv_.content.navigate(adw::NavigationDirection::Forward);
+ }
+ }),
+ );
+ }
+
fn dispose(&self, obj: &Self::Type) {
if let Some(source_id) = self.source_id.take() {
let _ = glib::Source::remove(source_id);
@@ -261,44 +241,11 @@ impl Session {
glib::Object::new(&[]).expect("Failed to create Session")
}
- pub fn selected_content_type(&self) -> ContentType {
- let priv_ = imp::Session::from_instance(self);
- priv_.selected_content_type.get()
- }
-
- pub fn set_selected_content_type(&self, selected_type: ContentType) {
- let priv_ = imp::Session::from_instance(self);
-
- if self.selected_content_type() == selected_type {
- return;
- }
-
- if selected_type == ContentType::None {
- priv_.content.navigate(adw::NavigationDirection::Back);
- } else {
- priv_.content.navigate(adw::NavigationDirection::Forward);
- }
-
- priv_.selected_content_type.set(selected_type);
-
- self.notify("selected-content-type");
- }
-
- pub fn selected_room(&self) -> Option<Room> {
- let priv_ = imp::Session::from_instance(self);
- priv_.selected_room.borrow().clone()
- }
-
- pub fn set_selected_room(&self, selected_room: Option<Room>) {
+ pub fn select_room(&self, room: Option<Room>) {
let priv_ = imp::Session::from_instance(self);
-
- if self.selected_room() == selected_room {
- return;
- }
-
- priv_.selected_room.replace(selected_room);
-
- self.notify("selected-room");
+ priv_
+ .sidebar
+ .set_selected_item(room.map(|item| item.upcast()));
}
pub fn login_with_password(&self, homeserver: Url, username: String, password: String) {
@@ -402,11 +349,6 @@ impl Session {
priv_.user.set(user.clone()).unwrap();
self.notify("user");
- priv_
- .to_device_handler
- .set(ToDeviceHandler::new(self))
- .unwrap();
-
let handle = spawn_tokio!(async move {
let display_name = client.display_name().await?;
let avatar_url = client.avatar_url().await?;
@@ -552,11 +494,7 @@ impl Session {
let verification = IdentityVerification::new(obj.user().unwrap());
let session = SessionVerification::new(&verification, &obj);
- priv_
- .to_device_handler
- .get()
- .unwrap()
- .add_request(verification);
+ obj.verification_list().add(verification);
priv_
.stack
.add_named(&session, Some("session-verification"));
@@ -576,8 +514,18 @@ impl Session {
}
pub fn room_list(&self) -> &RoomList {
+ self.item_list().room_list()
+ }
+
+ pub fn verification_list(&self) -> &VerificationList {
+ self.item_list().verification_list()
+ }
+
+ pub fn item_list(&self) -> &ItemList {
let priv_ = &imp::Session::from_instance(self);
- priv_.room_list.get_or_init(|| RoomList::new(self))
+ priv_
+ .item_list
+ .get_or_init(|| ItemList::new(&RoomList::new(self), &VerificationList::new(self)))
}
pub fn user(&self) -> Option<&User> {
@@ -655,18 +603,13 @@ impl Session {
}
fn handle_sync_response(&self, response: Result<SyncResponse, matrix_sdk::Error>) {
- let priv_ = imp::Session::from_instance(self);
-
match response {
Ok(response) => {
if !self.is_ready() {
self.mark_ready();
}
self.room_list().handle_response_rooms(response.rooms);
- priv_
- .to_device_handler
- .get()
- .unwrap()
+ self.verification_list()
.handle_response_to_device(response.to_device);
}
Err(error) => {
diff --git a/src/session/room/room_type.rs b/src/session/room/room_type.rs
index ca80a07d..1b7d88d3 100644
--- a/src/session/room/room_type.rs
+++ b/src/session/room/room_type.rs
@@ -1,4 +1,4 @@
-use gettextrs::gettext;
+use crate::session::sidebar::CategoryType;
use gtk::glib;
// TODO: do we also want the category `People` and a custom category support?
@@ -21,12 +21,6 @@ impl Default for RoomType {
impl ToString for RoomType {
fn to_string(&self) -> String {
- match self {
- RoomType::Invited => gettext("Invited"),
- RoomType::Favorite => gettext("Favorite"),
- RoomType::Normal => gettext("Rooms"),
- RoomType::LowPriority => gettext("Low Priority"),
- RoomType::Left => gettext("Historical"),
- }
+ CategoryType::from(self).to_string()
}
}
diff --git a/src/session/room_creation/mod.rs b/src/session/room_creation/mod.rs
index 0b142209..c8e806d6 100644
--- a/src/session/room_creation/mod.rs
+++ b/src/session/room_creation/mod.rs
@@ -242,7 +242,7 @@ impl RoomCreation {
Ok(response) => {
if let Some(session) = obj.session() {
let room = session.room_list().get_wait(response.room_id).await;
- session.set_selected_room(room);
+ session.select_room(room);
}
obj.close();
},
diff --git a/src/session/sidebar/category.rs b/src/session/sidebar/category.rs
index 44b6dd8d..41ad6334 100644
--- a/src/session/sidebar/category.rs
+++ b/src/session/sidebar/category.rs
@@ -1,9 +1,7 @@
use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*};
-use crate::session::{
- room::{Room, RoomType},
- room_list::RoomList,
-};
+use crate::session::sidebar::CategoryType;
+use crate::session::{room::Room, room_list::RoomList};
mod imp {
use once_cell::unsync::OnceCell;
@@ -14,7 +12,7 @@ mod imp {
#[derive(Debug, Default)]
pub struct Category {
pub model: OnceCell<gio::ListModel>,
- pub type_: Cell<RoomType>,
+ pub type_: Cell<CategoryType>,
}
#[glib::object_subclass]
@@ -34,8 +32,8 @@ mod imp {
"type",
"Type",
"The type of this category",
- RoomType::static_type(),
- RoomType::default() as i32,
+ CategoryType::static_type(),
+ CategoryType::default() as i32,
glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
),
glib::ParamSpec::new_string(
@@ -90,19 +88,19 @@ mod imp {
impl ListModelImpl for Category {
fn item_type(&self, _list_model: &Self::Type) -> glib::Type {
- Room::static_type()
+ glib::Object::static_type()
}
fn n_items(&self, _list_model: &Self::Type) -> u32 {
- self.model.get().map(|l| l.n_items()).unwrap_or(0)
+ self.model.get().unwrap().n_items()
}
fn item(&self, _list_model: &Self::Type, position: u32) -> Option<glib::Object> {
- self.model.get().and_then(|l| l.item(position))
+ self.model.get().unwrap().item(position)
}
}
}
glib::wrapper! {
- /// A list of Rooms in the same category implementing ListModel.
+ /// A list of Items in the same category implementing ListModel.
///
/// This struct is used in ItemList for the sidebar.
pub struct Category(ObjectSubclass<imp::Category>)
@@ -110,11 +108,11 @@ glib::wrapper! {
}
impl Category {
- pub fn new(type_: RoomType, model: &RoomList) -> Self {
+ pub fn new(type_: CategoryType, model: &impl IsA<gio::ListModel>) -> Self {
glib::Object::new(&[("type", &type_), ("model", model)]).expect("Failed to create Category")
}
- pub fn type_(&self) -> RoomType {
+ pub fn type_(&self) -> CategoryType {
let priv_ = imp::Category::from_instance(self);
priv_.type_.get()
}
@@ -123,26 +121,35 @@ impl Category {
let priv_ = imp::Category::from_instance(self);
let type_ = self.type_();
- let filter = gtk::CustomFilter::new(move |o| {
- o.downcast_ref::<Room>()
- .filter(|r| r.category() == type_)
- .is_some()
- });
- let filter_model = gtk::FilterListModel::new(Some(&model), Some(&filter));
-
- let sorter = gtk::CustomSorter::new(|a, b| {
- let a = a.downcast_ref::<Room>().unwrap();
- let b = b.downcast_ref::<Room>().unwrap();
- b.latest_change().cmp(&a.latest_change()).into()
- });
- let sort_model = gtk::SortListModel::new(Some(&filter_model), Some(&sorter));
-
- sort_model.connect_items_changed(
- clone!(@weak self as obj => move |_, pos, added, removed| {
- obj.items_changed(pos, added, removed);
- }),
- );
-
- priv_.model.set(sort_model.upcast()).unwrap();
+ // Special case room lists so that they are sorted and in the right category
+ if model.is::<RoomList>() {
+ let filter = gtk::CustomFilter::new(move |o| {
+ o.downcast_ref::<Room>()
+ .filter(|r| CategoryType::from(r.category()) == type_)
+ .is_some()
+ });
+ let filter_model = gtk::FilterListModel::new(Some(&model), Some(&filter));
+
+ let sorter = gtk::CustomSorter::new(|a, b| {
+ let a = a.downcast_ref::<Room>().unwrap();
+ let b = b.downcast_ref::<Room>().unwrap();
+ b.latest_change().cmp(&a.latest_change()).into()
+ });
+ let sort_model = gtk::SortListModel::new(Some(&filter_model), Some(&sorter));
+
+ sort_model.connect_items_changed(
+ clone!(@weak self as obj => move |_, pos, removed, added| {
+ obj.items_changed(pos, removed, added);
+ }),
+ );
+ priv_.model.set(sort_model.upcast()).unwrap();
+ } else {
+ model.connect_items_changed(
+ clone!(@weak self as obj => move |_, pos, removed, added| {
+ obj.items_changed(pos, removed, added);
+ }),
+ );
+ priv_.model.set(model).unwrap();
+ }
}
}
diff --git a/src/session/sidebar/category_type.rs b/src/session/sidebar/category_type.rs
new file mode 100644
index 00000000..3a027eba
--- /dev/null
+++ b/src/session/sidebar/category_type.rs
@@ -0,0 +1,58 @@
+use crate::session::room::RoomType;
+use gettextrs::gettext;
+use gtk::glib;
+
+#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy, glib::GEnum)]
+#[repr(u32)]
+#[genum(type_name = "CategoryType")]
+pub enum CategoryType {
+ VerificationRequest = 0,
+ Invited = 1,
+ Favorite = 2,
+ Normal = 3,
+ LowPriority = 4,
+ Left = 5,
+}
+
+impl Default for CategoryType {
+ fn default() -> Self {
+ CategoryType::Normal
+ }
+}
+
+impl ToString for CategoryType {
+ fn to_string(&self) -> String {
+ match self {
+ CategoryType::VerificationRequest => gettext("Login Requests"),
+ CategoryType::Invited => gettext("Invited"),
+ CategoryType::Favorite => gettext("Favorite"),
+ CategoryType::Normal => gettext("Rooms"),
+ CategoryType::LowPriority => gettext("Low Priority"),
+ CategoryType::Left => gettext("Historical"),
+ }
+ }
+}
+
+impl From<RoomType> for CategoryType {
+ fn from(room_type: RoomType) -> Self {
+ match room_type {
+ RoomType::Invited => Self::Invited,
+ RoomType::Favorite => Self::Favorite,
+ RoomType::Normal => Self::Normal,
+ RoomType::LowPriority => Self::LowPriority,
+ RoomType::Left => Self::Left,
+ }
+ }
+}
+
+impl From<&RoomType> for CategoryType {
+ fn from(room_type: &RoomType) -> Self {
+ match room_type {
+ RoomType::Invited => Self::Invited,
+ RoomType::Favorite => Self::Favorite,
+ RoomType::Normal => Self::Normal,
+ RoomType::LowPriority => Self::LowPriority,
+ RoomType::Left => Self::Left,
+ }
+ }
+}
diff --git a/src/session/sidebar/entry.rs b/src/session/sidebar/entry.rs
index d98f4527..4a0572f6 100644
--- a/src/session/sidebar/entry.rs
+++ b/src/session/sidebar/entry.rs
@@ -1,6 +1,6 @@
use gtk::{glib, prelude::*, subclass::prelude::*};
-use crate::session::content::ContentType;
+use crate::session::sidebar::EntryType;
mod imp {
use std::cell::{Cell, RefCell};
@@ -9,8 +9,7 @@ mod imp {
#[derive(Debug, Default)]
pub struct Entry {
- pub type_: Cell<ContentType>,
- pub display_name: RefCell<Option<String>>,
+ pub type_: Cell<EntryType>,
pub icon_name: RefCell<Option<String>>,
}
@@ -30,8 +29,8 @@ mod imp {
"type",
"Type",
"The type of this category",
- ContentType::static_type(),
- ContentType::default() as i32,
+ EntryType::static_type(),
+ EntryType::default() as i32,
glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
),
glib::ParamSpec::new_string(
@@ -39,7 +38,7 @@ mod imp {
"Display Name",
"The display name of this Entry",
None,
- glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ glib::ParamFlags::READABLE,
),
glib::ParamSpec::new_string(
"icon-name",
@@ -65,9 +64,6 @@ mod imp {
"type" => {
self.type_.set(value.get().unwrap());
}
- "display-name" => {
- let _ = self.display_name.replace(value.get().unwrap());
- }
"icon-name" => {
let _ = self.icon_name.replace(value.get().unwrap());
}
@@ -95,19 +91,18 @@ glib::wrapper! {
}
impl Entry {
- pub fn new(type_: ContentType) -> Self {
+ pub fn new(type_: EntryType) -> Self {
glib::Object::new(&[("type", &type_)]).expect("Failed to create Entry")
}
- pub fn type_(&self) -> ContentType {
+ pub fn type_(&self) -> EntryType {
let priv_ = imp::Entry::from_instance(self);
priv_.type_.get()
}
pub fn icon_name(&self) -> Option<&str> {
match self.type_() {
- ContentType::Explore => Some("explore-symbolic"),
- _ => None,
+ EntryType::Explore => Some("explore-symbolic"),
}
}
}
diff --git a/src/session/sidebar/entry_type.rs b/src/session/sidebar/entry_type.rs
new file mode 100644
index 00000000..fcbdfd17
--- /dev/null
+++ b/src/session/sidebar/entry_type.rs
@@ -0,0 +1,23 @@
+use gettextrs::gettext;
+use gtk::glib;
+
+#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy, glib::GEnum)]
+#[repr(u32)]
+#[genum(type_name = "EntryType")]
+pub enum EntryType {
+ Explore = 0,
+}
+
+impl Default for EntryType {
+ fn default() -> Self {
+ EntryType::Explore
+ }
+}
+
+impl ToString for EntryType {
+ fn to_string(&self) -> String {
+ match self {
+ EntryType::Explore => gettext("Explore"),
+ }
+ }
+}
diff --git a/src/session/sidebar/item_list.rs b/src/session/sidebar/item_list.rs
index 8042d3a8..7fa61cfd 100644
--- a/src/session/sidebar/item_list.rs
+++ b/src/session/sidebar/item_list.rs
@@ -1,10 +1,11 @@
use gtk::{gio, glib, prelude::*, subclass::prelude::*};
use crate::session::{
- content::ContentType,
- room::RoomType,
room_list::RoomList,
+ sidebar::CategoryType,
+ sidebar::EntryType,
sidebar::{Category, Entry},
+ verification::VerificationList,
};
mod imp {
@@ -15,7 +16,9 @@ mod imp {
#[derive(Debug, Default)]
pub struct ItemList {
- pub list: OnceCell<[glib::Object; 6]>,
+ pub list: OnceCell<[glib::Object; 7]>,
+ pub room_list: OnceCell<RoomList>,
+ pub verification_list: OnceCell<VerificationList>,
}
#[glib::object_subclass]
@@ -29,13 +32,22 @@ mod imp {
impl ObjectImpl for ItemList {
fn properties() -> &'static [glib::ParamSpec] {
static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
- vec![glib::ParamSpec::new_object(
- "room-list",
- "Room list",
- "Data model for the categories",
- RoomList::static_type(),
- glib::ParamFlags::WRITABLE | glib::ParamFlags::CONSTRUCT_ONLY,
- )]
+ vec![
+ glib::ParamSpec::new_object(
+ "room-list",
+ "Room list",
+ "The list of rooms",
+ RoomList::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+ ),
+ glib::ParamSpec::new_object(
+ "verification-list",
+ "Verification list",
+ "The list of verification requests",
+ VerificationList::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+ ),
+ ]
});
PROPERTIES.as_ref()
@@ -49,13 +61,39 @@ mod imp {
pspec: &glib::ParamSpec,
) {
match pspec.name() {
- "room-list" => {
- let x = value.get().unwrap();
- obj.set_room_list(&x)
- }
+ "room-list" => obj.set_room_list(value.get().unwrap()),
+ "verification-list" => obj.set_verification_list(value.get().unwrap()),
_ => unimplemented!(),
}
}
+
+ fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "room-list" => obj.room_list().to_value(),
+ "verification-list" => obj.verification_list().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn constructed(&self, obj: &Self::Type) {
+ self.parent_constructed(obj);
+
+ let room_list = obj.room_list();
+ let verification_list = obj.verification_list();
+
+ let list = [
+ Entry::new(EntryType::Explore).upcast::<glib::Object>(),
+ Category::new(CategoryType::VerificationRequest, verification_list)
+ .upcast::<glib::Object>(),
+ Category::new(CategoryType::Invited, room_list).upcast::<glib::Object>(),
+ Category::new(CategoryType::Favorite, room_list).upcast::<glib::Object>(),
+ Category::new(CategoryType::Normal, room_list).upcast::<glib::Object>(),
+ Category::new(CategoryType::LowPriority, room_list).upcast::<glib::Object>(),
+ Category::new(CategoryType::Left, room_list).upcast::<glib::Object>(),
+ ];
+
+ self.list.set(list).unwrap();
+ }
}
impl ListModelImpl for ItemList {
@@ -85,24 +123,31 @@ glib::wrapper! {
}
impl ItemList {
- pub fn new(room_list: &RoomList) -> Self {
- glib::Object::new(&[("room-list", room_list)]).expect("Failed to create ItemList")
+ pub fn new(room_list: &RoomList, verification_list: &VerificationList) -> Self {
+ glib::Object::new(&[
+ ("room-list", room_list),
+ ("verification-list", verification_list),
+ ])
+ .expect("Failed to create ItemList")
}
- fn set_room_list(&self, room_list: &RoomList) {
+ fn set_room_list(&self, room_list: RoomList) {
let priv_ = imp::ItemList::from_instance(self);
+ priv_.room_list.set(room_list).unwrap();
+ }
+
+ fn set_verification_list(&self, verification_list: VerificationList) {
+ let priv_ = imp::ItemList::from_instance(self);
+ priv_.verification_list.set(verification_list).unwrap();
+ }
- let list = [
- Entry::new(ContentType::Explore).upcast::<glib::Object>(),
- Category::new(RoomType::Invited, room_list).upcast::<glib::Object>(),
- Category::new(RoomType::Favorite, room_list).upcast::<glib::Object>(),
- Category::new(RoomType::Normal, room_list).upcast::<glib::Object>(),
- Category::new(RoomType::LowPriority, room_list).upcast::<glib::Object>(),
- Category::new(RoomType::Left, room_list).upcast::<glib::Object>(),
- ];
- let len = list.len() as u32;
-
- priv_.list.set(list).unwrap();
- self.items_changed(0, 0, len);
+ pub fn room_list(&self) -> &RoomList {
+ let priv_ = imp::ItemList::from_instance(self);
+ priv_.room_list.get().unwrap()
+ }
+
+ pub fn verification_list(&self) -> &VerificationList {
+ let priv_ = imp::ItemList::from_instance(self);
+ priv_.verification_list.get().unwrap()
}
}
diff --git a/src/session/sidebar/mod.rs b/src/session/sidebar/mod.rs
index 45f6d773..606f33fc 100644
--- a/src/session/sidebar/mod.rs
+++ b/src/session/sidebar/mod.rs
@@ -1,29 +1,34 @@
mod account_switcher;
mod category;
mod category_row;
+mod category_type;
mod entry;
mod entry_row;
+mod entry_type;
mod item_list;
mod room_row;
mod row;
mod selection;
+mod verification_row;
pub use self::category::Category;
use self::category_row::CategoryRow;
+pub use self::category_type::CategoryType;
pub use self::entry::Entry;
use self::entry_row::EntryRow;
+pub use self::entry_type::EntryType;
pub use self::item_list::ItemList;
use self::room_row::RoomRow;
use self::row::Row;
use self::selection::Selection;
+use self::verification_row::VerificationRow;
use adw::subclass::prelude::BinImpl;
use gtk::{gio, glib, prelude::*, subclass::prelude::*, CompositeTemplate, SelectionModel};
use crate::components::Avatar;
-use crate::session::content::ContentType;
use crate::session::room::Room;
-use crate::session::RoomList;
+use crate::session::verification::IdentityVerification;
use crate::session::Session;
use crate::session::User;
use account_switcher::AccountSwitcher;
@@ -38,8 +43,7 @@ mod imp {
#[template(resource = "/org/gnome/FractalNext/sidebar.ui")]
pub struct Sidebar {
pub compact: Cell<bool>,
- pub selected_room: RefCell<Option<Room>>,
- pub selected_type: Cell<ContentType>,
+ pub selected_item: RefCell<Option<glib::Object>>,
#[template_child]
pub headerbar: TemplateChild<adw::HeaderBar>,
#[template_child]
@@ -90,25 +94,17 @@ mod imp {
glib::ParamFlags::READWRITE,
),
glib::ParamSpec::new_object(
- "room-list",
- "Room List",
- "The list of rooms",
- RoomList::static_type(),
- glib::ParamFlags::WRITABLE,
- ),
- glib::ParamSpec::new_object(
- "selected-room",
- "Selected Room",
- "The selected room in this sidebar",
- Room::static_type(),
+ "item-list",
+ "Item List",
+ "The list of items in the sidebar",
+ ItemList::static_type(),
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
- glib::ParamSpec::new_enum(
- "selected-type",
- "Selected",
- "The type of item that is selected",
- ContentType::static_type(),
- ContentType::default() as i32,
+ glib::ParamSpec::new_object(
+ "selected-item",
+ "Selected Item",
+ "The selected item in this sidebar",
+ glib::Object::static_type(),
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
]
@@ -132,15 +128,13 @@ mod imp {
"user" => {
obj.set_user(value.get().unwrap());
}
- "room-list" => {
- let room_list = value.get().unwrap();
- obj.set_room_list(room_list);
+ "item-list" => {
+ obj.set_item_list(value.get().unwrap());
}
- "selected-room" => {
- let selected_room = value.get().unwrap();
- obj.set_selected_room(selected_room);
+ "selected-item" => {
+ let selected_item = value.get().unwrap();
+ obj.set_selected_item(selected_item);
}
- "selected-type" => obj.set_selected_type(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -149,8 +143,7 @@ mod imp {
match pspec.name() {
"compact" => self.compact.get().to_value(),
"user" => obj.user().to_value(),
- "selected-room" => obj.selected_room().to_value(),
- "selected-type" => obj.selected_type().to_value(),
+ "selected-item" => obj.selected_item().to_value(),
_ => unimplemented!(),
}
}
@@ -174,6 +167,7 @@ mod imp {
Some(o) if o.is::<Category>() => row.set_expanded(!row.is_expanded()),
Some(o) if o.is::<Room>() => model.set_selected(pos),
Some(o) if o.is::<Entry>() => model.set_selected(pos),
+ Some(o) if o.is::<IdentityVerification>() => model.set_selected(pos),
_ => {}
}
});
@@ -194,26 +188,9 @@ impl Sidebar {
glib::Object::new(&[]).expect("Failed to create Sidebar")
}
- pub fn selected_type(&self) -> ContentType {
+ pub fn selected_item(&self) -> Option<glib::Object> {
let priv_ = imp::Sidebar::from_instance(self);
- priv_.selected_type.get()
- }
-
- fn set_selected_type(&self, selected_type: ContentType) {
- let priv_ = imp::Sidebar::from_instance(self);
-
- if self.selected_type() == selected_type {
- return;
- }
-
- priv_.selected_type.set(selected_type);
-
- self.notify("selected-type");
- }
-
- pub fn selected_room(&self) -> Option<Room> {
- let priv_ = imp::Sidebar::from_instance(self);
- priv_.selected_room.borrow().clone()
+ priv_.selected_item.borrow().clone()
}
pub fn room_search_bar(&self) -> gtk::SearchBar {
@@ -221,10 +198,10 @@ impl Sidebar {
priv_.room_search.clone()
}
- pub fn set_room_list(&self, room_list: Option<RoomList>) {
+ pub fn set_item_list(&self, item_list: Option<ItemList>) {
let priv_ = imp::Sidebar::from_instance(self);
- let room_list = match room_list {
- Some(room_list) => room_list,
+ let item_list = match item_list {
+ Some(item_list) => item_list,
None => {
priv_.listview.set_model(gtk::NONE_SELECTION_MODEL);
return;
@@ -232,7 +209,6 @@ impl Sidebar {
};
// TODO: hide empty categories
- let item_list = ItemList::new(&room_list);
let tree_model = gtk::TreeListModel::new(&item_list, false, true, |item| {
item.clone().downcast::<gio::ListModel>().ok()
});
@@ -262,26 +238,22 @@ impl Sidebar {
.build();
let selection = Selection::new(Some(&filter_model));
- self.bind_property("selected-room", &selection, "selected-item")
- .flags(glib::BindingFlags::SYNC_CREATE | glib::BindingFlags::BIDIRECTIONAL)
- .build();
-
- self.bind_property("selected-type", &selection, "selected-type")
+ self.bind_property("selected-item", &selection, "selected-item")
.flags(glib::BindingFlags::SYNC_CREATE | glib::BindingFlags::BIDIRECTIONAL)
.build();
priv_.listview.set_model(Some(&selection));
}
- fn set_selected_room(&self, selected_room: Option<Room>) {
+ pub fn set_selected_item(&self, selected_item: Option<glib::Object>) {
let priv_ = imp::Sidebar::from_instance(self);
- if self.selected_room() == selected_room {
+ if self.selected_item() == selected_item {
return;
}
- priv_.selected_room.replace(selected_room);
- self.notify("selected-room");
+ priv_.selected_item.replace(selected_item);
+ self.notify("selected-item");
}
pub fn user(&self) -> Option<User> {
diff --git a/src/session/sidebar/row.rs b/src/session/sidebar/row.rs
index 2bf7f87f..d993d91e 100644
--- a/src/session/sidebar/row.rs
+++ b/src/session/sidebar/row.rs
@@ -3,7 +3,8 @@ use gtk::{glib, subclass::prelude::*};
use crate::session::{
room::Room,
- sidebar::{Category, CategoryRow, Entry, EntryRow, RoomRow},
+ sidebar::{Category, CategoryRow, Entry, EntryRow, RoomRow, VerificationRow},
+ verification::IdentityVerification,
};
mod imp {
@@ -166,6 +167,22 @@ impl Row {
if let Some(list_item) = self.parent() {
list_item.set_css_classes(&["entry"]);
}
+ } else if let Some(verification) = item.downcast_ref::<IdentityVerification>() {
+ let child = if let Some(Ok(child)) =
+ self.child().map(|w| w.downcast::<VerificationRow>())
+ {
+ child
+ } else {
+ let child = VerificationRow::new();
+ self.set_child(Some(&child));
+ child
+ };
+
+ child.set_identity_verification(Some(verification.clone()));
+
+ if let Some(list_item) = self.parent() {
+ list_item.set_css_classes(&["room"]);
+ }
} else {
panic!("Wrong row item: {:?}", item);
}
diff --git a/src/session/sidebar/selection.rs b/src/session/sidebar/selection.rs
index 544b6bf2..a0fc77b5 100644
--- a/src/session/sidebar/selection.rs
+++ b/src/session/sidebar/selection.rs
@@ -1,7 +1,5 @@
use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*};
-use crate::session::{content::ContentType, room::Room, sidebar::Entry};
-
mod imp {
use super::*;
use once_cell::sync::Lazy;
@@ -57,14 +55,6 @@ mod imp {
glib::Object::static_type(),
glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
- glib::ParamSpec::new_enum(
- "selected-type",
- "Selected Type",
- "The currently selected content type",
- ContentType::static_type(),
- ContentType::default() as i32,
- glib::ParamFlags::READWRITE | glib::ParamFlags::EXPLICIT_NOTIFY,
- ),
]
});
@@ -88,7 +78,6 @@ mod imp {
obj.set_selected(selected);
}
"selected-item" => obj.set_selected_item(value.get().unwrap()),
- "selected-type" => obj.set_selected_type(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -98,7 +87,6 @@ mod imp {
"model" => obj.model().to_value(),
"selected" => obj.selected().to_value(),
"selected-item" => obj.selected_item().to_value(),
- "selected-type" => obj.selected_type().to_value(),
_ => unimplemented!(),
}
}
@@ -169,74 +157,6 @@ impl Selection {
priv_.selected_item.borrow().clone()
}
- pub fn selected_type(&self) -> ContentType {
- if let Some(item) = self.selected_item() {
- if item.is::<Room>() {
- return ContentType::Room;
- } else if let Ok(entry) = item.downcast::<Entry>() {
- return entry.type_();
- }
- }
-
- ContentType::None
- }
-
- pub fn set_selected_type(&self, selected_type: ContentType) {
- let priv_ = imp::Selection::from_instance(self);
-
- if self.selected_type() == selected_type {
- return;
- }
-
- match selected_type {
- ContentType::None => self.set_selected_item(None),
- ContentType::Room => {
- if self
- .selected_item()
- .and_then(|item| item.downcast::<Room>().ok())
- .is_none()
- {
- if let Some(model) = &*priv_.model.borrow() {
- for i in 0..model.n_items() {
- if let Some(room) = model
- .item(i)
- .and_then(|item| item.downcast::<gtk::TreeListRow>().ok())
- .and_then(|i| i.item())
- .and_then(|o| o.downcast::<Room>().ok())
- {
- self.set_selected_item(Some(room.upcast()));
- break;
- }
- }
- }
- }
- }
- ContentType::Explore => {
- if !self
- .selected_item()
- .and_then(|item| item.downcast::<Entry>().ok())
- .map_or(false, |entry| entry.type_() == selected_type)
- {
- if let Some(model) = &*priv_.model.borrow() {
- for i in 0..model.n_items() {
- if let Some(entry) = model
- .item(i)
- .and_then(|item| item.downcast::<gtk::TreeListRow>().ok())
- .and_then(|i| i.item())
- .and_then(|o| o.downcast::<Entry>().ok())
- {
- if entry.type_() == selected_type {
- self.set_selected_item(Some(entry.upcast()));
- break;
- }
- }
- }
- }
- }
- }
- };
- }
-
pub fn set_model<P: IsA<gio::ListModel>>(&self, model: Option<&P>) {
let priv_ = imp::Selection::from_instance(self);
@@ -279,7 +199,6 @@ impl Selection {
}
if self.selected_item().is_some() {
priv_.selected_item.replace(None);
- self.notify("selected-type");
self.notify("selected-item");
}
@@ -328,7 +247,6 @@ impl Selection {
self.notify("selected");
self.notify("selected-item");
- self.notify("selected-type");
}
fn set_selected_item(&self, item: Option<glib::Object>) {
@@ -376,7 +294,6 @@ impl Selection {
}
self.notify("selected-item");
- self.notify("selected-type");
}
fn items_changed_cb(&self, model: &gio::ListModel, position: u32, removed: u32, added: u32) {
diff --git a/src/session/sidebar/verification_row.rs b/src/session/sidebar/verification_row.rs
new file mode 100644
index 00000000..fdc30c3d
--- /dev/null
+++ b/src/session/sidebar/verification_row.rs
@@ -0,0 +1,104 @@
+use adw::subclass::prelude::BinImpl;
+use gtk::{glib, prelude::*, subclass::prelude::*, CompositeTemplate};
+
+use crate::session::verification::IdentityVerification;
+
+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/sidebar-verification-row.ui")]
+ pub struct VerificationRow {
+ pub verification: RefCell<Option<IdentityVerification>>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for VerificationRow {
+ const NAME: &'static str = "SidebarVerificationRow";
+ type Type = super::VerificationRow;
+ 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 VerificationRow {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::new_object(
+ "identity-verification",
+ "Identity Verification",
+ "The identity verification of this row",
+ IdentityVerification::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() {
+ "identity-verification" => obj.set_identity_verification(value.get().unwrap()),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "identity-verification" => obj.identity_verification().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+ }
+
+ impl WidgetImpl for VerificationRow {}
+ impl BinImpl for VerificationRow {}
+}
+
+glib::wrapper! {
+ pub struct VerificationRow(ObjectSubclass<imp::VerificationRow>)
+ @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
+}
+
+impl VerificationRow {
+ pub fn new() -> Self {
+ glib::Object::new(&[]).expect("Failed to create VerificationRow")
+ }
+
+ pub fn identity_verification(&self) -> Option<IdentityVerification> {
+ let priv_ = imp::VerificationRow::from_instance(self);
+ priv_.verification.borrow().clone()
+ }
+
+ pub fn set_identity_verification(&self, verification: Option<IdentityVerification>) {
+ let priv_ = imp::VerificationRow::from_instance(self);
+
+ if self.identity_verification() == verification {
+ return;
+ }
+
+ priv_.verification.replace(verification);
+ self.notify("identity-verification");
+ }
+}
+
+impl Default for VerificationRow {
+ fn default() -> Self {
+ Self::new()
+ }
+}
diff --git a/src/session/verification/identity_verification.rs
b/src/session/verification/identity_verification.rs
index a2abc07e..53ccdb5d 100644
--- a/src/session/verification/identity_verification.rs
+++ b/src/session/verification/identity_verification.rs
@@ -130,6 +130,13 @@ mod imp {
Mode::default() as i32,
glib::ParamFlags::READABLE | glib::ParamFlags::EXPLICIT_NOTIFY,
),
+ glib::ParamSpec::new_string(
+ "display-name",
+ "Display name",
+ "The display name of this verificaiton request",
+ None,
+ glib::ParamFlags::READABLE | glib::ParamFlags::EXPLICIT_NOTIFY,
+ ),
]
});
@@ -153,6 +160,7 @@ mod imp {
match pspec.name() {
"user" => obj.user().to_value(),
"mode" => obj.mode().to_value(),
+ "display-name" => obj.display_name().to_value(),
_ => unimplemented!(),
}
}
@@ -283,6 +291,11 @@ impl IdentityVerification {
priv_.request.replace(request);
}
+ pub fn display_name(&self) -> String {
+ // TODO: give this request a name based on the device
+ "Request".to_string()
+ }
+
/// Get the QrCode for this verification request
///
/// This is only set once the request reached the `State::Ready`
diff --git a/src/session/verification/mod.rs b/src/session/verification/mod.rs
index ba2e3074..9fc05594 100644
--- a/src/session/verification/mod.rs
+++ b/src/session/verification/mod.rs
@@ -1,9 +1,9 @@
mod emoji;
mod identity_verification;
mod session_verification;
-mod to_device_handler;
+mod verification_list;
pub use self::emoji::Emoji;
pub use self::identity_verification::{IdentityVerification, Mode as VerificationMode};
pub use self::session_verification::SessionVerification;
-pub use self::to_device_handler::ToDeviceHandler;
+pub use self::verification_list::VerificationList;
diff --git a/src/session/verification/verification_list.rs b/src/session/verification/verification_list.rs
new file mode 100644
index 00000000..f3d73421
--- /dev/null
+++ b/src/session/verification/verification_list.rs
@@ -0,0 +1,123 @@
+use gtk::{gio, glib, prelude::*, subclass::prelude::*};
+use matrix_sdk::ruma::{api::client::r0::sync::sync_events::ToDevice, events::AnyToDeviceEvent};
+
+use crate::session::{verification::IdentityVerification, Session};
+
+mod imp {
+ use glib::object::WeakRef;
+ use once_cell::{sync::Lazy, unsync::OnceCell};
+ use std::cell::RefCell;
+
+ use super::*;
+
+ #[derive(Debug, Default)]
+ pub struct VerificationList {
+ pub list: RefCell<Vec<IdentityVerification>>,
+ pub session: OnceCell<WeakRef<Session>>,
+ }
+
+ #[glib::object_subclass]
+ impl ObjectSubclass for VerificationList {
+ const NAME: &'static str = "VerificationList";
+ type Type = super::VerificationList;
+ type ParentType = glib::Object;
+ type Interfaces = (gio::ListModel,);
+ }
+
+ impl ObjectImpl for VerificationList {
+ fn properties() -> &'static [glib::ParamSpec] {
+ static PROPERTIES: Lazy<Vec<glib::ParamSpec>> = Lazy::new(|| {
+ vec![glib::ParamSpec::new_object(
+ "session",
+ "Session",
+ "The session",
+ Session::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+ )]
+ });
+
+ PROPERTIES.as_ref()
+ }
+
+ fn set_property(
+ &self,
+ _obj: &Self::Type,
+ _id: usize,
+ value: &glib::Value,
+ pspec: &glib::ParamSpec,
+ ) {
+ match pspec.name() {
+ "session" => self
+ .session
+ .set(value.get::<Session>().unwrap().downgrade())
+ .unwrap(),
+ _ => unimplemented!(),
+ }
+ }
+
+ fn property(&self, obj: &Self::Type, _id: usize, pspec: &glib::ParamSpec) -> glib::Value {
+ match pspec.name() {
+ "session" => obj.session().to_value(),
+ _ => unimplemented!(),
+ }
+ }
+ }
+
+ impl ListModelImpl for VerificationList {
+ fn item_type(&self, _list_model: &Self::Type) -> glib::Type {
+ IdentityVerification::static_type()
+ }
+ fn n_items(&self, _list_model: &Self::Type) -> u32 {
+ self.list.borrow().len() as u32
+ }
+ fn item(&self, _list_model: &Self::Type, position: u32) -> Option<glib::Object> {
+ self.list
+ .borrow()
+ .get(position as usize)
+ .map(glib::object::Cast::upcast_ref::<glib::Object>)
+ .cloned()
+ }
+ }
+}
+
+glib::wrapper! {
+ pub struct VerificationList(ObjectSubclass<imp::VerificationList>)
+ @implements gio::ListModel;
+}
+
+impl VerificationList {
+ pub fn new(session: &Session) -> Self {
+ glib::Object::new(&[("session", session)]).expect("Failed to create VerificationList")
+ }
+
+ pub fn session(&self) -> Session {
+ let priv_ = imp::VerificationList::from_instance(self);
+ priv_.session.get().unwrap().upgrade().unwrap()
+ }
+
+ pub fn handle_response_to_device(&self, to_device: ToDevice) {
+ let priv_ = imp::VerificationList::from_instance(self);
+
+ for event in &to_device.events {
+ if let Ok(AnyToDeviceEvent::KeyVerificationRequest(_event)) = event.deserialize() {
+ //TODO: implement handling of incomming requests
+ }
+ }
+
+ for verification in &*priv_.list.borrow() {
+ verification.handle_response_to_device(to_device.clone());
+ }
+ }
+
+ /// Add a new `IdentityVerification` request
+ pub fn add(&self, request: IdentityVerification) {
+ let priv_ = imp::VerificationList::from_instance(self);
+ let length = {
+ let mut list = priv_.list.borrow_mut();
+ let length = list.len();
+ list.push(request);
+ length as u32
+ };
+ self.items_changed(length, 0, 1)
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]