use futures_lite::prelude::*;
use futures_lite::stream::once;
use zbus::zvariant;
use zbus::zvariant::OwnedValue;
use zbus::Connection;
use zbus::Error;
use zbus::ProxyBuilder;
use zbus::Result;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
const NAMESPACE: &str = "org.freedesktop.appearance";
const KEY: &str = "color-scheme";
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum SchemePreference {
#[default]
NoPreference = 0,
Dark = 1,
Light = 2,
}
impl TryFrom<zvariant::Value<'_>> for SchemePreference {
type Error = Error;
fn try_from(value: zvariant::Value) -> Result<Self> {
Ok(match u32::try_from(value)? {
0 => SchemePreference::NoPreference,
1 => SchemePreference::Dark,
2 => SchemePreference::Light,
_ => SchemePreference::NoPreference,
})
}
}
impl<'s> TryFrom<&'s zbus::Message> for SchemePreference {
type Error = Error;
fn try_from(message: &'s zbus::Message) -> Result<Self> {
message
.body::<(&str, &str, zvariant::Value<'_>)>()
.and_then(|args| SchemePreference::try_from(args.2))
}
}
#[derive(Debug, Clone)]
pub struct SchemeProxy<'a>(zbus::Proxy<'a>);
impl<'a> ::zbus::ProxyDefault for SchemeProxy<'a> {
const INTERFACE: &'static str = "org.freedesktop.portal.Settings";
const DESTINATION: &'static str = "org.freedesktop.portal.Desktop";
const PATH: &'static str = "/org/freedesktop/portal/desktop";
}
impl<'c> From<zbus::Proxy<'c>> for SchemeProxy<'c> {
fn from(proxy: zbus::Proxy<'c>) -> Self {
SchemeProxy(proxy)
}
}
impl<'a> SchemeProxy<'a> {
pub async fn new(conn: &Connection) -> Result<SchemeProxy<'a>> {
Self::builder(conn).build().await
}
pub async fn with_new_connection() -> Result<SchemeProxy<'a>> {
Self::new(&zbus::Connection::session().await?).await
}
pub fn builder(conn: &::zbus::Connection) -> ProxyBuilder<'a, Self> {
ProxyBuilder::new(conn).cache_properties(zbus::CacheProperties::No)
}
pub async fn read(&self) -> Result<SchemePreference> {
let reply: OwnedValue = self.0.call("Read", &(NAMESPACE, KEY)).await?;
reply
.downcast_ref::<zvariant::Value>()
.cloned()
.ok_or(zvariant::Error::IncorrectType.into())
.and_then(SchemePreference::try_from)
}
async fn receive_changed(&self) -> Result<impl Stream<Item = SchemePreference>> {
let signal = self
.0
.receive_signal_with_args("SettingChanged", &[(0, NAMESPACE), (1, KEY)])
.await?
.filter_map(|x| SchemePreference::try_from(x.as_ref()).ok());
Ok(signal)
}
pub async fn init_and_receive_changed(&self) -> Result<impl Stream<Item = SchemePreference>> {
let mut preference = self.read().await?;
Ok(
once(preference).chain(self.receive_changed().await?.filter_map(move |p| {
if p == preference {
None
} else {
preference = p;
Some(p)
}
})),
)
}
}