use std::sync::Arc; use slint::ComponentHandle; use tokio::sync::mpsc; use crate::{runtime::spawn, ui}; /// A thing for spawning I/O-tasks and updating the GUI `ConnectionStatus` with the result. #[derive(Clone)] pub struct Io { state: Arc, } struct State { status: mpsc::Sender, } impl Io { pub fn new(app: &ui::App) -> Self { let (tx, mut rx) = mpsc::channel(10); let app_weak = app.as_weak(); spawn(async move { loop { let Some(status) = rx.recv().await else { return; }; let _ = app_weak.upgrade_in_event_loop(move |app| { app.global::().set_connection_status(status); }); } }); Io { state: Arc::new(State { status: tx }), } } /// Spawn a fallible async function. /// /// Update the `ConnectionStatus` in the GUI depending on whether the result is an error. #[cfg(not(target_arch = "wasm32"))] pub fn spawn(&self, f: impl FnOnce() -> Fut + Send + 'static) where Fut: Future>, Fut: Send + 'static, { let io = self.clone(); spawn(async move { let _ = io.state.status.send(ui::ConnectionStatus::Syncing).await; let result = f().await; let was_error = result.is_err(); if let Err(e) = result { eprintln!("{e:?}"); } let _ = io .state .status .send(if was_error { ui::ConnectionStatus::Error } else { ui::ConnectionStatus::Idle }) .await; }); } /// Spawn a fallible async function. /// /// Update the `ConnectionStatus` in the GUI depending on whether the result is an error. // FIXME: this function is duplicated from the one above, but without the `Send` requirement on the future. #[cfg(target_arch = "wasm32")] pub fn spawn(&self, f: impl FnOnce() -> Fut + Send + 'static) where Fut: Future>, Fut: 'static, { let io = self.clone(); spawn(async move { let _ = io.state.status.send(ui::ConnectionStatus::Syncing).await; let result = f().await; let was_error = result.is_err(); if let Err(e) = result { eprintln!("{e:?}"); } let _ = io .state .status .send(if was_error { ui::ConnectionStatus::Error } else { ui::ConnectionStatus::Idle }) .await; }); } }