From b601f159ad1d26449c13ac62a5e0b8d21acf48a1 Mon Sep 17 00:00:00 2001 From: Julian Sparber Date: Wed, 24 Mar 2021 12:05:21 +0100 Subject: [PATCH] session: Add Supervisor aka EventHandler The Supervisor implements `matrix_sdk::EventHanlder` and forwards events to via channels so we can update the UI. --- src/meson.build | 1 + src/session/content.rs | 13 +++++- src/session/mod.rs | 9 ++++ src/session/sidebar.rs | 13 +++++- src/session/supervisor.rs | 90 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 2 deletions(-) create mode 100644 src/session/supervisor.rs diff --git a/src/meson.build b/src/meson.build index d03ab188..27d6c064 100644 --- a/src/meson.build +++ b/src/meson.build @@ -28,6 +28,7 @@ sources = files( 'session/mod.rs', 'session/content.rs', 'session/sidebar.rs', + 'session/supervisor.rs', ) custom_target( diff --git a/src/session/content.rs b/src/session/content.rs index 112a3c48..eab6b0b9 100644 --- a/src/session/content.rs +++ b/src/session/content.rs @@ -2,7 +2,8 @@ use adw; use adw::subclass::prelude::BinImpl; use gtk::subclass::prelude::*; use gtk::{self, prelude::*}; -use gtk::{glib, CompositeTemplate}; +use gtk::{glib, glib::SyncSender, CompositeTemplate}; +use matrix_sdk::identifiers::RoomId; mod imp { use super::*; @@ -102,4 +103,14 @@ impl FrctlContent { pub fn new() -> Self { glib::Object::new(&[]).expect("Failed to create FrctlContent") } + + /// Sets up the required channel to recive async updates from the `Client` + pub fn setup_channel(&self) -> SyncSender { + let (sender, receiver) = glib::MainContext::sync_channel::(Default::default(), 100); + receiver.attach(None, move |_room_id| { + //TODO: actually do something: update the message GListModel + glib::Continue(true) + }); + sender + } } diff --git a/src/session/mod.rs b/src/session/mod.rs index 9f38105a..a131c9e8 100644 --- a/src/session/mod.rs +++ b/src/session/mod.rs @@ -1,8 +1,10 @@ mod content; mod sidebar; +mod supervisor; use self::content::FrctlContent; use self::sidebar::FrctlSidebar; +use self::supervisor::Supervisor; use crate::secret; use crate::RUNTIME; @@ -169,8 +171,15 @@ impl FrctlSession { let client = client.unwrap(); + let sidebar_sender = priv_.sidebar.get().setup_channel(); + let content_sender = priv_.content.get().setup_channel(); + + let handler = Supervisor::new(sidebar_sender, content_sender); + RUNTIME.block_on(async { tokio::spawn(async move { + client.set_event_handler(Box::new(handler)).await; + let success = match method { CreationMethod::SessionRestore(session) => { let res = client.restore_login(session).await; diff --git a/src/session/sidebar.rs b/src/session/sidebar.rs index 10a9c4df..19396b39 100644 --- a/src/session/sidebar.rs +++ b/src/session/sidebar.rs @@ -2,7 +2,8 @@ use adw; use adw::subclass::prelude::BinImpl; use gtk::subclass::prelude::*; use gtk::{self, prelude::*}; -use gtk::{glib, CompositeTemplate}; +use gtk::{glib, glib::SyncSender, CompositeTemplate}; +use matrix_sdk::{identifiers::RoomId, Client}; mod imp { use super::*; @@ -102,4 +103,14 @@ impl FrctlSidebar { pub fn new() -> Self { glib::Object::new(&[]).expect("Failed to create FrctlSidebar") } + + /// Sets up the required channel to recive async updates from the `Client` + pub fn setup_channel(&self) -> SyncSender { + let (sender, receiver) = glib::MainContext::sync_channel::(Default::default(), 100); + receiver.attach(None, move |_room_id| { + //TODO: actually do something: update the message GListModel + glib::Continue(true) + }); + sender + } } diff --git a/src/session/supervisor.rs b/src/session/supervisor.rs new file mode 100644 index 00000000..70c4fcd6 --- /dev/null +++ b/src/session/supervisor.rs @@ -0,0 +1,90 @@ +use gtk::glib; +use gtk_macros::send; +use log::error; +use matrix_sdk::{ + self, async_trait, + events::{ + room::{ + aliases::AliasesEventContent, avatar::AvatarEventContent, + canonical_alias::CanonicalAliasEventContent, join_rules::JoinRulesEventContent, + message::MessageEventContent, name::NameEventContent, tombstone::TombstoneEventContent, + }, + SyncMessageEvent, SyncStateEvent, + }, + identifiers::RoomId, + room::Room, + CustomEvent, EventHandler, +}; +use serde_json::value::RawValue as RawJsonValue; +use std::sync::{Arc, RwLock}; + +/// The `Supervisor` implements the `matrix_sdk::EventHandler`. +/// +/// The idea is that the `Supervisor` sends a message to a `channel` when a matrix event is +/// received. +/// Every major UI component should provide a `glib::SyncSender` where `T` is the message the UI +/// compnent excpects to receive for a matrix event. +/// +pub struct Supervisor { + sidebar: glib::SyncSender, + // TODO: figure out what infromation the content actually needs and should receive from an + // event + content: glib::SyncSender, + /// The ID of the room we want to receive updates for in the content, this is usually the + /// user visible room. + pub room_of_intressed: Arc>>, +} + +impl Supervisor { + pub fn new(sidebar: glib::SyncSender, content: glib::SyncSender) -> Self { + Self { + sidebar, + content, + room_of_intressed: Arc::new(RwLock::new(None)), + } + } +} + +#[async_trait] +impl EventHandler for Supervisor { + async fn on_room_name(&self, room: Room, _: &SyncStateEvent) { + send!(self.sidebar, room.room_id().clone()); + } + + async fn on_room_canonical_alias( + &self, + room: Room, + _: &SyncStateEvent, + ) { + send!(self.sidebar, room.room_id().clone()); + } + + async fn on_room_aliases(&self, room: Room, _: &SyncStateEvent) { + send!(self.sidebar, room.room_id().clone()); + } + + async fn on_room_avatar(&self, room: Room, _: &SyncStateEvent) { + send!(self.sidebar, room.room_id().clone()); + } + + async fn on_room_message(&self, room: Room, _: &SyncMessageEvent) { + // TODO: get the correct event for new notification count + send!(self.sidebar, room.room_id().clone()); + send!(self.content, room.room_id().clone()); + } + async fn on_room_join_rules(&self, room: Room, _: &SyncStateEvent) { + send!(self.sidebar, room.room_id().clone()); + } + + async fn on_room_tombstone(&self, room: Room, _: &SyncStateEvent) { + send!(self.sidebar, room.room_id().clone()); + } + + async fn on_unrecognized_event(&self, room: Room, _: &RawJsonValue) { + send!(self.sidebar, room.room_id().clone()); + } + + async fn on_custom_event(&self, room: Room, _: &CustomEvent<'_>) { + send!(self.sidebar, room.room_id().clone()); + } +}