windjammer_ui/platform/
mod.rs

1// Platform abstraction layer for windjammer-ui
2//
3// This module provides platform-specific implementations for:
4// - Desktop (egui)
5// - Web (WASM)
6// - iOS (UIKit/SwiftUI) - Future
7// - Android (Jetpack Compose) - Future
8
9pub mod desktop;
10pub mod web;
11
12// Mobile platforms (coming soon)
13#[cfg(target_os = "ios")]
14pub mod ios;
15
16#[cfg(target_os = "android")]
17pub mod android;
18
19/// Platform target for code generation
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum Target {
22    /// Desktop (egui backend)
23    Desktop,
24    /// Web (WASM backend)
25    Web,
26    /// iOS (UIKit/SwiftUI backend)
27    IOS,
28    /// Android (Jetpack Compose backend)
29    Android,
30}
31
32impl Target {
33    /// Parse target from string (case-insensitive)
34    pub fn parse(s: &str) -> Option<Self> {
35        match s.to_lowercase().as_str() {
36            "desktop" => Some(Target::Desktop),
37            "web" | "wasm" => Some(Target::Web),
38            "ios" | "iphone" => Some(Target::IOS),
39            "android" => Some(Target::Android),
40            _ => None,
41        }
42    }
43
44    /// Check if target is mobile
45    pub fn is_mobile(&self) -> bool {
46        matches!(self, Target::IOS | Target::Android)
47    }
48
49    /// Get target name
50    pub fn name(&self) -> &'static str {
51        match self {
52            Target::Desktop => "desktop",
53            Target::Web => "web",
54            Target::IOS => "ios",
55            Target::Android => "android",
56        }
57    }
58}
59
60/// Renderer trait that all platforms must implement
61pub trait Renderer {
62    /// Render a virtual DOM node
63    fn render(&mut self, vnode: &crate::vdom::VNode);
64
65    /// Handle an event
66    fn handle_event(&mut self, event: Event);
67
68    /// Update the UI (call after state changes)
69    fn update(&mut self);
70}
71
72/// Platform-agnostic event
73#[derive(Debug, Clone)]
74pub enum Event {
75    /// Click/Tap event
76    Click { x: f32, y: f32 },
77    /// Key press
78    KeyPress { key: String },
79    /// Text input
80    TextInput { text: String },
81    /// Gesture (mobile)
82    Gesture(GestureEvent),
83}
84
85/// Mobile gesture events
86#[derive(Debug, Clone)]
87pub enum GestureEvent {
88    /// Swipe gesture
89    Swipe {
90        direction: SwipeDirection,
91        velocity: f32,
92    },
93    /// Pinch gesture (zoom)
94    Pinch { scale: f32 },
95    /// Long press
96    LongPress { x: f32, y: f32, duration: f32 },
97    /// Pan/Drag
98    Pan { dx: f32, dy: f32 },
99}
100
101#[derive(Debug, Clone, Copy)]
102pub enum SwipeDirection {
103    Up,
104    Down,
105    Left,
106    Right,
107}
108
109#[cfg(test)]
110mod tests {
111    use super::*;
112
113    #[test]
114    fn test_target_from_str() {
115        assert_eq!(Target::parse("desktop"), Some(Target::Desktop));
116        assert_eq!(Target::parse("web"), Some(Target::Web));
117        assert_eq!(Target::parse("ios"), Some(Target::IOS));
118        assert_eq!(Target::parse("android"), Some(Target::Android));
119        assert_eq!(Target::parse("invalid"), None);
120    }
121
122    #[test]
123    fn test_is_mobile() {
124        assert!(!Target::Desktop.is_mobile());
125        assert!(!Target::Web.is_mobile());
126        assert!(Target::IOS.is_mobile());
127        assert!(Target::Android.is_mobile());
128    }
129
130    #[test]
131    fn test_target_name() {
132        assert_eq!(Target::Desktop.name(), "desktop");
133        assert_eq!(Target::Web.name(), "web");
134        assert_eq!(Target::IOS.name(), "ios");
135        assert_eq!(Target::Android.name(), "android");
136    }
137}