Cosmic advanced text (#103)

* wip: update to use cosmic-advanced-text

* use cosmic-advanced-text branch of iced

* fix: line height and spacing for segmented button and update to get svg fix

* fix: spin button styling & spacing

* update iced to fix segmented button border radius

* feat: example improvements

* feat: helper for loading fonts

* feat: add focus style to button

* fix: slider height and iced fixed

* feat: hash icon width and height

* cleanup

* update ci

* refactor: always use lazy feature of iced

* update iced

* update iced

* cleanup & update iced

* update iced: new slider & tiny-skia quad updates

* update iced: fixes for tiny-skia quad rendering with edge case border radius

* re-export iced_runtime & iced_widget

* merge master

* udpate iced

* update iced

* update iced

* update iced

* fix: make rectangle_tracker subscription only return update if there is some

* feat: derive macro for loading a cosmic-config

* feat (cosmic-config): iced subscription

* fix (example): update to rectangle tracker subscription

* fix (cosmic-config)

* refactor(cosmic-config-derive): add support for types with generic parameters

* fix (cosmic-config): feature gate updates for subscription helpers

* feat: support for custom & system themes + move cosmic-theme to libcosmic

* feat: sorta hacky way of creating header bars for libcosmic + update iced to get support for resizable windows in iced-sctk

* update iced

* update and reexport sctk

* fix: applet border radius

* feat (cosmic-theme): add id and name methods

* fix(cosmic-theme): reexport palette from cosmic-theme

* fix(cosmic-config-derive): allow use with reexported cosmic-config

* feat: update iced with fix and refactor applet env vars

* update iced
This commit is contained in:
Ashley Wulber 2023-05-30 12:03:15 -04:00 committed by GitHub
parent a173794bed
commit e056e8c830
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 3431 additions and 405 deletions

View file

@ -1,12 +1,21 @@
use notify::Watcher;
#[cfg(feature = "subscription")]
use iced_futures::futures::channel::mpsc;
#[cfg(feature = "subscription")]
use iced_futures::subscription;
use notify::{RecommendedWatcher, Watcher};
use serde::{de::DeserializeOwned, Serialize};
use std::{
borrow::Cow,
fs,
hash::Hash,
io::Write,
path::{Path, PathBuf},
sync::Mutex,
};
#[cfg(feature = "macro")]
pub use cosmic_config_derive;
#[cfg(feature = "calloop")]
pub mod calloop;
@ -251,3 +260,123 @@ impl<'a> ConfigSet for ConfigTransaction<'a> {
Ok(())
}
}
#[cfg(feature = "subscription")]
pub enum ConfigState<T> {
Init(Cow<'static, str>, u64),
Waiting(T, RecommendedWatcher, mpsc::Receiver<()>, Config),
Failed,
}
#[cfg(feature = "subscription")]
pub enum ConfigUpdate<T> {
Update(T),
UpdateError(T, Vec<crate::Error>),
Failed,
}
pub trait CosmicConfigEntry
where
Self: Sized,
{
fn write_entry(&self, config: &Config) -> Result<(), crate::Error>;
fn get_entry(config: &Config) -> Result<Self, (Vec<crate::Error>, Self)>;
}
#[cfg(feature = "subscription")]
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<(I, Result<T, (Vec<crate::Error>, T)>)> {
subscription::unfold(
id,
ConfigState::Init(config_id, config_version),
move |state| start_listening_loop(id, state),
)
}
#[cfg(feature = "subscription")]
async fn start_listening<
I: Copy,
T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry,
>(
id: I,
state: ConfigState<T>,
) -> (
Option<(I, Result<T, (Vec<crate::Error>, T)>)>,
ConfigState<T>,
) {
use iced_futures::futures::{future::pending, StreamExt};
match state {
ConfigState::Init(config_id, version) => {
let (tx, rx) = mpsc::channel(100);
let config = match Config::new(&config_id, version) {
Ok(c) => c,
Err(_) => return (None, ConfigState::Failed),
};
let watcher = match config.watch(move |_helper, _keys| {
let mut tx = tx.clone();
let _ = tx.try_send(());
}) {
Ok(w) => w,
Err(_) => return (None, ConfigState::Failed),
};
match T::get_entry(&config) {
Ok(t) => (
Some((id, Ok(t.clone()))),
ConfigState::Waiting(t, watcher, rx, config),
),
Err((errors, t)) => (
Some((id, Err((errors, t.clone())))),
ConfigState::Waiting(t, watcher, rx, config),
),
}
}
ConfigState::Waiting(old, watcher, mut rx, config) => match rx.next().await {
Some(_) => match T::get_entry(&config) {
Ok(t) => (
if t != old {
Some((id, Ok(t.clone())))
} else {
None
},
ConfigState::Waiting(t, watcher, rx, config),
),
Err((errors, t)) => (
if t != old {
Some((id, Err((errors, t.clone()))))
} else {
None
},
ConfigState::Waiting(t, watcher, rx, config),
),
},
None => (None, ConfigState::Failed),
},
ConfigState::Failed => pending().await,
}
}
#[cfg(feature = "subscription")]
async fn start_listening_loop<
I: Copy,
T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry,
>(
id: I,
mut state: ConfigState<T>,
) -> ((I, Result<T, (Vec<crate::Error>, T)>), ConfigState<T>) {
loop {
let (update, new_state) = start_listening(id, state).await;
state = new_state;
if let Some(update) = update {
return (update, state);
}
}
}