use super::app::Platform;
use super::with_env;
use crate::error::PlatformError;
use crate::traits::screenshot::{AppScreenshot, WindowInfo};
use async_trait::async_trait;
use base64::Engine as _;
use jni::objects::{JClass, JValue};
use jni::{jni_sig, jni_str};
use serde::Deserialize;
#[derive(Deserialize)]
struct ScreenshotEnvelope {
ok: bool,
#[serde(default)]
data: Option<String>,
#[serde(default)]
error: Option<String>,
}
#[async_trait]
impl AppScreenshot for Platform {
async fn list_app_windows(&self) -> Result<Vec<WindowInfo>, PlatformError> {
Ok(vec![WindowInfo {
id: "main".to_string(),
title: String::new(),
focused: true,
main: true,
visible: true,
width: 0,
height: 0,
}])
}
async fn take_app_screenshot(&self, window_id: Option<&str>) -> Result<Vec<u8>, PlatformError> {
let _ = window_id;
let envelope_json = crate::rt::native_call(|callback_id| {
let screenshot_class: &JClass =
super::get_cached_class(super::CachedClass::AppScreenshot)
.map_err(|e| PlatformError::Platform(e.to_string()))?;
with_env(|env| -> Result<(), PlatformError> {
env.call_static_method(
screenshot_class,
jni_str!("captureWindow"),
jni_sig!("(J)V"),
&[JValue::Long(callback_id as i64)],
)?;
Ok(())
})
.map_err(|e| {
PlatformError::Platform(format!("Failed to dispatch captureWindow: {}", e))
})
})
.await?;
let envelope: ScreenshotEnvelope = serde_json::from_str(&envelope_json).map_err(|e| {
PlatformError::Platform(format!(
"Failed to parse app screenshot envelope: {} (payload: {})",
e, envelope_json
))
})?;
if !envelope.ok {
return Err(PlatformError::Platform(
envelope
.error
.unwrap_or_else(|| "unknown error".to_string()),
));
}
let data = envelope
.data
.ok_or_else(|| PlatformError::Platform("envelope ok=true but no data".to_string()))?;
base64::engine::general_purpose::STANDARD
.decode(data.trim())
.map_err(|e| {
PlatformError::Platform(format!("Failed to decode app screenshot base64: {}", e))
})
}
}