use std::sync::{Arc, Mutex};
use dioxus_core::prelude::{consume_context, try_consume_context, use_hook};
use dioxus_signals::{Readable, Signal};
use freya_common::EventMessage;
use tokio::sync::{broadcast, mpsc::UnboundedSender};
use torin::geometry::Size2D;
use winit::{dpi::PhysicalSize, event_loop::EventLoopProxy, window::CursorIcon};
#[derive(Clone, Copy, PartialEq)]
pub struct UsePlatform {
ticker: Signal<Arc<broadcast::Receiver<()>>>,
event_loop_proxy: Signal<Option<EventLoopProxy<EventMessage>>>,
platform_emitter: Signal<Option<UnboundedSender<EventMessage>>>,
platform_information: Signal<Arc<Mutex<PlatformInformation>>>,
}
#[derive(PartialEq, Eq, Debug)]
pub enum UsePlatformError {
EventLoopProxyFailed,
PlatformEmitterFailed,
}
impl UsePlatform {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
UsePlatform {
event_loop_proxy: Signal::new(try_consume_context::<EventLoopProxy<EventMessage>>()),
platform_emitter: Signal::new(try_consume_context::<UnboundedSender<EventMessage>>()),
ticker: Signal::new(consume_context::<Arc<broadcast::Receiver<()>>>()),
platform_information: Signal::new(consume_context::<Arc<Mutex<PlatformInformation>>>()),
}
}
pub fn send(&self, event: EventMessage) -> Result<(), UsePlatformError> {
if let Some(event_loop_proxy) = &*self.event_loop_proxy.peek() {
event_loop_proxy
.send_event(event)
.map_err(|_| UsePlatformError::EventLoopProxyFailed)?;
} else if let Some(platform_emitter) = &*self.platform_emitter.peek() {
platform_emitter
.send(event)
.map_err(|_| UsePlatformError::PlatformEmitterFailed)?;
}
Ok(())
}
pub fn set_cursor(&self, cursor_icon: CursorIcon) {
self.send(EventMessage::SetCursorIcon(cursor_icon)).ok();
}
pub fn request_animation_frame(&self) {
self.send(EventMessage::RequestRerender).ok();
}
pub fn new_ticker(&self) -> Ticker {
Ticker {
inner: self.ticker.peek().resubscribe(),
}
}
pub fn info(&self) -> PlatformInformation {
self.platform_information.read().lock().unwrap().clone()
}
}
pub fn use_platform() -> UsePlatform {
use_hook(UsePlatform::new)
}
pub struct Ticker {
inner: broadcast::Receiver<()>,
}
impl Ticker {
pub async fn tick(&mut self) {
self.inner.recv().await.ok();
}
}
#[derive(Clone)]
pub struct PlatformInformation {
pub window_size: Size2D,
}
impl PlatformInformation {
pub fn from_winit(physical_size: PhysicalSize<u32>) -> Self {
Self {
window_size: Size2D::new(physical_size.width as f32, physical_size.height as f32),
}
}
pub fn new(window_size: Size2D) -> Self {
Self { window_size }
}
}