use std::collections::HashMap;
use enumflags2::{bitflags, BitFlags};
use serde::{Deserialize, Serialize};
use serde_repr::{Deserialize_repr, Serialize_repr};
use zbus::zvariant::{self, SerializeDict, Type};
use super::{HandleToken, Icon, DESTINATION, PATH};
use crate::{
helpers::{call_method, call_request_method},
Error, WindowIdentifier,
};
#[bitflags]
#[derive(Serialize_repr, Deserialize_repr, PartialEq, Debug, Copy, Clone, Type)]
#[repr(u32)]
#[doc(alias = "XdpLauncherType")]
pub enum LauncherType {
#[doc(alias = "XDP_LAUNCHER_APPLICATION")]
Application,
#[doc(alias = "XDP_LAUNCHER_WEBAPP")]
WebApplication,
}
impl Default for LauncherType {
fn default() -> Self {
Self::Application
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Type)]
#[zvariant(signature = "s")]
#[serde(rename_all = "lowercase")]
pub enum IconType {
Png,
Jpeg,
Svg,
}
#[derive(Deserialize, Type)]
#[zvariant(signature = "(vsu)")]
pub struct LauncherIcon(Icon, IconType, u32);
impl LauncherIcon {
pub fn icon(&self) -> &Icon {
&self.0
}
pub fn type_(&self) -> IconType {
self.1
}
pub fn size(&self) -> u32 {
self.2
}
}
#[derive(Debug, Default, SerializeDict, Type)]
#[zvariant(signature = "dict")]
pub struct PrepareInstallOptions {
handle_token: HandleToken,
modal: Option<bool>,
launcher_type: LauncherType,
target: Option<String>,
editable_name: Option<bool>,
editable_icon: Option<bool>,
}
impl PrepareInstallOptions {
pub fn modal(mut self, modal: bool) -> Self {
self.modal = Some(modal);
self
}
pub fn launcher_type(mut self, launcher_type: LauncherType) -> Self {
self.launcher_type = launcher_type;
self
}
pub fn target(mut self, target: &str) -> Self {
self.target = Some(target.to_owned());
self
}
pub fn editable_name(mut self, editable_name: bool) -> Self {
self.editable_name = Some(editable_name);
self
}
pub fn editable_icon(mut self, editable_icon: bool) -> Self {
self.editable_icon = Some(editable_icon);
self
}
}
#[derive(Debug)]
#[doc(alias = "org.freedesktop.portal.DynamicLauncher")]
pub struct DynamicLauncherProxy<'a>(zbus::Proxy<'a>);
impl<'a> DynamicLauncherProxy<'a> {
pub async fn new(connection: &zbus::Connection) -> Result<DynamicLauncherProxy<'a>, Error> {
let proxy = zbus::ProxyBuilder::new_bare(connection)
.interface("org.freedesktop.portal.DynamicLauncher")?
.path(PATH)?
.destination(DESTINATION)?
.build()
.await?;
Ok(Self(proxy))
}
pub fn inner(&self) -> &zbus::Proxy<'_> {
&self.0
}
#[doc(alias = "PrepareInstall")]
#[doc(alias = "xdp_portal_dynamic_launcher_prepare_install")]
#[doc(alias = "xdp_portal_dynamic_launcher_prepare_install_finish")]
pub async fn prepare_install(
&self,
parent_window: &WindowIdentifier,
name: &str,
icon: Icon,
options: PrepareInstallOptions,
) -> Result<(String, String), Error> {
let response = call_request_method(
self.inner(),
&options.handle_token,
"PrepareInstall",
&(parent_window, name, icon, &options),
)
.await?;
Ok(response)
}
#[doc(alias = "RequestInstallToken")]
#[doc(alias = "xdp_portal_dynamic_launcher_request_install_token")]
pub async fn request_install_token(&self, name: &str, icon: Icon) -> Result<String, Error> {
let options: HashMap<&str, zvariant::Value<'_>> = HashMap::new();
let token =
call_method::<String, _>(self.inner(), "RequestInstallToken", &(name, icon, options))
.await?;
Ok(token)
}
#[doc(alias = "Install")]
#[doc(alias = "xdp_portal_dynamic_launcher_install")]
pub async fn install(
&self,
token: &str,
desktop_file_id: &str,
desktop_entry: &str,
) -> Result<(), Error> {
let options: HashMap<&str, zvariant::Value<'_>> = HashMap::new();
call_method(
self.inner(),
"Install",
&(token, desktop_file_id, desktop_entry, options),
)
.await?;
Ok(())
}
#[doc(alias = "Uninstall")]
#[doc(alias = "xdp_portal_dynamic_launcher_uninstall")]
pub async fn uninstall(&self, desktop_file_id: &str) -> Result<(), Error> {
let options: HashMap<&str, zvariant::Value<'_>> = HashMap::new();
call_method(self.inner(), "Uninstall", &(desktop_file_id, options)).await?;
Ok(())
}
#[doc(alias = "GetDesktopEntry")]
#[doc(alias = "xdp_portal_dynamic_launcher_get_desktop_entry")]
pub async fn desktop_entry(&self, desktop_file_id: &str) -> Result<String, Error> {
call_method(self.inner(), "GetDesktopEntry", &(desktop_file_id)).await
}
#[doc(alias = "GetIcon")]
#[doc(alias = "xdp_portal_dynamic_launcher_get_icon")]
pub async fn icon(&self, desktop_file_id: &str) -> Result<LauncherIcon, Error> {
call_method(self.inner(), "GetIcon", &(desktop_file_id)).await
}
#[doc(alias = "Launch")]
#[doc(alias = "xdp_portal_dynamic_launcher_launch")]
pub async fn launch(&self, desktop_file_id: &str) -> Result<(), Error> {
let options: HashMap<&str, zvariant::Value<'_>> = HashMap::new();
call_method(self.inner(), "Launch", &(desktop_file_id, &options)).await
}
#[doc(alias = "SupportedLauncherTypes")]
pub async fn supported_launcher_types(&self) -> Result<BitFlags<LauncherType>, Error> {
self.inner()
.get_property::<BitFlags<LauncherType>>("SupportedLauncherTypes")
.await
.map_err(From::from)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_icon_signature() {
let signature = LauncherIcon::signature();
assert_eq!(signature.as_str(), "(vsu)");
let icon = vec![IconType::Png];
assert_eq!(serde_json::to_string(&icon).unwrap(), "[\"png\"]");
}
}