Skip to main content

lingxia_platform/traits/
ui.rs

1use std::future::Future;
2
3use lingxia_surface::LayoutPresentationPlan;
4
5use crate::error::PlatformError;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum ToastIcon {
9    Success,
10    Error,
11    Loading,
12    None,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum ToastPosition {
17    Top,
18    Center,
19    Bottom,
20}
21
22#[derive(Debug, Clone)]
23pub struct ToastOptions {
24    pub title: String,
25    pub icon: ToastIcon,
26    pub image: Option<String>,
27    pub duration: f64,
28    pub mask: bool,
29    pub position: ToastPosition,
30}
31
32#[derive(Debug, Clone)]
33pub struct ModalOptions {
34    pub title: String,
35    pub content: String,
36    pub show_cancel: bool,
37    pub cancel_text: String,
38    pub cancel_color: Option<String>,
39    pub confirm_text: String,
40    pub confirm_color: Option<String>,
41}
42
43#[repr(i32)]
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub enum SurfaceKind {
46    Window = 0,
47    Overlay = 1,
48}
49
50/// The arbitrated role that drives how the platform presents a surface:
51/// `Main` = a top-level window/primary, `Aside` = a docked split companion,
52/// `Float` = a positioned popup (it keeps its edge/center placement but never
53/// splits the main). Distinguishes a float-popup-at-edge from an aside-dock.
54#[repr(i32)]
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
56pub enum SurfaceRole {
57    #[default]
58    Main = 0,
59    Aside = 1,
60    Float = 2,
61}
62
63#[repr(i32)]
64#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
65pub enum SurfaceContent {
66    #[default]
67    Page = 0,
68    Url = 1,
69}
70
71#[repr(i32)]
72#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
73pub enum SurfacePosition {
74    #[default]
75    Center = 0,
76    Bottom = 1,
77    Left = 2,
78    Right = 3,
79    Top = 4,
80}
81
82#[derive(Debug, Clone)]
83pub struct SurfaceRequest {
84    pub id: String,
85    pub app_id: String,
86    pub path: String,
87    pub session_id: u64,
88    pub page_instance_id: String,
89    pub content: SurfaceContent,
90    pub kind: SurfaceKind,
91    pub width: f64,
92    pub height: f64,
93    pub width_ratio: f64,
94    pub height_ratio: f64,
95    pub position: SurfacePosition,
96    /// Arbitrated role; the platform uses it to decide dock vs popup vs window.
97    pub role: SurfaceRole,
98    /// Resolved interaction contract. Platforms render this verbatim.
99    pub interaction: lingxia_surface::SurfaceInteraction,
100    /// `Url` content only: isolate the WebView's cookies/site storage from
101    /// shared persistent data and discard them when the surface closes (auth
102    /// handoffs). `Page` content ignores it.
103    pub ephemeral_web_data: bool,
104    /// `Url` content only: navigation is paired with a native callback
105    /// interception channel. Platforms use this to keep local-file access out
106    /// of callback surfaces without restricting ordinary browser surfaces.
107    pub url_callback: bool,
108}
109
110pub trait SurfacePresenter: Send + Sync + 'static {
111    /// The shared core resolves a `LayoutPresentationPlan` for one window/graph
112    /// and the platform skin binds it. The per-surface methods below present a
113    /// single surface at a time.
114    fn present_layout(
115        &self,
116        _window_id: &str,
117        _plan: &LayoutPresentationPlan,
118    ) -> Result<(), PlatformError> {
119        Err(PlatformError::NotSupported(
120            "present_layout is not supported on this platform".to_string(),
121        ))
122    }
123
124    fn present_surface(&self, _request: SurfaceRequest) -> Result<(), PlatformError> {
125        Err(PlatformError::NotSupported(
126            "surface is not supported on this platform".to_string(),
127        ))
128    }
129
130    fn close_surface(&self, _app_id: &str, _id: &str, _reason: &str) -> Result<(), PlatformError> {
131        Err(PlatformError::NotSupported(
132            "surface close is not supported on this platform".to_string(),
133        ))
134    }
135
136    fn show_surface(&self, _app_id: &str, _id: &str) -> Result<(), PlatformError> {
137        Err(PlatformError::NotSupported(
138            "surface show is not supported on this platform".to_string(),
139        ))
140    }
141
142    fn hide_surface(&self, _app_id: &str, _id: &str) -> Result<(), PlatformError> {
143        Err(PlatformError::NotSupported(
144            "surface hide is not supported on this platform".to_string(),
145        ))
146    }
147
148    /// Show or hide a top-level surface declared by the host (e.g. the AI-chat
149    /// panel or terminal in `ui` config). `edge` overrides the declared edge
150    /// for this show (the panel moves if already visible); `None` keeps the
151    /// current placement. Only platforms with a host shell that manages
152    /// declared surfaces (currently macOS) support it; others have no such
153    /// shell and return `NotSupported`.
154    fn set_managed_surface_visible(
155        &self,
156        _id: &str,
157        _visible: bool,
158        _edge: Option<&str>,
159    ) -> Result<(), PlatformError> {
160        Err(PlatformError::NotSupported(
161            "managed surfaces are not supported on this platform".to_string(),
162        ))
163    }
164
165    /// Toggle a host-declared top-level surface's visibility. See
166    /// [`set_managed_surface_visible`](Self::set_managed_surface_visible).
167    fn toggle_managed_surface(&self, _id: &str) -> Result<(), PlatformError> {
168        Err(PlatformError::NotSupported(
169            "managed surfaces are not supported on this platform".to_string(),
170        ))
171    }
172}
173
174pub trait UIUpdate: Send + Sync + 'static {
175    fn update_navbar_ui(&self, appid: String) -> Result<(), PlatformError>;
176    fn update_tabbar_ui(&self, appid: String) -> Result<(), PlatformError>;
177
178    fn update_tabbar_ui_async(
179        &self,
180        appid: String,
181    ) -> impl Future<Output = Result<(), PlatformError>> + Send {
182        async move { self.update_tabbar_ui(appid) }
183    }
184
185    fn update_orientation_ui(&self, _appid: String) -> Result<(), PlatformError> {
186        Err(PlatformError::NotSupported(
187            "update_orientation_ui not implemented for this platform".to_string(),
188        ))
189    }
190}
191
192pub trait UserFeedback: Send + Sync + 'static {
193    fn show_toast(&self, options: ToastOptions) -> Result<(), PlatformError>;
194    fn hide_toast(&self) -> Result<(), PlatformError>;
195
196    fn show_modal(
197        &self,
198        options: ModalOptions,
199    ) -> impl Future<Output = Result<String, PlatformError>> + Send;
200
201    fn show_action_sheet(
202        &self,
203        options: Vec<String>,
204        cancel_text: String,
205        item_color: String,
206    ) -> impl Future<Output = Result<String, PlatformError>> + Send;
207}