use iced_futures::futures::SinkExt; use iced_futures::{futures::channel::mpsc, subscription}; use notify::RecommendedWatcher; use std::{borrow::Cow, hash::Hash}; use crate::{Config, CosmicConfigEntry}; pub enum ConfigState { Init(Cow<'static, str>, u64, bool), Waiting(T, RecommendedWatcher, mpsc::Receiver>, Config), Failed, } pub enum ConfigUpdate { Update(crate::Update), Failed, } pub fn config_subscription< I: 'static + Copy + Send + Sync + Hash, T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry, >( id: I, config_id: Cow<'static, str>, config_version: u64, ) -> iced_futures::Subscription> { subscription::channel(id, 100, move |mut output| { let config_id = config_id.clone(); async move { let config_id = config_id.clone(); let mut state = ConfigState::Init(config_id, config_version, false); loop { state = start_listening(state, &mut output, id).await; } } }) } pub fn config_state_subscription< I: 'static + Copy + Send + Sync + Hash, T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry, >( id: I, config_id: Cow<'static, str>, config_version: u64, ) -> iced_futures::Subscription> { subscription::channel(id, 100, move |mut output| { let config_id = config_id.clone(); async move { let config_id = config_id.clone(); let mut state = ConfigState::Init(config_id, config_version, true); loop { state = start_listening(state, &mut output, id).await; } } }) } async fn start_listening< I: Copy, T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry, >( state: ConfigState, output: &mut mpsc::Sender>, id: I, ) -> ConfigState { use iced_futures::futures::{future::pending, StreamExt}; match state { ConfigState::Init(config_id, version, is_state) => { let (tx, rx) = mpsc::channel(100); let Ok(config) = (if is_state { Config::new_state(&config_id, version) } else { Config::new(&config_id, version) }) else { return ConfigState::Failed; }; let Ok(watcher) = config.watch(move |_helper, keys| { let mut tx = tx.clone(); let _ = tx.try_send(keys.to_vec()); }) else { return ConfigState::Failed; }; match T::get_entry(&config) { Ok(t) => { let update = crate::Update { errors: Vec::new(), keys: Vec::new(), config: t.clone(), }; _ = output.send(update).await; ConfigState::Waiting(t, watcher, rx, config) } Err((errors, t)) => { let update = crate::Update { errors: errors, keys: Vec::new(), config: t.clone(), }; _ = output.send(update).await; ConfigState::Waiting(t, watcher, rx, config) } } } ConfigState::Waiting(mut conf_data, watcher, mut rx, config) => match rx.next().await { Some(keys) => { let (errors, changed) = conf_data.update_keys(&config, &keys); if !changed.is_empty() { _ = output .send(crate::Update { errors, keys: changed, config: conf_data.clone(), }) .await; } ConfigState::Waiting(conf_data, watcher, rx, config) } None => ConfigState::Failed, }, ConfigState::Failed => pending().await, } }