//! Screenshot pipeline — captures app screenshots for each store target size. use crate::PublishResult; /// A screenshot target device/size specification. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ScreenshotTarget { /// Display name (e.g. "iPhone 6.7\"") pub name: String, /// Target identifier used in el.toml (e.g. "iphone-6.7") pub id: String, pub width: u32, pub height: u32, pub platform: ScreenshotPlatform, } #[derive(Debug, Clone, PartialEq, Eq)] pub enum ScreenshotPlatform { Ios, Android, } impl ScreenshotTarget { /// All standard screenshot targets, matching Apple and Google requirements. pub fn all_standard() -> Vec { vec![ Self { name: "iPhone 6.7\"".into(), id: "iphone-6.7".into(), width: 1290, height: 2796, platform: ScreenshotPlatform::Ios, }, Self { name: "iPhone 6.1\"".into(), id: "iphone-6.1".into(), width: 1179, height: 2556, platform: ScreenshotPlatform::Ios, }, Self { name: "iPad 13\"".into(), id: "ipad-13".into(), width: 2064, height: 2752, platform: ScreenshotPlatform::Ios, }, Self { name: "Android Phone".into(), id: "android-phone".into(), width: 1080, height: 1920, platform: ScreenshotPlatform::Android, }, ] } /// Find a target by its ID. pub fn find(id: &str) -> Option { Self::all_standard().into_iter().find(|t| t.id == id) } } /// A captured screenshot. #[derive(Debug, Clone)] pub struct Screenshot { pub target: ScreenshotTarget, pub locale: String, pub scenario: String, /// Path to the PNG file. pub path: String, } /// Trait for screenshot capture backends. /// /// Implementations might use: /// - `xcrun simctl` for iOS Simulator screenshots /// - Android Emulator ADB screenshots /// - Puppeteer/Playwright for web screenshots pub trait ScreenshotCapture: Send + Sync { /// Capture a screenshot for the given scenario and target. fn capture( &self, scenario: &str, target: &ScreenshotTarget, locale: &str, output_dir: &str, ) -> PublishResult; /// Capture all scenarios for all targets and locales. fn capture_all( &self, scenarios: &[String], targets: &[ScreenshotTarget], locales: &[String], output_dir: &str, ) -> PublishResult> { let mut screenshots = Vec::new(); for scenario in scenarios { for target in targets { for locale in locales { let shot = self.capture(scenario, target, locale, output_dir)?; screenshots.push(shot); } } } Ok(screenshots) } } /// Stub screenshot capture (produces placeholder paths without actually /// launching a simulator). A future agent fills in the real capture logic. pub struct StubScreenshotCapture; impl ScreenshotCapture for StubScreenshotCapture { fn capture( &self, scenario: &str, target: &ScreenshotTarget, locale: &str, output_dir: &str, ) -> PublishResult { let filename = format!( "{}/{}/{}-{}.png", output_dir, locale, target.id, scenario ); // TODO: actually launch simulator/emulator, navigate to scenario, capture PNG Ok(Screenshot { target: target.clone(), locale: locale.to_string(), scenario: scenario.to_string(), path: filename, }) } }