use serde::{Deserialize, Serialize};
use crate::content::SurfaceContent;
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 = "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, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SurfaceInteraction {
pub close_button: bool,
pub dismiss: FloatDismiss,
pub modal: bool,
}
impl SurfaceInteraction {
pub const fn standard() -> Self {
Self {
close_button: false,
dismiss: FloatDismiss::TapOutside,
modal: false,
}
}
pub const fn url_callback() -> Self {
Self {
close_button: true,
dismiss: FloatDismiss::Manual,
modal: true,
}
}
pub const fn window() -> Self {
Self {
close_button: false,
dismiss: FloatDismiss::Manual,
modal: false,
}
}
}
impl Default for SurfaceInteraction {
fn default() -> Self {
Self::standard()
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FloatSpec {
pub anchor: FloatAnchor,
pub dismiss: FloatDismiss,
pub modal: bool,
pub close_button: bool,
}
impl Default for FloatSpec {
fn default() -> Self {
Self {
anchor: FloatAnchor::Screen,
dismiss: FloatDismiss::TapOutside,
modal: false,
close_button: 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 lxapp(id: impl Into<SurfaceId>, role: Role, app_id: impl Into<String>) -> Self {
Self {
id: id.into(),
role,
content: SurfaceContent::Lxapp {
app_id: app_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 native(id: impl Into<SurfaceId>, role: Role, capability: impl Into<String>) -> Self {
Self::native_instance(id, role, capability, None)
}
pub fn native_instance(
id: impl Into<SurfaceId>,
role: Role,
capability: impl Into<String>,
instance_key: Option<String>,
) -> Self {
Self {
id: id.into(),
role,
content: SurfaceContent::Native {
capability: capability.into(),
instance_key,
},
owner: SurfaceOwner::Host,
placement: Placement::default(),
state: SurfaceState::Mounted,
float: (role == Role::Float).then(FloatSpec::default),
}
}
pub fn browser(id: impl Into<SurfaceId>, role: Role, initial_url: impl Into<String>) -> Self {
Self {
id: id.into(),
role,
content: SurfaceContent::Browser {
initial_url: initial_url.into(),
reuse_by_url: true,
},
owner: SurfaceOwner::Host,
placement: Placement::default(),
state: SurfaceState::Mounted,
float: (role == Role::Float).then(FloatSpec::default),
}
}
pub fn is_modal_float(&self) -> bool {
self.role == Role::Float && self.float.as_ref().is_some_and(|f| f.modal)
}
}