refactor: config improvements
This commit is contained in:
parent
3eed30f723
commit
efe4ce2f5b
7 changed files with 69 additions and 86 deletions
|
|
@ -1,6 +1,6 @@
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use crate::CosmicConfigEntry;
|
use crate::{CosmicConfigEntry, Update};
|
||||||
use cosmic_settings_daemon::{ConfigProxy, CosmicSettingsDaemonProxy};
|
use cosmic_settings_daemon::{ConfigProxy, CosmicSettingsDaemonProxy};
|
||||||
use futures_util::SinkExt;
|
use futures_util::SinkExt;
|
||||||
use iced_futures::futures::{future::pending, StreamExt};
|
use iced_futures::futures::{future::pending, StreamExt};
|
||||||
|
|
@ -51,13 +51,6 @@ impl Watcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Update<T> {
|
|
||||||
pub errors: Vec<crate::Error>,
|
|
||||||
pub keys: Vec<&'static str>,
|
|
||||||
pub config: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn watcher_subscription<T: CosmicConfigEntry + Send + Sync + Default + 'static + Clone>(
|
pub fn watcher_subscription<T: CosmicConfigEntry + Send + Sync + Default + 'static + Clone>(
|
||||||
settings_daemon: CosmicSettingsDaemonProxy<'static>,
|
settings_daemon: CosmicSettingsDaemonProxy<'static>,
|
||||||
config_id: &'static str,
|
config_id: &'static str,
|
||||||
|
|
@ -79,7 +72,7 @@ pub fn watcher_subscription<T: CosmicConfigEntry + Send + Sync + Default + 'stat
|
||||||
Ok(config) => config,
|
Ok(config) => config,
|
||||||
Err((errors, default)) => {
|
Err((errors, default)) => {
|
||||||
if !errors.is_empty() {
|
if !errors.is_empty() {
|
||||||
eprintln!("Failed to get config: {errors:?}");
|
eprintln!("Error getting config: {config_id} {errors:?}");
|
||||||
}
|
}
|
||||||
default
|
default
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ pub enum Error {
|
||||||
Notify(notify::Error),
|
Notify(notify::Error),
|
||||||
Ron(ron::Error),
|
Ron(ron::Error),
|
||||||
RonSpanned(ron::error::SpannedError),
|
RonSpanned(ron::error::SpannedError),
|
||||||
|
GetKey(String, std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
impl fmt::Display for Error {
|
||||||
|
|
@ -44,6 +45,7 @@ impl fmt::Display for Error {
|
||||||
Self::Notify(err) => err.fmt(f),
|
Self::Notify(err) => err.fmt(f),
|
||||||
Self::Ron(err) => err.fmt(f),
|
Self::Ron(err) => err.fmt(f),
|
||||||
Self::RonSpanned(err) => err.fmt(f),
|
Self::RonSpanned(err) => err.fmt(f),
|
||||||
|
Self::GetKey(key, err) => write!(f, "failed to get key '{}': {}", key, err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -264,11 +266,11 @@ impl ConfigGet for Config {
|
||||||
let key_path = self.key_path(key)?;
|
let key_path = self.key_path(key)?;
|
||||||
let data = if key_path.is_file() {
|
let data = if key_path.is_file() {
|
||||||
// Load user override
|
// Load user override
|
||||||
fs::read_to_string(key_path)?
|
fs::read_to_string(key_path).map_err(|err| Error::GetKey(key.to_string(), err))?
|
||||||
} else {
|
} else {
|
||||||
// Load system default
|
// Load system default
|
||||||
let default_path = self.default_path(key)?;
|
let default_path = self.default_path(key)?;
|
||||||
fs::read_to_string(default_path)?
|
fs::read_to_string(default_path).map_err(|err| Error::GetKey(key.to_string(), err))?
|
||||||
};
|
};
|
||||||
let t = ron::from_str(&data)?;
|
let t = ron::from_str(&data)?;
|
||||||
Ok(t)
|
Ok(t)
|
||||||
|
|
@ -339,3 +341,9 @@ where
|
||||||
changed_keys: &[T],
|
changed_keys: &[T],
|
||||||
) -> (Vec<crate::Error>, Vec<&'static str>);
|
) -> (Vec<crate::Error>, Vec<&'static str>);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Update<T> {
|
||||||
|
pub errors: Vec<crate::Error>,
|
||||||
|
pub keys: Vec<&'static str>,
|
||||||
|
pub config: T,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ pub enum ConfigState<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ConfigUpdate<T> {
|
pub enum ConfigUpdate<T> {
|
||||||
Update(T),
|
Update(crate::Update<T>),
|
||||||
UpdateError(T, Vec<crate::Error>),
|
|
||||||
Failed,
|
Failed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,7 +23,7 @@ pub fn config_subscription<
|
||||||
id: I,
|
id: I,
|
||||||
config_id: Cow<'static, str>,
|
config_id: Cow<'static, str>,
|
||||||
config_version: u64,
|
config_version: u64,
|
||||||
) -> iced_futures::Subscription<(I, Result<T, (Vec<crate::Error>, T)>)> {
|
) -> iced_futures::Subscription<crate::Update<T>> {
|
||||||
subscription::channel(id, 100, move |mut output| {
|
subscription::channel(id, 100, move |mut output| {
|
||||||
let config_id = config_id.clone();
|
let config_id = config_id.clone();
|
||||||
async move {
|
async move {
|
||||||
|
|
@ -45,7 +44,7 @@ pub fn config_state_subscription<
|
||||||
id: I,
|
id: I,
|
||||||
config_id: Cow<'static, str>,
|
config_id: Cow<'static, str>,
|
||||||
config_version: u64,
|
config_version: u64,
|
||||||
) -> iced_futures::Subscription<(I, Result<T, (Vec<crate::Error>, T)>)> {
|
) -> iced_futures::Subscription<crate::Update<T>> {
|
||||||
subscription::channel(id, 100, move |mut output| {
|
subscription::channel(id, 100, move |mut output| {
|
||||||
let config_id = config_id.clone();
|
let config_id = config_id.clone();
|
||||||
async move {
|
async move {
|
||||||
|
|
@ -64,7 +63,7 @@ async fn start_listening<
|
||||||
T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry,
|
T: 'static + Send + Sync + PartialEq + Clone + CosmicConfigEntry,
|
||||||
>(
|
>(
|
||||||
state: ConfigState<T>,
|
state: ConfigState<T>,
|
||||||
output: &mut mpsc::Sender<(I, Result<T, (Vec<crate::Error>, T)>)>,
|
output: &mut mpsc::Sender<crate::Update<T>>,
|
||||||
id: I,
|
id: I,
|
||||||
) -> ConfigState<T> {
|
) -> ConfigState<T> {
|
||||||
use iced_futures::futures::{future::pending, StreamExt};
|
use iced_futures::futures::{future::pending, StreamExt};
|
||||||
|
|
@ -90,11 +89,21 @@ async fn start_listening<
|
||||||
|
|
||||||
match T::get_entry(&config) {
|
match T::get_entry(&config) {
|
||||||
Ok(t) => {
|
Ok(t) => {
|
||||||
_ = output.send((id, Ok(t.clone()))).await;
|
let update = crate::Update {
|
||||||
|
errors: Vec::new(),
|
||||||
|
keys: Vec::new(),
|
||||||
|
config: t.clone(),
|
||||||
|
};
|
||||||
|
_ = output.send(update).await;
|
||||||
ConfigState::Waiting(t, watcher, rx, config)
|
ConfigState::Waiting(t, watcher, rx, config)
|
||||||
}
|
}
|
||||||
Err((errors, t)) => {
|
Err((errors, t)) => {
|
||||||
_ = output.send((id, Err((errors, t.clone())))).await;
|
let update = crate::Update {
|
||||||
|
errors: errors,
|
||||||
|
keys: Vec::new(),
|
||||||
|
config: t.clone(),
|
||||||
|
};
|
||||||
|
_ = output.send(update).await;
|
||||||
ConfigState::Waiting(t, watcher, rx, config)
|
ConfigState::Waiting(t, watcher, rx, config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -104,11 +113,13 @@ async fn start_listening<
|
||||||
let (errors, changed) = conf_data.update_keys(&config, &keys);
|
let (errors, changed) = conf_data.update_keys(&config, &keys);
|
||||||
|
|
||||||
if !changed.is_empty() {
|
if !changed.is_empty() {
|
||||||
if errors.is_empty() {
|
_ = output
|
||||||
_ = output.send((id, Ok(conf_data.clone()))).await;
|
.send(crate::Update {
|
||||||
} else {
|
errors: errors,
|
||||||
_ = output.send((id, Err((errors, conf_data.clone())))).await;
|
keys: changed,
|
||||||
}
|
config: conf_data.clone(),
|
||||||
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
ConfigState::Waiting(conf_data, watcher, rx, config)
|
ConfigState::Waiting(conf_data, watcher, rx, config)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,6 @@ const ID: &str = "com.system76.CosmicAppletExample";
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
core: Core,
|
core: Core,
|
||||||
popup: Option<Id>,
|
popup: Option<Id>,
|
||||||
id_ctr: u128,
|
|
||||||
example_row: bool,
|
example_row: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -214,27 +214,37 @@ impl Core {
|
||||||
self.system_theme_mode
|
self.system_theme_mode
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "dbus-config")]
|
pub fn watch_config<
|
||||||
pub fn watch_config<T: CosmicConfigEntry + Send + Sync + Default + 'static + Clone>(
|
T: CosmicConfigEntry + Send + Sync + Default + 'static + Clone + PartialEq,
|
||||||
|
>(
|
||||||
&self,
|
&self,
|
||||||
config_id: &'static str,
|
config_id: &'static str,
|
||||||
) -> iced::Subscription<cosmic_config::dbus::Update<T>> {
|
) -> iced::Subscription<cosmic_config::Update<T>> {
|
||||||
|
#[cfg(feature = "dbus-config")]
|
||||||
if let Some(settings_daemon) = self.settings_daemon.clone() {
|
if let Some(settings_daemon) = self.settings_daemon.clone() {
|
||||||
cosmic_config::dbus::watcher_subscription(settings_daemon, config_id, false)
|
return cosmic_config::dbus::watcher_subscription(settings_daemon, config_id, false);
|
||||||
} else {
|
|
||||||
iced::Subscription::none()
|
|
||||||
}
|
}
|
||||||
|
cosmic_config::config_subscription(
|
||||||
|
std::any::TypeId::of::<T>(),
|
||||||
|
std::borrow::Cow::Borrowed(config_id),
|
||||||
|
T::VERSION,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "dbus-config")]
|
pub fn watch_state<
|
||||||
pub fn watch_state<T: CosmicConfigEntry + Send + Sync + Default + 'static + Clone>(
|
T: CosmicConfigEntry + Send + Sync + Default + 'static + Clone + PartialEq,
|
||||||
|
>(
|
||||||
&self,
|
&self,
|
||||||
state_id: &'static str,
|
state_id: &'static str,
|
||||||
) -> iced::Subscription<cosmic_config::dbus::Update<T>> {
|
) -> iced::Subscription<cosmic_config::Update<T>> {
|
||||||
|
#[cfg(feature = "dbus-config")]
|
||||||
if let Some(settings_daemon) = self.settings_daemon.clone() {
|
if let Some(settings_daemon) = self.settings_daemon.clone() {
|
||||||
cosmic_config::dbus::watcher_subscription(settings_daemon, state_id, true)
|
return cosmic_config::dbus::watcher_subscription(settings_daemon, state_id, true);
|
||||||
} else {
|
|
||||||
iced::Subscription::none()
|
|
||||||
}
|
}
|
||||||
|
cosmic_config::config_subscription(
|
||||||
|
std::any::TypeId::of::<T>(),
|
||||||
|
std::borrow::Cow::Borrowed(state_id),
|
||||||
|
T::VERSION,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ use iced::window;
|
||||||
#[cfg(not(any(feature = "multi-window", feature = "wayland")))]
|
#[cfg(not(any(feature = "multi-window", feature = "wayland")))]
|
||||||
use iced::Application as IcedApplication;
|
use iced::Application as IcedApplication;
|
||||||
use iced_futures::event::listen_raw;
|
use iced_futures::event::listen_raw;
|
||||||
|
use iced_futures::futures::executor::block_on;
|
||||||
#[cfg(not(feature = "wayland"))]
|
#[cfg(not(feature = "wayland"))]
|
||||||
use iced_runtime::command::Action;
|
use iced_runtime::command::Action;
|
||||||
#[cfg(not(feature = "wayland"))]
|
#[cfg(not(feature = "wayland"))]
|
||||||
|
|
@ -66,9 +67,6 @@ pub enum Message {
|
||||||
WmCapabilities(window::Id, WindowManagerCapabilities),
|
WmCapabilities(window::Id, WindowManagerCapabilities),
|
||||||
/// Activate the application
|
/// Activate the application
|
||||||
Activate(String),
|
Activate(String),
|
||||||
#[cfg(feature = "dbus-config")]
|
|
||||||
/// dbus settings daemon setup
|
|
||||||
SettingsDaemon(zbus::Result<cosmic_settings_daemon::CosmicSettingsDaemonProxy<'static>>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
@ -85,16 +83,14 @@ where
|
||||||
type Message = super::Message<T::Message>;
|
type Message = super::Message<T::Message>;
|
||||||
type Theme = Theme;
|
type Theme = Theme;
|
||||||
|
|
||||||
fn new((core, flags): Self::Flags) -> (Self, iced::Command<Self::Message>) {
|
fn new((mut core, flags): Self::Flags) -> (Self, iced::Command<Self::Message>) {
|
||||||
|
#[cfg(feature = "dbus-config")]
|
||||||
|
{
|
||||||
|
core.settings_daemon = block_on(cosmic_config::dbus::settings_daemon_proxy()).ok();
|
||||||
|
}
|
||||||
|
|
||||||
let (model, command) = T::init(core, flags);
|
let (model, command) = T::init(core, flags);
|
||||||
|
|
||||||
#[cfg(feature = "dbus-config")]
|
|
||||||
let command = iced::Command::batch(vec![
|
|
||||||
command,
|
|
||||||
iced::Command::perform(cosmic_config::dbus::settings_daemon_proxy(), |p| {
|
|
||||||
super::Message::Cosmic(super::cosmic::Message::SettingsDaemon(p))
|
|
||||||
}),
|
|
||||||
]);
|
|
||||||
(Self::new(model), command)
|
(Self::new(model), command)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,7 +172,6 @@ where
|
||||||
keyboard_nav::subscription()
|
keyboard_nav::subscription()
|
||||||
.map(Message::KeyboardNav)
|
.map(Message::KeyboardNav)
|
||||||
.map(super::Message::Cosmic),
|
.map(super::Message::Cosmic),
|
||||||
#[cfg(feature = "dbus-config")]
|
|
||||||
self.app
|
self.app
|
||||||
.core()
|
.core()
|
||||||
.watch_config::<cosmic_theme::Theme>(if self.app.core().system_theme_mode.is_dark {
|
.watch_config::<cosmic_theme::Theme>(if self.app.core().system_theme_mode.is_dark {
|
||||||
|
|
@ -191,27 +186,6 @@ where
|
||||||
Message::SystemThemeChange(crate::theme::Theme::system(Arc::new(update.config)))
|
Message::SystemThemeChange(crate::theme::Theme::system(Arc::new(update.config)))
|
||||||
})
|
})
|
||||||
.map(super::Message::Cosmic),
|
.map(super::Message::Cosmic),
|
||||||
#[cfg(not(feature = "dbus-config"))]
|
|
||||||
theme::subscription(self.app.core().system_theme_mode.is_dark)
|
|
||||||
.map(Message::SystemThemeChange)
|
|
||||||
.map(super::Message::Cosmic),
|
|
||||||
#[cfg(not(feature = "dbus-config"))]
|
|
||||||
cosmic_config::config_subscription::<_, cosmic_theme::ThemeMode>(
|
|
||||||
0,
|
|
||||||
cosmic_theme::THEME_MODE_ID.into(),
|
|
||||||
cosmic_theme::ThemeMode::version(),
|
|
||||||
)
|
|
||||||
.map(|(_, u)| match u {
|
|
||||||
Ok(t) => Message::SystemThemeModeChange(t),
|
|
||||||
Err((errors, t)) => {
|
|
||||||
for e in errors {
|
|
||||||
tracing::error!("{e}");
|
|
||||||
}
|
|
||||||
Message::SystemThemeModeChange(t)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(super::Message::Cosmic),
|
|
||||||
#[cfg(feature = "dbus-config")]
|
|
||||||
self.app
|
self.app
|
||||||
.core()
|
.core()
|
||||||
.watch_config::<ThemeMode>(cosmic_theme::THEME_MODE_ID)
|
.watch_config::<ThemeMode>(cosmic_theme::THEME_MODE_ID)
|
||||||
|
|
@ -422,15 +396,6 @@ impl<T: Application> Cosmic<T> {
|
||||||
_token,
|
_token,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
#[cfg(feature = "dbus-config")]
|
|
||||||
Message::SettingsDaemon(p) => match p {
|
|
||||||
Ok(p) => {
|
|
||||||
self.app.core_mut().settings_daemon = Some(p);
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to connect to settings daemon: {e}");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iced::Command::none()
|
iced::Command::none()
|
||||||
|
|
|
||||||
|
|
@ -85,15 +85,12 @@ pub fn subscription(is_dark: bool) -> Subscription<crate::theme::Theme> {
|
||||||
.into(),
|
.into(),
|
||||||
crate::cosmic_theme::Theme::version(),
|
crate::cosmic_theme::Theme::version(),
|
||||||
)
|
)
|
||||||
.map(|(_, res)| {
|
.map(|res| {
|
||||||
let theme = res.unwrap_or_else(|(errors, theme)| {
|
for err in res.errors {
|
||||||
for err in errors {
|
tracing::error!("{:?}", err);
|
||||||
tracing::error!("{:?}", err);
|
}
|
||||||
}
|
|
||||||
theme
|
|
||||||
});
|
|
||||||
|
|
||||||
Theme::system(Arc::new(theme))
|
Theme::system(Arc::new(res.config))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue