use crate::util::Real32;
use serde::{Deserialize, Serialize};
use std::fmt::{Debug, Display, Formatter};
#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct ModalButton {
pub actions: Vec<Action>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
pub text: String,
}
impl ModalButton {
#[must_use]
pub fn new(text: impl Into<String>) -> Self {
let text = text.into();
assert!(!text.is_empty());
Self {
actions: Vec::new(),
id: String::new(),
text,
}
}
#[must_use]
pub fn with_actions(mut self, actions: impl IntoIterator<Item = Action>) -> Self {
self.actions.extend(actions);
self
}
#[must_use]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id = id.as_ref().to_string();
self
}
}
pub fn modal_button(text: impl Into<String>, actions: impl Into<Vec<Action>>) -> ModalButton {
ModalButton {
actions: actions.into(),
id: String::new(),
text: text.into(),
}
}
#[derive(Clone, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub struct Action {
pub typ: String,
#[serde(default, skip_serializing_if = "crate::is_default")]
pub aspect_ratio: Option<Real32>,
#[serde(default, skip_serializing_if = "crate::is_default")]
pub buttons: Vec<ModalButton>,
#[serde(default, skip_serializing_if = "String::is_empty")]
pub id: String,
#[serde(default, skip_serializing_if = "crate::is_default")]
pub message: String,
#[serde(default, skip_serializing_if = "crate::is_default")]
pub on_user_error_poll: bool,
#[serde(default, skip_serializing_if = "crate::is_default")]
pub page: String,
#[serde(default, skip_serializing_if = "crate::is_default")]
pub string_value: String,
#[serde(default, skip_serializing_if = "crate::is_default")]
pub title: String,
#[serde(default, skip_serializing_if = "crate::is_default")]
pub url: String,
#[serde(default, skip_serializing_if = "crate::is_default")]
var_name: String,
}
impl Action {
pub fn new(typ: impl Display) -> Self {
Action {
typ: typ.to_string(),
aspect_ratio: None,
buttons: Vec::new(),
id: String::new(),
message: String::new(),
on_user_error_poll: false,
page: String::new(),
string_value: String::new(),
title: String::new(),
url: String::new(),
var_name: String::new(),
}
}
#[must_use]
pub fn with_id(mut self, id: impl AsRef<str>) -> Self {
self.id = id.as_ref().to_string();
self
}
}
impl Debug for Action {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
serde_json::to_string(self)
.unwrap_or_else(|_| "Action<failed serializing>".to_string())
)
}
}
#[must_use]
pub fn choose_photo(upload_url: impl Display, aspect_ratio: Option<f32>) -> Action {
let mut action = Action::new("choose_photo");
action.aspect_ratio = aspect_ratio.map(Real32::new);
action.url = upload_url.to_string();
action
}
#[must_use]
pub fn copy_to_clipboard(text: impl Display) -> Action {
let mut action = Action::new("copy_to_clipboard");
action.string_value = text.to_string();
action
}
#[must_use]
pub fn launch_url(url: impl Display) -> Action {
let mut action = Action::new("launch_url");
action.url = url.to_string();
action
}
#[must_use]
pub fn logout() -> Action {
Action::new("logout")
}
#[allow(clippy::implicit_hasher)]
#[must_use]
pub fn modal(
title: impl Into<String>,
message: Option<String>,
buttons: impl Into<Vec<ModalButton>>,
) -> Action {
let mut action = Action::new("modal");
action.title = title.into();
action.message = message.unwrap_or_default();
action.buttons = buttons.into();
action
}
#[must_use]
pub fn poll() -> Action {
Action::new("poll")
}
#[must_use]
pub fn pop() -> Action {
Action::new("pop")
}
#[must_use]
pub fn push(page_key: impl Display) -> Action {
let mut action = Action::new("push");
action.page = page_key.to_string();
action
}
#[must_use]
pub fn replace_all(page_key: impl Display) -> Action {
let mut action = Action::new("replace_all");
action.page = page_key.to_string();
action
}
#[must_use]
pub fn reset_var(var_name: impl Display) -> Action {
let mut action = Action::new("reset_var");
action.var_name = var_name.to_string();
action
}
#[must_use]
pub fn rpc(url: impl Display, on_user_error_poll: bool) -> Action {
let mut action = Action::new("rpc");
action.url = url.to_string();
action.on_user_error_poll = on_user_error_poll;
action
}
#[must_use]
pub fn stop_actions() -> Action {
Action::new("stop_actions")
}
#[must_use]
pub fn take_photo(upload_url: impl Display, aspect_ratio: Option<f32>) -> Action {
let mut action = Action::new("take_photo");
action.aspect_ratio = aspect_ratio.map(Real32::new);
action.url = upload_url.to_string();
action
}