use js_sys::{Function, Object, Reflect};
use serde::Serialize;
use wasm_bindgen::{JsCast, JsValue, prelude::Closure};
use crate::logger;
pub struct EventHandle<T: ?Sized> {
pub(super) target: Object,
pub(super) method: &'static str,
pub(super) event: Option<String>,
pub(super) callback: Closure<T>,
pub(super) unregistered: bool
}
impl<T: ?Sized> EventHandle<T> {
pub(super) fn new(
target: Object,
method: &'static str,
event: Option<String>,
callback: Closure<T>
) -> Self {
Self {
target,
method,
event,
callback,
unregistered: false
}
}
pub(crate) fn unregister(mut self) -> Result<(), JsValue> {
if self.unregistered {
return Ok(());
}
let f = Reflect::get(&self.target, &self.method.into())?;
let func = f
.dyn_ref::<Function>()
.ok_or_else(|| JsValue::from_str(&format!("{} is not a function", self.method)))?;
match &self.event {
Some(event) => func.call2(
&self.target,
&event.clone().into(),
self.callback.as_ref().unchecked_ref()
)?,
None => func.call1(&self.target, self.callback.as_ref().unchecked_ref())?
};
self.unregistered = true;
Ok(())
}
}
impl<T: ?Sized> Drop for EventHandle<T> {
fn drop(&mut self) {
if self.unregistered {
return;
}
let f = match Reflect::get(&self.target, &self.method.into()) {
Ok(f) => f,
Err(_) => {
logger::error("Failed to get unregister method");
return;
}
};
let func = match f.dyn_ref::<Function>() {
Some(func) => func,
None => {
logger::error(&format!("{} is not a function", self.method));
return;
}
};
let result = match &self.event {
Some(event) => func.call2(
&self.target,
&event.clone().into(),
self.callback.as_ref().unchecked_ref()
),
None => func.call1(&self.target, self.callback.as_ref().unchecked_ref())
};
if result.is_err() {
logger::error("Failed to unregister event callback");
}
self.unregistered = true;
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BottomButton {
Main,
Secondary
}
impl BottomButton {
pub(super) const fn js_name(self) -> &'static str {
match self {
BottomButton::Main => "MainButton",
BottomButton::Secondary => "SecondaryButton"
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize)]
#[serde(rename_all = "lowercase")]
pub enum SecondaryButtonPosition {
Top,
Left,
Bottom,
Right
}
impl SecondaryButtonPosition {
pub(super) fn from_js_value(value: JsValue) -> Option<Self> {
let as_str = value.as_string()?;
match as_str.as_str() {
"top" => Some(Self::Top),
"left" => Some(Self::Left),
"bottom" => Some(Self::Bottom),
"right" => Some(Self::Right),
_ => None
}
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct SafeAreaInset {
pub top: f64,
pub bottom: f64,
pub left: f64,
pub right: f64
}
impl SafeAreaInset {
pub(super) fn from_js(value: JsValue) -> Option<Self> {
let object = value.dyn_into::<Object>().ok()?;
let top = Reflect::get(&object, &"top".into()).ok()?.as_f64()?;
let bottom = Reflect::get(&object, &"bottom".into()).ok()?.as_f64()?;
let left = Reflect::get(&object, &"left".into()).ok()?.as_f64()?;
let right = Reflect::get(&object, &"right".into()).ok()?.as_f64()?;
Some(Self {
top,
bottom,
left,
right
})
}
}
#[derive(Debug, Default, Serialize)]
pub struct BottomButtonParams<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_color: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_active: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_visible: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub has_shine_effect: Option<bool>,
#[serde(
skip_serializing_if = "Option::is_none",
rename = "icon_custom_emoji_id"
)]
pub icon_custom_emoji_id: Option<&'a str>
}
#[derive(Debug, Default, Serialize)]
pub struct SecondaryButtonParams<'a> {
#[serde(flatten)]
pub common: BottomButtonParams<'a>,
#[serde(skip_serializing_if = "Option::is_none")]
pub position: Option<SecondaryButtonPosition>
}
#[derive(Debug, Default, Serialize)]
pub struct OpenLinkOptions {
#[serde(skip_serializing_if = "Option::is_none")]
pub try_instant_view: Option<bool>
}
#[derive(Clone, Copy, Debug)]
pub enum BackgroundEvent {
MainButtonClicked,
BackButtonClicked,
SettingsButtonClicked,
WriteAccessRequested,
ContactRequested,
PhoneRequested,
InvoiceClosed,
PopupClosed,
QrTextReceived,
ClipboardTextReceived
}
impl BackgroundEvent {
pub(super) const fn as_str(self) -> &'static str {
match self {
BackgroundEvent::MainButtonClicked => "mainButtonClicked",
BackgroundEvent::BackButtonClicked => "backButtonClicked",
BackgroundEvent::SettingsButtonClicked => "settingsButtonClicked",
BackgroundEvent::WriteAccessRequested => "writeAccessRequested",
BackgroundEvent::ContactRequested => "contactRequested",
BackgroundEvent::PhoneRequested => "phoneRequested",
BackgroundEvent::InvoiceClosed => "invoiceClosed",
BackgroundEvent::PopupClosed => "popupClosed",
BackgroundEvent::QrTextReceived => "qrTextReceived",
BackgroundEvent::ClipboardTextReceived => "clipboardTextReceived"
}
}
}