use serde::Deserialize;
use tracing::warn;
use crate::{IdeviceError, ReadWrite, obf};
use super::{CoreDeviceError, CoreDeviceServiceClient};
#[derive(Debug)]
pub struct IconServiceClient<R: ReadWrite> {
inner: CoreDeviceServiceClient<R>,
}
#[cfg(feature = "rsd")]
impl crate::RsdService for IconServiceClient<Box<dyn ReadWrite>> {
fn rsd_service_name() -> std::borrow::Cow<'static, str> {
obf!("com.apple.coredevice.iconservice")
}
async fn from_stream(stream: Box<dyn ReadWrite>) -> Result<Self, IdeviceError> {
Ok(Self {
inner: CoreDeviceServiceClient::new(stream).await?,
})
}
}
#[derive(Debug, Clone)]
pub enum AppIconTarget {
BundleIdentifier(String),
AppPath(String),
}
#[derive(Debug, Clone, Deserialize)]
pub struct AppIcon {
#[serde(rename = "pngData")]
pub png_data: plist::Data,
#[serde(rename = "pixelSize")]
pub pixel_size: (f64, f64),
pub size: (f64, f64),
pub scale: f64,
#[serde(rename = "isAppIconPlaceholder")]
pub is_placeholder: bool,
}
impl<R: ReadWrite> IconServiceClient<R> {
pub async fn new(inner: R) -> Result<Self, IdeviceError> {
Ok(Self {
inner: CoreDeviceServiceClient::new(inner).await?,
})
}
pub async fn fetch_icon(
&mut self,
target: AppIconTarget,
width: f32,
height: f32,
scale: f32,
allow_placeholder: bool,
) -> Result<AppIcon, IdeviceError> {
let (bundle_identifier, app_path) = match target {
AppIconTarget::BundleIdentifier(b) => (Some(b), None),
AppIconTarget::AppPath(p) => (None, Some(p)),
};
let feature = obf!("com.apple.coredevice.feature.fetchappicons");
let res = self
.inner
.invoke_with_plist(
feature,
crate::plist!({
"bundleIdentifier":? bundle_identifier,
"appPath":? app_path,
"width": width,
"height": height,
"scale": scale,
"allowPlaceholder": allow_placeholder,
})
.into_dictionary()
.unwrap(),
)
.await?;
let info = res
.as_dictionary()
.and_then(|x| x.get("appIconInfo"))
.ok_or(CoreDeviceError::MissingField("appIconInfo"))?;
match plist::from_value(info) {
Ok(icon) => Ok(icon),
Err(e) => {
warn!("Could not parse appIconInfo: {e:?}");
Err(IdeviceError::UnexpectedResponse(
"failed to parse appIconInfo in fetch icon response".into(),
))
}
}
}
}