[fractal/ui-refactor: 7/15] Use AppRuntime for better ergonomics for the reactive loop
- From: Alejandro Domínguez <aledomu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/ui-refactor: 7/15] Use AppRuntime for better ergonomics for the reactive loop
- Date: Wed, 2 Dec 2020 16:51:50 +0000 (UTC)
commit 3da717eb9a02e3918251e1b7d50c431a5fd5f20d
Author: Alejandro Domínguez <adomu net-c com>
Date: Thu Oct 15 10:43:14 2020 +0200
Use AppRuntime for better ergonomics for the reactive loop
fractal-gtk/src/actions/account_settings.rs | 10 +--
fractal-gtk/src/actions/global.rs | 24 +++----
fractal-gtk/src/actions/message.rs | 74 ++++++++++-----------
fractal-gtk/src/app/mod.rs | 65 +++++++++++--------
fractal-gtk/src/appop/account.rs | 2 +-
fractal-gtk/src/appop/connect/account.rs | 40 ++++++------
fractal-gtk/src/appop/connect/direct.rs | 32 ++++-----
fractal-gtk/src/appop/connect/directory.rs | 14 ++--
fractal-gtk/src/appop/connect/invite.rs | 82 ++++++++++++------------
fractal-gtk/src/appop/connect/join_room.rs | 8 +--
fractal-gtk/src/appop/connect/language.rs | 26 ++++----
fractal-gtk/src/appop/connect/leave_room.rs | 4 +-
fractal-gtk/src/appop/connect/markdown.rs | 14 ++--
fractal-gtk/src/appop/connect/new_room.rs | 8 +--
fractal-gtk/src/appop/connect/roomlist_search.rs | 4 +-
fractal-gtk/src/appop/connect/send.rs | 12 ++--
fractal-gtk/src/appop/media_viewer.rs | 3 +-
fractal-gtk/src/appop/mod.rs | 8 +--
fractal-gtk/src/appop/room.rs | 3 +-
19 files changed, 224 insertions(+), 209 deletions(-)
---
diff --git a/fractal-gtk/src/actions/account_settings.rs b/fractal-gtk/src/actions/account_settings.rs
index 04cd63da..5dfe7322 100644
--- a/fractal-gtk/src/actions/account_settings.rs
+++ b/fractal-gtk/src/actions/account_settings.rs
@@ -5,14 +5,14 @@ use gio::SimpleAction;
use gio::SimpleActionGroup;
use glib::clone;
-use crate::app::{UpdateApp, RUNTIME};
+use crate::app::{AppRuntime, RUNTIME};
use crate::widgets::FileDialog::open;
use crate::actions::ButtonState;
// This creates all actions a user can perform in the account settings
-pub fn new(window: >k::Window, app_tx: glib::Sender<UpdateApp>) -> gio::SimpleActionGroup {
+pub fn new(window: >k::Window, app_runtime: AppRuntime) -> gio::SimpleActionGroup {
let actions = SimpleActionGroup::new();
// TODO create two stats loading interaction and connect it to the avatar box
let change_avatar =
@@ -21,9 +21,9 @@ pub fn new(window: >k::Window, app_tx: glib::Sender<UpdateApp>) -> gio::Simple
actions.add_action(&change_avatar);
change_avatar.connect_activate(clone!(@weak window => move |a, _| {
- let _ = app_tx.send(Box::new(clone!(@weak a => move |op| {
+ app_runtime.update_state_with(clone!(@weak a => move |state| {
let (session_client, uid) = unwrap_or_unit_return!(
- op.login_data.as_ref().map(|ld| (ld.session_client.clone(), ld.uid.clone()))
+ state.login_data.as_ref().map(|ld| (ld.session_client.clone(), ld.uid.clone()))
);
let filter = gtk::FileFilter::new();
@@ -42,7 +42,7 @@ pub fn new(window: >k::Window, app_tx: glib::Sender<UpdateApp>) -> gio::Simple
}
});
}
- })));
+ }));
}));
actions
diff --git a/fractal-gtk/src/actions/global.rs b/fractal-gtk/src/actions/global.rs
index 9f3f1a9a..0c24ff37 100644
--- a/fractal-gtk/src/actions/global.rs
+++ b/fractal-gtk/src/actions/global.rs
@@ -4,7 +4,7 @@ use std::convert::TryInto;
use std::rc::Rc;
use std::sync::{Arc, Mutex};
-use crate::app::UpdateApp;
+use crate::app::AppRuntime;
use crate::appop::AppOp;
use crate::model::message::Message;
use crate::util::i18n::i18n;
@@ -65,7 +65,7 @@ impl From<AppState> for glib::Variant {
/* This creates globale actions which are connected to the application */
/* TODO: Remove op */
-pub fn new(app: >k::Application, app_tx: glib::Sender<UpdateApp>, op: &Arc<Mutex<AppOp>>) {
+pub fn new(app: >k::Application, app_runtime: AppRuntime, op: &Arc<Mutex<AppOp>>) {
let settings = SimpleAction::new("settings", None);
let chat = SimpleAction::new("start_chat", None);
let newr = SimpleAction::new("new_room", None);
@@ -267,7 +267,7 @@ pub fn new(app: >k::Application, app_tx: glib::Sender<UpdateApp>, op: &Arc<Mut
media_viewer.connect_activate(clone!(
@weak back_history as back
=> move |_, data| {
- open_viewer(&app_tx, data.cloned());
+ open_viewer(&app_runtime, data.cloned());
back.borrow_mut().push(AppState::MediaViewer);
}));
@@ -382,24 +382,24 @@ pub(super) fn get_message_by_id(op: &AppOp, id: &EventId) -> Option<Message> {
op.get_message_by_id(room_id, id)
}
-fn open_viewer(app_tx: &glib::Sender<UpdateApp>, data: Option<glib::Variant>) {
- let _ = app_tx.send(Box::new(move |op| {
+fn open_viewer(app_runtime: &AppRuntime, data: Option<glib::Variant>) {
+ app_runtime.update_state_with(move |state| {
if let Some(msg) = get_event_id(data.as_ref())
.as_ref()
- .and_then(|evid| get_message_by_id(op, evid))
+ .and_then(|evid| get_message_by_id(state, evid))
{
- op.create_media_viewer(msg);
+ state.create_media_viewer(msg);
}
- }));
+ });
}
pub fn activate_action(
- app_tx: &glib::Sender<UpdateApp>,
+ app_runtime: &AppRuntime,
action_group_name: &'static str,
action_name: &'static str,
) {
- let _ = app_tx.send(Box::new(move |op| {
- let main_window = op
+ app_runtime.update_state_with(move |state| {
+ let main_window = state
.ui
.builder
.get_object::<gtk::Window>("main_window")
@@ -407,5 +407,5 @@ pub fn activate_action(
if let Some(action_group) = main_window.get_action_group(action_group_name) {
action_group.activate_action(action_name, None);
}
- }));
+ });
}
diff --git a/fractal-gtk/src/actions/message.rs b/fractal-gtk/src/actions/message.rs
index 319f4d22..cc63cf04 100644
--- a/fractal-gtk/src/actions/message.rs
+++ b/fractal-gtk/src/actions/message.rs
@@ -8,7 +8,7 @@ use std::process::Command;
use std::rc::Rc;
use crate::actions::AppState;
-use crate::app::{UpdateApp, RUNTIME};
+use crate::app::{AppRuntime, RUNTIME};
use crate::appop::AppOp;
use crate::backend::HandleError;
use crate::model::message::Message;
@@ -28,7 +28,7 @@ use crate::widgets::SourceDialog;
/* This creates all actions the room history can perform */
pub fn new(
- app_tx: glib::Sender<UpdateApp>,
+ app_runtime: AppRuntime,
ui: UI,
back_history: Rc<RefCell<Vec<AppState>>>,
) -> gio::SimpleActionGroup {
@@ -59,18 +59,18 @@ pub fn new(
.builder
.get_object("main_window")
.expect("Can't find main_window in ui file.");
- show_source.connect_activate(clone!(@weak parent, @strong app_tx => move |_, data| {
+ show_source.connect_activate(clone!(@weak parent, @strong app_runtime => move |_, data| {
let viewer = SourceDialog::new();
viewer.set_parent_window(&parent);
let data = data.cloned();
- let _ = app_tx.send(Box::new(move |op| {
- if let Some(m) = get_message(op, data.as_ref()) {
+ app_runtime.update_state_with(move |state| {
+ if let Some(m) = get_message(state, data.as_ref()) {
let error = i18n("This message has no source.");
let source = m.source.as_ref().unwrap_or(&error);
viewer.show(source);
}
- }));
+ });
}));
let window = ui
@@ -81,7 +81,7 @@ pub fn new(
@weak back_history,
@weak window,
@weak ui.sventry.view as msg_entry,
- @strong app_tx
+ @strong app_runtime
=> move |_, data| {
let state = back_history.borrow().last().cloned();
if let Some(AppState::MediaViewer) = state {
@@ -94,8 +94,8 @@ pub fn new(
if let Some(buffer) = msg_entry.get_buffer() {
let mut start = buffer.get_start_iter();
let data = data.cloned();
- let _ = app_tx.send(Box::new(move |op| {
- if let Some(m) = get_message(op, data.as_ref()) {
+ app_runtime.update_state_with(move |state| {
+ if let Some(m) = get_message(state, data.as_ref()) {
let quote = m
.body
.lines()
@@ -107,16 +107,16 @@ pub fn new(
buffer.insert(&mut start, "e);
msg_entry.grab_focus();
}
- }));
+ });
}
}));
- open_with.connect_activate(clone!(@strong app_tx => move |_, data| {
+ open_with.connect_activate(clone!(@strong app_runtime => move |_, data| {
let data = data.cloned();
- let _ = app_tx.send(Box::new(move |op| {
- let url = unwrap_or_unit_return!(get_message(op, data.as_ref()).and_then(|m| m.url));
+ app_runtime.update_state_with(move |state| {
+ let url = unwrap_or_unit_return!(get_message(state, data.as_ref()).and_then(|m| m.url));
let session_client =
- unwrap_or_unit_return!(op.login_data.as_ref().map(|ld| ld.session_client.clone()));
+ unwrap_or_unit_return!(state.login_data.as_ref().map(|ld| ld.session_client.clone()));
RUNTIME.spawn(async move {
match dw_media(session_client, &url, ContentType::Download, None).await {
Ok(fname) => {
@@ -128,18 +128,18 @@ pub fn new(
Err(err) => err.handle_error(),
}
});
- }));
+ });
}));
save_as.connect_activate(
- clone!(@weak parent as window, @strong app_tx => move |_, data| {
+ clone!(@weak parent as window, @strong app_runtime => move |_, data| {
let data = data.cloned();
- let _ = app_tx.send(Box::new(move |op| {
+ app_runtime.update_state_with(move |state| {
let (url, name) = unwrap_or_unit_return!(
- get_message(op, data.as_ref()).and_then(|m| Some((m.url?, m.body)))
+ get_message(state, data.as_ref()).and_then(|m| Some((m.url?, m.body)))
);
let session_client = unwrap_or_unit_return!(
- op.login_data.as_ref().map(|ld| ld.session_client.clone())
+ state.login_data.as_ref().map(|ld| ld.session_client.clone())
);
let response = RUNTIME.spawn(async move {
media::get_media(session_client, &url).await
@@ -164,16 +164,16 @@ pub fn new(
}
}
});
- }));
+ });
}),
);
- copy_image.connect_activate(clone!(@strong app_tx => move |_, data| {
+ copy_image.connect_activate(clone!(@strong app_runtime => move |_, data| {
let data = data.cloned();
- let _ = app_tx.send(Box::new(move |op| {
- let url = unwrap_or_unit_return!(get_message(op, data.as_ref()).and_then(|m| m.url));
+ app_runtime.update_state_with(move |state| {
+ let url = unwrap_or_unit_return!(get_message(state, data.as_ref()).and_then(|m| m.url));
let session_client =
- unwrap_or_unit_return!(op.login_data.as_ref().map(|ld| ld.session_client.clone()));
+ unwrap_or_unit_return!(state.login_data.as_ref().map(|ld| ld.session_client.clone()));
let response =
RUNTIME.spawn(async move { media::get_media(session_client, &url).await });
@@ -195,25 +195,25 @@ pub fn new(
}
}
});
- }));
+ });
}));
- copy_text.connect_activate(clone!(@strong app_tx => move |_, data| {
+ copy_text.connect_activate(clone!(@strong app_runtime => move |_, data| {
let data = data.cloned();
- let _ = app_tx.send(Box::new(move |op| {
- if let Some(m) = get_message(op, data.as_ref()) {
+ app_runtime.update_state_with(move |state| {
+ if let Some(m) = get_message(state, data.as_ref()) {
let atom = gdk::Atom::intern("CLIPBOARD");
let clipboard = gtk::Clipboard::get(&atom);
clipboard.set_text(&m.body);
}
- }));
+ });
}));
delete.connect_activate(clone!(
@weak back_history,
@weak window,
- @strong app_tx
+ @strong app_runtime
=> move |_, data| {
let state = back_history.borrow().last().cloned();
if let Some(AppState::MediaViewer) = state {
@@ -224,10 +224,10 @@ pub fn new(
}
}
let data = data.cloned();
- let _ = app_tx.send(Box::new(move |op| {
- let msg = unwrap_or_unit_return!(get_message(op, data.as_ref()));
+ app_runtime.update_state_with(move |state| {
+ let msg = unwrap_or_unit_return!(get_message(state, data.as_ref()));
let session_client = unwrap_or_unit_return!(
- op.login_data.as_ref().map(|ld| ld.session_client.clone())
+ state.login_data.as_ref().map(|ld| ld.session_client.clone())
);
RUNTIME.spawn(async move {
let query = room::redact_msg(session_client, msg).await;
@@ -235,15 +235,15 @@ pub fn new(
err.handle_error();
}
});
- }));
+ });
}));
load_more_messages.connect_activate(move |_, data| {
let data = data.cloned();
- let _ = app_tx.send(Box::new(move |op| {
+ app_runtime.update_state_with(move |state| {
let id = get_room_id(data.as_ref());
- request_more_messages(op, id);
- }));
+ request_more_messages(state, id);
+ });
});
actions
diff --git a/fractal-gtk/src/app/mod.rs b/fractal-gtk/src/app/mod.rs
index 5af5efa8..bec097b1 100644
--- a/fractal-gtk/src/app/mod.rs
+++ b/fractal-gtk/src/app/mod.rs
@@ -22,12 +22,11 @@ mod windowstate;
use windowstate::WindowState;
-type GlobalAppOp = Arc<Mutex<AppOp>>;
-pub type UpdateApp = Box<dyn FnOnce(&mut AppOp)>;
+type GlobalState = Arc<Mutex<AppOp>>;
-static mut APP_TX: Option<glib::Sender<UpdateApp>> = None;
+static mut APP_RUNTIME: Option<AppRuntime> = None;
// TODO: Deprecated. It should be removed
-static mut OP: Option<GlobalAppOp> = None;
+static mut OP: Option<GlobalState> = None;
lazy_static! {
pub static ref RUNTIME: TokioRuntime = TokioRuntime::new().unwrap();
@@ -37,15 +36,42 @@ lazy_static! {
macro_rules! APPOP {
($fn: ident, ($($x:ident),*) ) => {{
$( let $x = $x.clone(); )*
- let _ = crate::app::get_app_tx().send(Box::new(move |op| {
- crate::appop::AppOp::$fn(op, $($x),*);
- }));
+ crate::app::get_app_runtime().update_state_with(move |op| {
+ op.$fn($($x),*);
+ });
}};
($fn: ident) => {{
APPOP!($fn, ( ) );
}}
}
+#[derive(Clone)]
+pub struct AppRuntime(glib::Sender<Box<dyn FnOnce(&mut AppOp)>>);
+
+impl AppRuntime {
+ fn init(ui: uibuilder::UI) {
+ let (app_tx, app_rx) = glib::MainContext::channel(Default::default());
+ let app_runtime = Self(app_tx);
+ let state = AppOp::new(ui, app_runtime.clone());
+
+ unsafe {
+ OP = Some(Arc::new(Mutex::new(state)));
+ APP_RUNTIME = Some(app_runtime);
+ }
+
+ let state = get_op();
+ app_rx.attach(None, move |update_state| {
+ update_state(&mut state.lock().unwrap());
+
+ glib::Continue(true)
+ });
+ }
+
+ pub fn update_state_with(&self, update_fn: impl FnOnce(&mut AppOp) + 'static) {
+ let _ = self.0.send(Box::new(update_fn));
+ }
+}
+
// Our application struct for containing all the state we have to carry around.
// TODO: subclass gtk::Application once possible
pub struct App {
@@ -73,21 +99,8 @@ impl App {
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
- let (app_tx, app_rx) = glib::MainContext::channel(Default::default());
let ui = uibuilder::UI::new();
- let op = AppOp::new(ui.clone(), app_tx.clone());
-
- unsafe {
- OP = Some(Arc::new(Mutex::new(op)));
- APP_TX = Some(app_tx);
- }
-
- let op = get_op();
- app_rx.attach(None, move |update_op: UpdateApp| {
- update_op(&mut op.lock().unwrap());
-
- glib::Continue(true)
- });
+ AppRuntime::init(ui.clone());
ui.main_window.set_application(Some(gtk_app));
@@ -162,11 +175,11 @@ impl App {
gtk_app.set_accels_for_action("login.back", &["Escape"]);
- actions::Global::new(gtk_app, get_app_tx().clone(), get_op());
+ actions::Global::new(gtk_app, get_app_runtime().clone(), get_op());
let app = AppRef::new(Self { ui });
- let _ = get_app_tx().send(Box::new(|op| op.connect_gtk()));
+ get_app_runtime().update_state_with(|state| state.connect_gtk());
app
}
@@ -222,13 +235,13 @@ impl App {
}
// TODO: Deprecated. It should be removed
-pub fn get_op() -> &'static GlobalAppOp {
+pub fn get_op() -> &'static GlobalState {
unsafe { OP.as_ref().expect("Fatal: AppOp has not been initialized") }
}
-pub fn get_app_tx() -> &'static glib::Sender<UpdateApp> {
+pub fn get_app_runtime() -> &'static AppRuntime {
unsafe {
- APP_TX
+ APP_RUNTIME
.as_ref()
.expect("Fatal: AppRuntime has not been initialized")
}
diff --git a/fractal-gtk/src/appop/account.rs b/fractal-gtk/src/appop/account.rs
index 6e3c07e6..7b5610b3 100644
--- a/fractal-gtk/src/appop/account.rs
+++ b/fractal-gtk/src/appop/account.rs
@@ -201,7 +201,7 @@ impl AppOp {
let dialog = self.create_error_dialog(error);
dialog.connect_response(move |w, _| w.close());
dialog.show_all();
- activate_action(&self.app_tx, "app", "back");
+ activate_action(&self.app_runtime, "app", "back");
}
pub fn create_error_dialog(&self, error: String) -> gtk::MessageDialog {
diff --git a/fractal-gtk/src/appop/connect/account.rs b/fractal-gtk/src/appop/connect/account.rs
index f1e431e0..a665ab5e 100644
--- a/fractal-gtk/src/appop/connect/account.rs
+++ b/fractal-gtk/src/appop/connect/account.rs
@@ -7,7 +7,7 @@ use crate::appop::AppOp;
use crate::actions::{AccountSettings, StateExt};
pub fn connect(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let builder = &appop.ui.builder;
let cancel_password = appop
.ui
@@ -71,7 +71,7 @@ pub fn connect(appop: &AppOp) {
.expect("Can't find account_settings_delete_btn in ui file.");
let window = appop.ui.main_window.upcast_ref::<gtk::Window>();
- let actions = AccountSettings::new(&window, app_tx.clone());
+ let actions = AccountSettings::new(&window, app_runtime.clone());
let container = appop
.ui
.builder
@@ -102,11 +102,11 @@ pub fn connect(appop: &AppOp) {
}
name_entry.connect_property_text_notify(
- clone!(@strong app_tx, @strong name_btn as button => move |w| {
- let _ = app_tx.send(Box::new(clone!(@strong w, @strong button => move |op| {
+ clone!(@strong app_runtime, @strong name_btn as button => move |w| {
+ app_runtime.update_state_with(clone!(@strong w, @strong button => move |state| {
let username = w.get_text();
if !username.is_empty()
- && op
+ && state
.login_data
.as_ref()
.and_then(|login_data| login_data.username.as_ref())
@@ -117,7 +117,7 @@ pub fn connect(appop: &AppOp) {
return;
}
button.hide();
- })));
+ }));
}),
);
@@ -126,8 +126,8 @@ pub fn connect(appop: &AppOp) {
let _ = button.emit("clicked", &[]);
});
- name_btn.connect_clicked(clone!(@strong app_tx => move |_w| {
- let _ = app_tx.send(Box::new(|op| op.update_username_account_settings()));
+ name_btn.connect_clicked(clone!(@strong app_runtime => move |_w| {
+ app_runtime.update_state_with(|state| state.update_username_account_settings());
}));
/*
@@ -184,25 +184,25 @@ pub fn connect(appop: &AppOp) {
}
/* Passsword dialog */
- password_btn.connect_clicked(clone!(@strong app_tx => move |_| {
- let _ = app_tx.send(Box::new(|op| op.show_password_dialog()));
+ password_btn.connect_clicked(clone!(@strong app_runtime => move |_| {
+ app_runtime.update_state_with(|state| state.show_password_dialog());
}));
- password_dialog.connect_delete_event(clone!(@strong app_tx => move |_, _| {
- let _ = app_tx.send(Box::new(|op| op.close_password_dialog()));
+ password_dialog.connect_delete_event(clone!(@strong app_runtime => move |_, _| {
+ app_runtime.update_state_with(|state| state.close_password_dialog());
glib::signal::Inhibit(true)
}));
/* Headerbar */
- cancel_password.connect_clicked(clone!(@strong app_tx => move |_| {
- let _ = app_tx.send(Box::new(|op| op.close_password_dialog()));
+ cancel_password.connect_clicked(clone!(@strong app_runtime => move |_| {
+ app_runtime.update_state_with(|state| state.close_password_dialog());
}));
- confirm_password.connect_clicked(clone!(@strong app_tx => move |_| {
- let _ = app_tx.send(Box::new(|op| {
- op.set_new_password();
- op.close_password_dialog();
- }));
+ confirm_password.connect_clicked(clone!(@strong app_runtime => move |_| {
+ app_runtime.update_state_with(|state| {
+ state.set_new_password();
+ state.close_password_dialog();
+ });
}));
/* Body */
@@ -225,6 +225,6 @@ pub fn connect(appop: &AppOp) {
}));
destruction_btn.connect_clicked(move |_| {
- let _ = app_tx.send(Box::new(|op| op.account_destruction()));
+ app_runtime.update_state_with(|state| state.account_destruction());
});
}
diff --git a/fractal-gtk/src/appop/connect/direct.rs b/fractal-gtk/src/appop/connect/direct.rs
index eefce9e6..58eeb800 100644
--- a/fractal-gtk/src/appop/connect/direct.rs
+++ b/fractal-gtk/src/appop/connect/direct.rs
@@ -7,7 +7,7 @@ use std::sync::{Arc, Mutex};
use crate::appop::AppOp;
pub fn connect(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let cancel = appop
.ui
.builder
@@ -52,7 +52,7 @@ pub fn connect(appop: &AppOp) {
// this is used to cancel the timeout and not search for every key input. We'll wait 500ms
// without key release event to launch the search
let source_id: Arc<Mutex<Option<glib::source::SourceId>>> = Arc::new(Mutex::new(None));
- to_chat_entry.connect_key_release_event(clone!(@strong app_tx => move |entry, _| {
+ to_chat_entry.connect_key_release_event(clone!(@strong app_runtime => move |entry, _| {
{
let mut id = source_id.lock().unwrap();
if let Some(sid) = id.take() {
@@ -65,7 +65,7 @@ pub fn connect(appop: &AppOp) {
clone!(
@strong entry,
@strong source_id,
- @strong app_tx
+ @strong app_runtime
=> move || {
if let Some(buffer) = entry.get_buffer() {
let start = buffer.get_start_iter();
@@ -74,7 +74,7 @@ pub fn connect(appop: &AppOp) {
if let Some(text) =
buffer.get_text(&start, &end, false).map(|gstr| gstr.to_string())
{
- let _ = app_tx.send(Box::new(|op| op.search_invite_user(text)));
+ app_runtime.update_state_with(|state| state.search_invite_user(text));
}
}
@@ -88,43 +88,43 @@ pub fn connect(appop: &AppOp) {
}));
to_chat_entry.connect_focus_in_event(
- clone!(@strong to_chat_entry_box, @strong app_tx => move |_, _| {
+ clone!(@strong to_chat_entry_box, @strong app_runtime => move |_, _| {
to_chat_entry_box.get_style_context().add_class("message-input-focused");
- let _ = app_tx.send(Box::new(|op| op.remove_invite_user_dialog_placeholder()));
+ app_runtime.update_state_with(|state| state.remove_invite_user_dialog_placeholder());
Inhibit(false)
}),
);
to_chat_entry.connect_focus_out_event(
- clone!(@strong to_chat_entry_box, @strong app_tx => move |_, _| {
+ clone!(@strong to_chat_entry_box, @strong app_runtime => move |_, _| {
to_chat_entry_box.get_style_context().remove_class("message-input-focused");
- let _ = app_tx.send(Box::new(|op| op.set_invite_user_dialog_placeholder()));
+ app_runtime.update_state_with(|state| state.set_invite_user_dialog_placeholder());
Inhibit(false)
}),
);
if let Some(buffer) = to_chat_entry.get_buffer() {
- buffer.connect_delete_range(clone!(@strong app_tx => move |_, _, _| {
- glib::idle_add_local(clone!(@strong app_tx => move || {
- let _ = app_tx.send(Box::new(|op| op.detect_removed_invite()));
+ buffer.connect_delete_range(clone!(@strong app_runtime => move |_, _, _| {
+ glib::idle_add_local(clone!(@strong app_runtime => move || {
+ app_runtime.update_state_with(|state| state.detect_removed_invite());
Continue(false)
}));
}));
}
- dialog.connect_delete_event(clone!(@strong app_tx => move |_, _| {
- let _ = app_tx.send(Box::new(|op| op.close_direct_chat_dialog()));
+ dialog.connect_delete_event(clone!(@strong app_runtime => move |_, _| {
+ app_runtime.update_state_with(|state| state.close_direct_chat_dialog());
glib::signal::Inhibit(true)
}));
- cancel.connect_clicked(clone!(@strong app_tx => move |_| {
- let _ = app_tx.send(Box::new(|op| op.close_direct_chat_dialog()));
+ cancel.connect_clicked(clone!(@strong app_runtime => move |_| {
+ app_runtime.update_state_with(|state| state.close_direct_chat_dialog());
}));
invite.set_sensitive(false);
invite.connect_clicked(move |_| {
- let _ = app_tx.send(Box::new(|op| op.start_chat()));
+ app_runtime.update_state_with(|state| state.start_chat());
});
}
diff --git a/fractal-gtk/src/appop/connect/directory.rs b/fractal-gtk/src/appop/connect/directory.rs
index b987ccc5..3b0eb330 100644
--- a/fractal-gtk/src/appop/connect/directory.rs
+++ b/fractal-gtk/src/appop/connect/directory.rs
@@ -8,7 +8,7 @@ use libhandy::prelude::*;
use crate::appop::{AppOp, RoomSearchPagination};
pub fn connect(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let q = appop
.ui
.builder
@@ -104,17 +104,17 @@ pub fn connect(appop: &AppOp) {
.get_object::<gtk::ScrolledWindow>("directory_scroll")
.expect("Can't find directory_scroll in ui file.");
- scroll.connect_edge_reached(clone!(@strong app_tx => move |_, dir| {
+ scroll.connect_edge_reached(clone!(@strong app_runtime => move |_, dir| {
if dir == gtk::PositionType::Bottom {
- let _ = app_tx.send(Box::new(|op| op.load_more_rooms()));
+ app_runtime.update_state_with(|state| state.load_more_rooms());
}
}));
q.connect_activate(move |_| {
- let _ = app_tx.send(Box::new(|op| {
- op.directory_pagination = RoomSearchPagination::Initial;
- op.search_rooms();
- }));
+ app_runtime.update_state_with(|state| {
+ state.directory_pagination = RoomSearchPagination::Initial;
+ state.search_rooms();
+ });
});
default_matrix_server_radio.connect_toggled(clone!(
diff --git a/fractal-gtk/src/appop/connect/invite.rs b/fractal-gtk/src/appop/connect/invite.rs
index b3d23e06..9117c00b 100644
--- a/fractal-gtk/src/appop/connect/invite.rs
+++ b/fractal-gtk/src/appop/connect/invite.rs
@@ -7,7 +7,7 @@ use std::sync::{Arc, Mutex};
use crate::appop::AppOp;
pub fn connect_dialog(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let dialog = appop
.ui
.builder
@@ -24,24 +24,24 @@ pub fn connect_dialog(appop: &AppOp) {
.get_object::<gtk::Button>("invite_reject")
.expect("Can't find invite_reject in ui file.");
- reject.connect_clicked(clone!(@strong dialog, @strong app_tx => move |_| {
- let _ = app_tx.send(Box::new(|op| op.accept_inv(false)));
+ reject.connect_clicked(clone!(@strong dialog, @strong app_runtime => move |_| {
+ app_runtime.update_state_with(|state| state.accept_inv(false));
dialog.hide();
}));
- dialog.connect_delete_event(clone!(@strong dialog, @strong app_tx => move |_, _| {
- let _ = app_tx.send(Box::new(|op| op.accept_inv(false)));
+ dialog.connect_delete_event(clone!(@strong dialog, @strong app_runtime => move |_, _| {
+ app_runtime.update_state_with(|state| state.accept_inv(false));
dialog.hide();
glib::signal::Inhibit(true)
}));
accept.connect_clicked(clone!(@strong dialog => move |_| {
- let _ = app_tx.send(Box::new(|op| op.accept_inv(true)));
+ app_runtime.update_state_with(|state| state.accept_inv(true));
dialog.hide();
}));
}
pub fn connect_user(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let cancel = appop
.ui
.builder
@@ -86,73 +86,73 @@ pub fn connect_user(appop: &AppOp) {
// this is used to cancel the timeout and not search for every key input. We'll wait 500ms
// without key release event to launch the search
let source_id: Arc<Mutex<Option<glib::source::SourceId>>> = Arc::new(Mutex::new(None));
- invite_entry.connect_key_release_event(clone!(@strong app_tx => move |entry, _| {
- {
- let mut id = source_id.lock().unwrap();
- if let Some(sid) = id.take() {
- glib::source::source_remove(sid);
- }
+ invite_entry.connect_key_release_event(clone!(@strong app_runtime => move |entry, _| {
+ {
+ let mut id = source_id.lock().unwrap();
+ if let Some(sid) = id.take() {
+ glib::source::source_remove(sid);
}
+ }
- let sid = glib::timeout_add_local(
- 500,
- clone!(@strong entry, @strong source_id, @strong app_tx => move || {
- if let Some(buffer) = entry.get_buffer() {
- let start = buffer.get_start_iter();
- let end = buffer.get_end_iter();
+ let sid = glib::timeout_add_local(
+ 500,
+ clone!(@strong entry, @strong source_id, @strong app_runtime => move || {
+ if let Some(buffer) = entry.get_buffer() {
+ let start = buffer.get_start_iter();
+ let end = buffer.get_end_iter();
- if let Some(text) = buffer.get_text(&start, &end, false).map(|gstr|
gstr.to_string()) {
- let _ = app_tx.send(Box::new(|op| op.search_invite_user(text)));
- }
+ if let Some(text) = buffer.get_text(&start, &end, false).map(|gstr| gstr.to_string()) {
+ app_runtime.update_state_with(|state| state.search_invite_user(text));
}
+ }
- *(source_id.lock().unwrap()) = None;
- Continue(false)
- }),
- );
+ *(source_id.lock().unwrap()) = None;
+ Continue(false)
+ }),
+ );
- *(source_id.lock().unwrap()) = Some(sid);
- glib::signal::Inhibit(false)
- }));
+ *(source_id.lock().unwrap()) = Some(sid);
+ glib::signal::Inhibit(false)
+ }));
invite_entry.connect_focus_in_event(
- clone!(@strong invite_entry_box, @strong app_tx => move |_, _| {
+ clone!(@strong invite_entry_box, @strong app_runtime => move |_, _| {
invite_entry_box.get_style_context().add_class("message-input-focused");
- let _ = app_tx.send(Box::new(|op| op.remove_invite_user_dialog_placeholder()));
+ app_runtime.update_state_with(|state| state.remove_invite_user_dialog_placeholder());
Inhibit(false)
}),
);
invite_entry.connect_focus_out_event(
- clone!(@strong invite_entry_box, @strong app_tx => move |_, _| {
+ clone!(@strong invite_entry_box, @strong app_runtime => move |_, _| {
invite_entry_box.get_style_context().remove_class("message-input-focused");
- let _ = app_tx.send(Box::new(|op| op.set_invite_user_dialog_placeholder()));
+ app_runtime.update_state_with(|state| state.set_invite_user_dialog_placeholder());
Inhibit(false)
}),
);
if let Some(buffer) = invite_entry.get_buffer() {
- buffer.connect_delete_range(clone!(@strong app_tx => move |_, _, _| {
- glib::idle_add_local(clone!(@strong app_tx => move || {
- let _ = app_tx.send(Box::new(|op| op.detect_removed_invite()));
+ buffer.connect_delete_range(clone!(@strong app_runtime => move |_, _, _| {
+ glib::idle_add_local(clone!(@strong app_runtime => move || {
+ app_runtime.update_state_with(|state| state.detect_removed_invite());
Continue(false)
}));
}));
}
- dialog.connect_delete_event(clone!(@strong app_tx => move |_, _| {
- let _ = app_tx.send(Box::new(|op| op.close_invite_dialog()));
+ dialog.connect_delete_event(clone!(@strong app_runtime => move |_, _| {
+ app_runtime.update_state_with(|state| state.close_invite_dialog());
glib::signal::Inhibit(true)
}));
- cancel.connect_clicked(clone!(@strong app_tx => move |_| {
- let _ = app_tx.send(Box::new(|op| op.close_invite_dialog()));
+ cancel.connect_clicked(clone!(@strong app_runtime => move |_| {
+ app_runtime.update_state_with(|state| state.close_invite_dialog());
}));
invite.set_sensitive(false);
invite.connect_clicked(move |_| {
- let _ = app_tx.send(Box::new(|op| op.invite()));
+ app_runtime.update_state_with(|state| state.invite());
});
}
diff --git a/fractal-gtk/src/appop/connect/join_room.rs b/fractal-gtk/src/appop/connect/join_room.rs
index 87306933..18518801 100644
--- a/fractal-gtk/src/appop/connect/join_room.rs
+++ b/fractal-gtk/src/appop/connect/join_room.rs
@@ -4,7 +4,7 @@ use gtk::prelude::*;
use crate::appop::AppOp;
pub fn connect(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let dialog = appop
.ui
.builder
@@ -37,16 +37,16 @@ pub fn connect(appop: &AppOp) {
}));
confirm.connect_clicked(
- clone!(@strong entry, @strong dialog, @strong app_tx => move |_| {
+ clone!(@strong entry, @strong dialog, @strong app_runtime => move |_| {
dialog.hide();
- let _ = app_tx.send(Box::new(|op| op.join_to_room()));
+ app_runtime.update_state_with(|state| state.join_to_room());
entry.set_text("");
}),
);
entry.connect_activate(clone!(@strong dialog => move |entry| {
dialog.hide();
- let _ = app_tx.send(Box::new(|op| op.join_to_room()));
+ app_runtime.update_state_with(|state| state.join_to_room());
entry.set_text("");
}));
entry.connect_changed(clone!(@strong confirm => move |entry| {
diff --git a/fractal-gtk/src/appop/connect/language.rs b/fractal-gtk/src/appop/connect/language.rs
index e7f90ad1..f1915742 100644
--- a/fractal-gtk/src/appop/connect/language.rs
+++ b/fractal-gtk/src/appop/connect/language.rs
@@ -8,7 +8,7 @@ use gtk::prelude::*;
use gspell::{CheckerExt, TextBuffer, TextBufferExt as GspellTextBufferExt};
pub fn connect(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let textview = appop.ui.sventry.view.upcast_ref::<gtk::TextView>();
if let Some(checker) = textview
.get_buffer()
@@ -16,24 +16,24 @@ pub fn connect(appop: &AppOp) {
.and_then(|gs_buffer| gs_buffer.get_spell_checker())
{
let _signal_handler = checker.connect_property_language_notify(move |checker| {
- let _ = app_tx.send(Box::new(clone!(@weak checker => move |op| {
+ app_runtime.update_state_with(clone!(@weak checker => move |state| {
if let Some(lang_code) = checker
.get_language()
.and_then(|lang| lang.get_code())
.map(String::from)
{
- if let (Some(active_room), Some(login_data)) = (op.active_room.clone(),
op.login_data.as_ref()) {
- let session_client = login_data.session_client.clone();
- let uid = login_data.uid.clone();
- RUNTIME.spawn(async move {
- let query = room::set_language(session_client, &uid, &active_room,
lang_code).await;
- if let Err(err) = query {
- err.handle_error();
- }
- });
- }
+ if let (Some(active_room), Some(login_data)) = (state.active_room.clone(),
state.login_data.as_ref()) {
+ let session_client = login_data.session_client.clone();
+ let uid = login_data.uid.clone();
+ RUNTIME.spawn(async move {
+ let query = room::set_language(session_client, &uid, &active_room,
lang_code).await;
+ if let Err(err) = query {
+ err.handle_error();
+ }
+ });
+ }
}
- })));
+ }));
});
}
}
diff --git a/fractal-gtk/src/appop/connect/leave_room.rs b/fractal-gtk/src/appop/connect/leave_room.rs
index ae528b74..6c33e5c3 100644
--- a/fractal-gtk/src/appop/connect/leave_room.rs
+++ b/fractal-gtk/src/appop/connect/leave_room.rs
@@ -4,7 +4,7 @@ use gtk::prelude::*;
use crate::appop::AppOp;
pub fn connect(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let dialog = appop
.ui
.builder
@@ -31,6 +31,6 @@ pub fn connect(appop: &AppOp) {
confirm.connect_clicked(clone!(@strong dialog => move |_| {
dialog.hide();
- let _ = app_tx.send(Box::new(|op| op.really_leave_active_room()));
+ app_runtime.update_state_with(move |state| state.really_leave_active_room());
}));
}
diff --git a/fractal-gtk/src/appop/connect/markdown.rs b/fractal-gtk/src/appop/connect/markdown.rs
index dbcbd9fd..03af0a75 100644
--- a/fractal-gtk/src/appop/connect/markdown.rs
+++ b/fractal-gtk/src/appop/connect/markdown.rs
@@ -7,7 +7,7 @@ use crate::util;
use crate::appop::AppOp;
pub fn connect(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let md_popover_btn = &appop.ui.sventry.markdown;
let md_img = appop.ui.sventry.markdown_img.clone();
let buffer = appop.ui.sventry.buffer.clone();
@@ -37,9 +37,9 @@ pub fn connect(appop: &AppOp) {
let md_active = util::get_markdown_schema();
if md_active {
- let _ = app_tx.send(Box::new(|op| {
- op.md_enabled = true;
- }));
+ app_runtime.update_state_with(|state| {
+ state.md_enabled = true;
+ });
markdown_switch.set_active(true);
md_img.set_from_icon_name(Some("format-indent-more-symbolic"), gtk::IconSize::Menu);
txt.get_style_context().remove_class("dim-label");
@@ -53,9 +53,9 @@ pub fn connect(appop: &AppOp) {
markdown_switch.connect_property_active_notify(clone!(@strong markdown_switch => move |_| {
let md_active = markdown_switch.get_active();
- let _ = app_tx.send(Box::new(move |op| {
- op.md_enabled = md_active;
- }));
+ app_runtime.update_state_with(move |state| {
+ state.md_enabled = md_active;
+ });
if markdown_switch.get_active() {
md_img.set_from_icon_name(
diff --git a/fractal-gtk/src/appop/connect/new_room.rs b/fractal-gtk/src/appop/connect/new_room.rs
index aff74984..15ae479e 100644
--- a/fractal-gtk/src/appop/connect/new_room.rs
+++ b/fractal-gtk/src/appop/connect/new_room.rs
@@ -4,7 +4,7 @@ use gtk::prelude::*;
use crate::appop::AppOp;
pub fn connect(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let dialog = appop
.ui
.builder
@@ -49,9 +49,9 @@ pub fn connect(appop: &AppOp) {
);
confirm.connect_clicked(
- clone!(@strong entry, @strong dialog, @strong private, @strong app_tx => move |_| {
+ clone!(@strong entry, @strong dialog, @strong private, @strong app_runtime => move |_| {
dialog.hide();
- let _ = app_tx.send(Box::new(|op| op.create_new_room()));
+ app_runtime.update_state_with(|state| state.create_new_room());
entry.set_text("");
private.set_active(true);
}),
@@ -59,7 +59,7 @@ pub fn connect(appop: &AppOp) {
entry.connect_activate(clone!(@strong dialog => move |entry| {
dialog.hide();
- let _ = app_tx.send(Box::new(|op| op.create_new_room()));
+ app_runtime.update_state_with(|state| state.create_new_room());
entry.set_text("");
private.set_active(true);
}));
diff --git a/fractal-gtk/src/appop/connect/roomlist_search.rs
b/fractal-gtk/src/appop/connect/roomlist_search.rs
index 774eecc4..f657b6aa 100644
--- a/fractal-gtk/src/appop/connect/roomlist_search.rs
+++ b/fractal-gtk/src/appop/connect/roomlist_search.rs
@@ -4,7 +4,7 @@ use gtk::prelude::*;
use crate::appop::AppOp;
pub fn connect(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
let search_btn = appop
.ui
.builder
@@ -33,7 +33,7 @@ pub fn connect(appop: &AppOp) {
search_entry.connect_search_changed(move |entry| {
let search_text = Some(entry.get_text().to_string());
- let _ = app_tx.send(Box::new(|op| op.filter_rooms(search_text)));
+ app_runtime.update_state_with(|state| state.filter_rooms(search_text));
});
// hidding left and right boxes to align with top buttons
diff --git a/fractal-gtk/src/appop/connect/send.rs b/fractal-gtk/src/appop/connect/send.rs
index 2682a4f0..c00cdb6d 100644
--- a/fractal-gtk/src/appop/connect/send.rs
+++ b/fractal-gtk/src/appop/connect/send.rs
@@ -8,7 +8,7 @@ use crate::appop::AppOp;
const MAX_INPUT_HEIGHT: i32 = 100;
pub fn connect(appop: &AppOp) {
- let app_tx = appop.app_tx.clone();
+ let app_runtime = appop.app_runtime.clone();
appop.ui.sventry.container.set_redraw_on_allocate(true);
let msg_entry = appop.ui.sventry.view.clone();
let buffer = &appop.ui.sventry.buffer;
@@ -32,27 +32,27 @@ pub fn connect(appop: &AppOp) {
.expect("Can't find autocomplete_popover in ui file.");
msg_entry.connect_key_press_event(
- clone!(@strong app_tx => move |_, key| match key.get_keyval() {
+ clone!(@strong app_runtime => move |_, key| match key.get_keyval() {
gdk::keys::constants::Return | gdk::keys::constants::KP_Enter
if !key.get_state().contains(gdk::ModifierType::SHIFT_MASK)
&& !autocomplete_popover.is_visible() =>
{
- activate_action(&app_tx, "app", "send-message");
+ activate_action(&app_runtime, "app", "send-message");
Inhibit(true)
}
_ => Inhibit(false),
}),
);
- msg_entry.connect_key_release_event(clone!(@strong app_tx => move |_, ev| {
+ msg_entry.connect_key_release_event(clone!(@strong app_runtime => move |_, ev| {
if ev.get_keyval().to_unicode().is_some() {
- let _ = app_tx.send(Box::new(|op| op.send_typing()));
+ app_runtime.update_state_with(|state| state.send_typing());
}
Inhibit(false)
}));
msg_entry.connect_paste_clipboard(move |_| {
- let _ = app_tx.send(Box::new(|op| op.paste()));
+ app_runtime.update_state_with(|state| state.paste());
});
msg_entry.connect_focus_in_event(clone!(@strong msg_entry_box => move |_, _| {
diff --git a/fractal-gtk/src/appop/media_viewer.rs b/fractal-gtk/src/appop/media_viewer.rs
index 5e7ad473..fa3debb5 100644
--- a/fractal-gtk/src/appop/media_viewer.rs
+++ b/fractal-gtk/src/appop/media_viewer.rs
@@ -34,7 +34,8 @@ impl AppOp {
*self.media_viewer.borrow_mut() = Some(panel);
let back_history = self.room_back_history.clone();
- let actions = actions::Message::new(self.app_tx.clone(), self.ui.clone(), back_history);
+ let actions =
+ actions::Message::new(self.app_runtime.clone(), self.ui.clone(), back_history);
header.insert_action_group("message", Some(&actions));
body.insert_action_group("message", Some(&actions));
diff --git a/fractal-gtk/src/appop/mod.rs b/fractal-gtk/src/appop/mod.rs
index 46e66c78..2060ebe9 100644
--- a/fractal-gtk/src/appop/mod.rs
+++ b/fractal-gtk/src/appop/mod.rs
@@ -22,7 +22,7 @@ use crate::model::{
use crate::passwd::PasswordStorage;
use crate::actions::AppState;
-use crate::app::UpdateApp;
+use crate::app::AppRuntime;
use crate::cache;
use crate::uibuilder;
use crate::widgets;
@@ -85,7 +85,7 @@ pub struct LoginData {
}
pub struct AppOp {
- pub app_tx: glib::Sender<UpdateApp>,
+ pub app_runtime: AppRuntime,
pub ui: uibuilder::UI,
pub syncing: bool, // TODO: Replace with a Mutex
@@ -126,7 +126,7 @@ pub struct AppOp {
impl PasswordStorage for AppOp {}
impl AppOp {
- pub fn new(ui: uibuilder::UI, app_tx: glib::Sender<UpdateApp>) -> AppOp {
+ pub fn new(ui: uibuilder::UI, app_runtime: AppRuntime) -> AppOp {
let leaflet = ui
.builder
.get_object::<libhandy::Leaflet>("chat_page")
@@ -137,7 +137,7 @@ impl AppOp {
.expect("Couldn't find main_deck in ui file");
AppOp {
- app_tx,
+ app_runtime,
ui,
active_room: None,
join_to_room: None,
diff --git a/fractal-gtk/src/appop/room.rs b/fractal-gtk/src/appop/room.rs
index 020e9b12..715c060b 100644
--- a/fractal-gtk/src/appop/room.rs
+++ b/fractal-gtk/src/appop/room.rs
@@ -298,7 +298,8 @@ impl AppOp {
}
let back_history = self.room_back_history.clone();
- let actions = actions::Message::new(self.app_tx.clone(), self.ui.clone(), back_history);
+ let actions =
+ actions::Message::new(self.app_runtime.clone(), self.ui.clone(), back_history);
let history = widgets::RoomHistory::new(actions, active_room.clone(), &self.ui);
self.history = if let Some(mut history) = history {
history.create(
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]