use serde::{Deserialize, Serialize};
pub type SurfaceId = String;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Role {
Main,
Aside,
Float,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Edge {
Left,
Right,
Top,
Bottom,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "lowercase")]
pub enum SurfaceContent {
Entry {
id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
path: Option<String>,
},
Web { url: String },
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "scope", rename_all = "camelCase")]
pub enum SurfaceOwner {
Page { page_instance_id: String },
Lxapp { app_id: String },
Host,
}
#[derive(Debug, Clone, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Placement {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub edge: Option<Edge>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub preferred_size: Option<f64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SurfaceState {
Mounted,
Hidden,
Minimized,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(tag = "to", rename_all = "lowercase")]
pub enum FloatAnchor {
Screen,
Surface { surface_id: SurfaceId },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum FloatDismiss {
TapOutside,
Manual,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FloatSpec {
pub anchor: FloatAnchor,
pub dismiss: FloatDismiss,
pub modal: bool,
}
impl Default for FloatSpec {
fn default() -> Self {
Self {
anchor: FloatAnchor::Screen,
dismiss: FloatDismiss::TapOutside,
modal: false,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Surface {
pub id: SurfaceId,
pub role: Role,
pub content: SurfaceContent,
pub owner: SurfaceOwner,
#[serde(default)]
pub placement: Placement,
pub state: SurfaceState,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub float: Option<FloatSpec>,
}
impl Surface {
pub fn entry(id: impl Into<SurfaceId>, role: Role, entry_id: impl Into<String>) -> Self {
Self {
id: id.into(),
role,
content: SurfaceContent::Entry {
id: entry_id.into(),
path: None,
},
owner: SurfaceOwner::Host,
placement: Placement::default(),
state: SurfaceState::Mounted,
float: if role == Role::Float {
Some(FloatSpec::default())
} else {
None
},
}
}
pub fn is_modal_float(&self) -> bool {
self.role == Role::Float && self.float.as_ref().is_some_and(|f| f.modal)
}
}