mirror of
https://github.com/DioxusLabs/dioxus
synced 2024-11-23 04:33:06 +00:00
20d146d9bd
* improve documentation for the fullstack server context * Add a section about axum integration to the crate root docs * make serve_dioxus_application accept the cfg builder directly * remove unused server_fn module * improve fullstack config docs * improve documentation for the server function macro * fix axum router extension link * Fix doc tests * Fix launch builder * Simplify the launch builder * don't re-export launch in the prelude * refactor fullstack launch * Fix fullstack launch builder * Update static generation with the new builder api * fix some formatting/overly broad launch replacements * fix custom menu example * fix fullstack/static generation examples * Fix static generation launch * A few small formatting fixes * Fix a few doc tests * implement LaunchConfig for serve configs * fix fullstack launch with separate web and server launch methods * fix check with all features * dont expose inner core module * clippy and check * fix readme --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
218 lines
6 KiB
R
218 lines
6 KiB
R
#![allow(dead_code, unused)]
|
|
use dioxus::desktop::use_window;
|
|
use dioxus::prelude::*;
|
|
use std::{
|
|
process::exit,
|
|
time::{Duration, Instant},
|
|
};
|
|
use tokio::time::sleep;
|
|
|
|
fn main() {
|
|
dioxus::LaunchBuilder::desktop().launch(app);
|
|
}
|
|
|
|
struct WindowPreferences {
|
|
always_on_top: bool,
|
|
with_decorations: bool,
|
|
exiting: Option<Instant>,
|
|
}
|
|
|
|
impl Default for WindowPreferences {
|
|
fn default() -> Self {
|
|
Self {
|
|
with_decorations: true,
|
|
always_on_top: false,
|
|
exiting: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl WindowPreferences {
|
|
fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
struct Timer {
|
|
hours: u8,
|
|
minutes: u8,
|
|
seconds: u8,
|
|
started_at: Option<Instant>,
|
|
}
|
|
|
|
impl Timer {
|
|
fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
fn duration(&self) -> Duration {
|
|
Duration::from_secs(
|
|
(self.hours as u64 * 60 + self.minutes as u64) * 60 + self.seconds as u64,
|
|
)
|
|
}
|
|
}
|
|
|
|
const UPD_FREQ: Duration = Duration::from_millis(100);
|
|
|
|
fn exit_button(
|
|
delay: Duration,
|
|
label: fn(Signal<Option<Instant>>, Duration) -> Option<VNode>,
|
|
) -> Element {
|
|
let mut trigger: Signal<Option<Instant>> = use_signal(|| None);
|
|
use_future(move || async move {
|
|
loop {
|
|
sleep(UPD_FREQ).await;
|
|
if let Some(true) = trigger.read().map(|e| e.elapsed() > delay) {
|
|
exit(0);
|
|
}
|
|
}
|
|
});
|
|
let stuff: Option<VNode> = rsx! {
|
|
button {
|
|
onmouseup: move |_| {
|
|
trigger.set(None);
|
|
},
|
|
onmousedown: move |_| {
|
|
trigger.set(Some(Instant::now()));
|
|
},
|
|
width: 100,
|
|
{label(trigger, delay)}
|
|
}
|
|
};
|
|
stuff
|
|
}
|
|
|
|
fn app() -> Element {
|
|
let mut timer = use_signal(Timer::new);
|
|
let mut window_preferences = use_signal(WindowPreferences::new);
|
|
|
|
use_future(move || async move {
|
|
loop {
|
|
sleep(UPD_FREQ).await;
|
|
timer.with_mut(|t| {
|
|
if let Some(started_at) = t.started_at {
|
|
if t.duration().saturating_sub(started_at.elapsed()) == Duration::ZERO {
|
|
t.started_at = None;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
});
|
|
|
|
rsx! {
|
|
div {
|
|
{
|
|
let millis = timer
|
|
.with(|t| {
|
|
t.duration()
|
|
.saturating_sub(
|
|
t.started_at.map(|x| x.elapsed()).unwrap_or(Duration::ZERO),
|
|
)
|
|
.as_millis()
|
|
});
|
|
format!(
|
|
"{:02}:{:02}:{:02}.{:01}",
|
|
millis / 1000 / 3600 % 3600,
|
|
millis / 1000 / 60 % 60,
|
|
millis / 1000 % 60,
|
|
millis / 100 % 10,
|
|
)
|
|
}
|
|
}
|
|
div {
|
|
input {
|
|
r#type: "number",
|
|
min: 0,
|
|
max: 99,
|
|
value: format!("{:02}", timer.read().hours),
|
|
oninput: move |e| {
|
|
timer.write().hours = e.value().parse().unwrap_or(0);
|
|
},
|
|
}
|
|
|
|
input {
|
|
r#type: "number",
|
|
min: 0,
|
|
max: 59,
|
|
value: format!("{:02}", timer.read().minutes),
|
|
oninput: move |e| {
|
|
timer.write().minutes = e.value().parse().unwrap_or(0);
|
|
},
|
|
}
|
|
|
|
input {
|
|
r#type: "number",
|
|
min: 0,
|
|
max: 59,
|
|
value: format!("{:02}", timer.read().seconds),
|
|
oninput: move |e| {
|
|
timer.write().seconds = e.value().parse().unwrap_or(0);
|
|
},
|
|
}
|
|
}
|
|
|
|
button {
|
|
id: "start_stop",
|
|
onclick: move |_| {
|
|
timer
|
|
.with_mut(|t| {
|
|
t.started_at = if t.started_at.is_none() {
|
|
Some(Instant::now())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
},
|
|
{timer.with(|t| if t.started_at.is_none() { "Start" } else { "Stop" })}
|
|
}
|
|
div { id: "app",
|
|
button {
|
|
onclick: move |_| {
|
|
let decorations = window_preferences.read().with_decorations;
|
|
use_window().set_decorations(!decorations);
|
|
window_preferences.write().with_decorations = !decorations;
|
|
},
|
|
{
|
|
format!(
|
|
"with decorations{}",
|
|
if window_preferences.read().with_decorations { " ✓" } else { "" },
|
|
)
|
|
}
|
|
}
|
|
button {
|
|
onclick: move |_| {
|
|
window_preferences
|
|
.with_mut(|wp| {
|
|
use_window().set_always_on_top(!wp.always_on_top);
|
|
wp.always_on_top = !wp.always_on_top;
|
|
})
|
|
},
|
|
width: 100,
|
|
{
|
|
format!(
|
|
"always on top{}",
|
|
if window_preferences.read().always_on_top { " ✓" } else { "" },
|
|
)
|
|
}
|
|
}
|
|
}
|
|
{
|
|
exit_button(
|
|
Duration::from_secs(3),
|
|
|trigger, delay| {
|
|
rsx! {
|
|
{
|
|
format!(
|
|
"{:0.1?}",
|
|
trigger
|
|
.read()
|
|
.map(|inst| (delay.as_secs_f32() - inst.elapsed().as_secs_f32())),
|
|
)
|
|
}
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|
|
}
|