use std::{collections::HashMap, convert::TryFrom, fmt::Debug};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
use zbus::zvariant::{OwnedValue, Type};
use super::{DESTINATION, PATH};
use crate::{
helpers::{call_method, receive_signal},
Error,
};
pub type Namespace = HashMap<String, OwnedValue>;
#[derive(Serialize, Clone, Deserialize, Type)]
pub struct Setting(String, String, OwnedValue);
impl Setting {
pub fn namespace(&self) -> &str {
&self.0
}
pub fn key(&self) -> &str {
&self.1
}
pub fn value(&self) -> &OwnedValue {
&self.2
}
}
impl std::fmt::Debug for Setting {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Setting")
.field("namespace", &self.namespace())
.field("key", &self.key())
.field("value", self.value())
.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ColorScheme {
NoPreference,
PreferDark,
PreferLight,
}
#[derive(Debug)]
#[doc(alias = "org.freedesktop.portal.Settings")]
pub struct SettingsProxy<'a>(zbus::Proxy<'a>);
impl<'a> SettingsProxy<'a> {
pub async fn new(connection: &zbus::Connection) -> Result<SettingsProxy<'a>, Error> {
let proxy = zbus::ProxyBuilder::new_bare(connection)
.interface("org.freedesktop.portal.Settings")?
.path(PATH)?
.destination(DESTINATION)?
.build()
.await?;
Ok(Self(proxy))
}
pub fn inner(&self) -> &zbus::Proxy<'_> {
&self.0
}
#[doc(alias = "ReadAll")]
pub async fn read_all(
&self,
namespaces: &[impl AsRef<str> + Type + Serialize + Debug],
) -> Result<HashMap<String, Namespace>, Error> {
call_method(self.inner(), "ReadAll", &(namespaces)).await
}
#[doc(alias = "Read")]
pub async fn read<T>(&self, namespace: &str, key: &str) -> Result<T, Error>
where
T: TryFrom<OwnedValue> + DeserializeOwned + Type,
Error: From<<T as TryFrom<OwnedValue>>::Error>,
{
let value = call_method::<OwnedValue, _>(self.inner(), "Read", &(namespace, key)).await?;
T::try_from(value).map_err(From::from)
}
pub async fn color_scheme(&self) -> Result<ColorScheme, Error> {
let scheme = match self
.read::<u32>("org.freedesktop.appearance", "color-scheme")
.await?
{
1 => ColorScheme::PreferDark,
2 => ColorScheme::PreferLight,
_ => ColorScheme::NoPreference,
};
Ok(scheme)
}
pub async fn receive_color_scheme_changed(&self) -> Result<ColorScheme, Error> {
loop {
let setting = self.receive_setting_changed().await?;
if setting.namespace() == "org.freedesktop.appearance"
&& setting.key() == "color-scheme"
{
return Ok(match u32::try_from(setting.value()) {
Ok(1) => ColorScheme::PreferDark,
Ok(2) => ColorScheme::PreferLight,
_ => ColorScheme::NoPreference,
});
}
}
}
#[doc(alias = "SettingChanged")]
pub async fn receive_setting_changed(&self) -> Result<Setting, Error> {
receive_signal(self.inner(), "SettingChanged").await
}
}