feat(comp/timer): add rest duration
This commit is contained in:
parent
7618fcb8a8
commit
82d75caee1
|
@ -1,6 +1,7 @@
|
|||
use druid::{Selector, WidgetId};
|
||||
|
||||
pub const OPEN_NOTIFIER_WINDOW: Selector<WidgetId> = Selector::new("hwt.cmd.win.notifier.open");
|
||||
pub const OPEN_NOTIFIER_WINDOW: Selector<(WidgetId, f64)> =
|
||||
Selector::new("hwt.cmd.win.notifier.open");
|
||||
pub const OPEN_IDLE_WINDOW: Selector<(WidgetId, f64)> = Selector::new("hwt.cmd.win.idle.open");
|
||||
|
||||
pub const DEINIT_COMP: Selector = Selector::new("hwt.cmd.comp.deinit");
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::cmd;
|
||||
use crate::comp;
|
||||
use crate::env;
|
||||
use crate::state;
|
||||
use druid::widget::{Flex, Label};
|
||||
use druid::{Key, Widget, WidgetExt};
|
||||
|
@ -9,17 +8,21 @@ pub fn build(
|
|||
name: &str,
|
||||
duration_env_key: Key<f64>,
|
||||
postpone_duration_env_key: Key<f64>,
|
||||
rest_duration_env_key: Key<f64>,
|
||||
) -> impl Widget<state::BreakTimer> {
|
||||
let name_label = Label::new(name);
|
||||
Flex::row().with_child(name_label).with_child(
|
||||
comp::timer::build()
|
||||
.controller(
|
||||
comp::timer::TimerController::new(|ctx| {
|
||||
comp::timer::TimerController::new(|ctx, rest_duration_secs| {
|
||||
ctx.submit_command(cmd::PAUSE_ALL_TIMER_COMP);
|
||||
ctx.submit_command(cmd::OPEN_NOTIFIER_WINDOW.with(ctx.widget_id()))
|
||||
ctx.submit_command(
|
||||
cmd::OPEN_NOTIFIER_WINDOW.with((ctx.widget_id(), rest_duration_secs)),
|
||||
)
|
||||
})
|
||||
.with_duration_env(duration_env_key.clone())
|
||||
.with_postpone_duration_env(postpone_duration_env_key.clone()),
|
||||
.with_postpone_duration_env(postpone_duration_env_key.clone())
|
||||
.with_rest_duration_env(rest_duration_env_key.clone()),
|
||||
)
|
||||
.lens(state::BreakTimer::work_timer),
|
||||
)
|
||||
|
|
|
@ -18,18 +18,19 @@ pub struct TimerController {
|
|||
env_duration: Key<f64>,
|
||||
env_init_duration: Option<Key<f64>>,
|
||||
env_postpone_duration: Option<Key<f64>>,
|
||||
env_rest_duration: Option<Key<f64>>,
|
||||
start_time: Instant,
|
||||
pause_time: Option<Instant>,
|
||||
render_timer_id: TimerToken,
|
||||
finish_timer_id: TimerToken,
|
||||
finish_handler: Option<Box<dyn Fn(&mut EventCtx)>>,
|
||||
finish_handler: Option<Box<dyn Fn(&mut EventCtx, f64)>>,
|
||||
postpone_times: u32,
|
||||
}
|
||||
|
||||
impl TimerController {
|
||||
pub fn new<Handler>(finish_handler: Handler) -> Self
|
||||
where
|
||||
Handler: Fn(&mut EventCtx) + 'static,
|
||||
Handler: Fn(&mut EventCtx, f64) + 'static,
|
||||
{
|
||||
Self {
|
||||
finish_handler: Some(Box::new(finish_handler)),
|
||||
|
@ -44,6 +45,7 @@ impl Default for TimerController {
|
|||
env_duration: env::TIMER_DURATION,
|
||||
env_init_duration: None,
|
||||
env_postpone_duration: None,
|
||||
env_rest_duration: None,
|
||||
start_time: Instant::now(),
|
||||
pause_time: None,
|
||||
render_timer_id: TimerToken::INVALID,
|
||||
|
@ -69,6 +71,11 @@ impl TimerController {
|
|||
self.env_postpone_duration = Some(key);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_rest_duration_env(mut self, key: Key<f64>) -> Self {
|
||||
self.env_rest_duration = Some(key);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<W> Controller<state::Timer, W> for TimerController
|
||||
|
@ -108,7 +115,7 @@ where
|
|||
}
|
||||
Event::Timer(id) if *id == self.finish_timer_id => {
|
||||
if let Some(finish_handler) = &self.finish_handler {
|
||||
finish_handler(ctx);
|
||||
finish_handler(ctx, self.full_rest_duration(env).as_secs_f64());
|
||||
}
|
||||
}
|
||||
Event::Command(cmd) if cmd.is(cmd::PAUSE_ALL_TIMER_COMP) => {
|
||||
|
@ -154,6 +161,31 @@ where
|
|||
}
|
||||
|
||||
impl TimerController {
|
||||
fn full_rest_duration(&self, env: &Env) -> Duration {
|
||||
self.rest_duration(env) + self.postpone_times * self.postpone_rest_duration(env)
|
||||
}
|
||||
|
||||
fn postpone_rest_duration(&self, env: &Env) -> Duration {
|
||||
match (&self.env_postpone_duration, &self.env_rest_duration) {
|
||||
(Some(_), Some(_)) => {
|
||||
let duration = self.duration(env).as_secs_f64();
|
||||
let rest_duration = self.rest_duration(env).as_secs_f64();
|
||||
let postpone_duration = self.postpone_duration(env).as_secs_f64();
|
||||
|
||||
let rest_per_sec = rest_duration / duration;
|
||||
Duration::from_secs_f64(postpone_duration * rest_per_sec)
|
||||
}
|
||||
_ => Duration::ZERO,
|
||||
}
|
||||
}
|
||||
|
||||
fn rest_duration(&self, env: &Env) -> Duration {
|
||||
match &self.env_rest_duration {
|
||||
None => Duration::ZERO,
|
||||
Some(key) => Duration::from_secs_f64(env.get(key)),
|
||||
}
|
||||
}
|
||||
|
||||
fn full_duration(&self, env: &Env) -> Duration {
|
||||
self.duration(env) + self.postpone_times * self.postpone_duration(env)
|
||||
}
|
||||
|
|
|
@ -17,13 +17,13 @@ impl AppDelegate<state::App> for Delegate {
|
|||
) -> Handled {
|
||||
match cmd {
|
||||
_ if cmd.is(cmd::OPEN_NOTIFIER_WINDOW) => {
|
||||
let widget_id = *cmd.get_unchecked(cmd::OPEN_NOTIFIER_WINDOW);
|
||||
ctx.new_window(win::notifier::create(widget_id));
|
||||
let (widget_id, rest_duration_secs) = *cmd.get_unchecked(cmd::OPEN_NOTIFIER_WINDOW);
|
||||
ctx.new_window(win::notifier::create(widget_id, rest_duration_secs));
|
||||
Handled::Yes
|
||||
}
|
||||
_ if cmd.is(cmd::OPEN_IDLE_WINDOW) => {
|
||||
let (widget_id, rest_duration) = *cmd.get_unchecked(cmd::OPEN_IDLE_WINDOW);
|
||||
ctx.new_window(win::rest::create(widget_id, rest_duration));
|
||||
let (widget_id, rest_duration_secs) = *cmd.get_unchecked(cmd::OPEN_IDLE_WINDOW);
|
||||
ctx.new_window(win::rest::create(widget_id, rest_duration_secs));
|
||||
Handled::Yes
|
||||
}
|
||||
_ => Handled::No,
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::state;
|
|||
use druid::widget::{Button, Flex};
|
||||
use druid::{MenuDesc, Target, Widget, WidgetExt, WidgetId, WindowDesc};
|
||||
|
||||
pub fn create(parent_widget_id: WidgetId) -> WindowDesc<state::App> {
|
||||
pub fn create(parent_widget_id: WidgetId, rest_duration_secs: f64) -> WindowDesc<state::App> {
|
||||
let win_width = 200.0;
|
||||
let win_height = 100.0;
|
||||
|
||||
|
@ -13,7 +13,7 @@ pub fn create(parent_widget_id: WidgetId) -> WindowDesc<state::App> {
|
|||
let x = (rect.width() - win_width) / 2.0;
|
||||
let y = 0.0;
|
||||
|
||||
return WindowDesc::new(move || build(parent_widget_id))
|
||||
return WindowDesc::new(move || build(parent_widget_id, rest_duration_secs))
|
||||
.show_titlebar(false)
|
||||
.menu(MenuDesc::empty())
|
||||
.set_position((x, y))
|
||||
|
@ -21,22 +21,27 @@ pub fn create(parent_widget_id: WidgetId) -> WindowDesc<state::App> {
|
|||
.window_size((win_width, win_height));
|
||||
}
|
||||
|
||||
fn build(parent_widget_id: WidgetId) -> impl Widget<state::App> {
|
||||
fn build(parent_widget_id: WidgetId, rest_duration_secs: f64) -> impl Widget<state::App> {
|
||||
Flex::column()
|
||||
.with_child(build_notifier_timer(parent_widget_id).lens(state::App::notifier))
|
||||
.with_child(
|
||||
build_notifier_timer(parent_widget_id, rest_duration_secs).lens(state::App::notifier),
|
||||
)
|
||||
.with_default_spacer()
|
||||
.with_child(build_postpone_btn(parent_widget_id))
|
||||
.padding((8.0, 8.0))
|
||||
}
|
||||
|
||||
fn build_notifier_timer(parent_widget_id: WidgetId) -> impl Widget<state::Timer> {
|
||||
fn build_notifier_timer(
|
||||
parent_widget_id: WidgetId,
|
||||
rest_duration_secs: f64,
|
||||
) -> impl Widget<state::Timer> {
|
||||
comp::timer::build()
|
||||
.controller(
|
||||
comp::timer::TimerController::new(move |ctx| {
|
||||
comp::timer::TimerController::new(move |ctx, _| {
|
||||
ctx.submit_command(cmd::DEINIT_COMP.to(Target::Widget(ctx.widget_id())));
|
||||
ctx.submit_command(
|
||||
cmd::OPEN_IDLE_WINDOW
|
||||
.with((parent_widget_id, 30.0))
|
||||
.with((parent_widget_id, rest_duration_secs))
|
||||
.to(Target::Global),
|
||||
);
|
||||
ctx.submit_command(druid::commands::CLOSE_WINDOW);
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::state;
|
|||
use druid::widget::Flex;
|
||||
use druid::{MenuDesc, Target, Widget, WidgetExt, WidgetId, WindowDesc};
|
||||
|
||||
pub fn create(parent_widget_id: WidgetId, rest_duration: f64) -> WindowDesc<state::App> {
|
||||
pub fn create(parent_widget_id: WidgetId, rest_duration_secs: f64) -> WindowDesc<state::App> {
|
||||
let win_width = 450.0;
|
||||
let win_height = 200.0;
|
||||
|
||||
|
@ -13,7 +13,7 @@ pub fn create(parent_widget_id: WidgetId, rest_duration: f64) -> WindowDesc<stat
|
|||
let x = (rect.width() - win_width) / 2.0;
|
||||
let y = (rect.height() - win_height) / 2.0;
|
||||
|
||||
return WindowDesc::new(move || build(parent_widget_id, rest_duration))
|
||||
return WindowDesc::new(move || build(parent_widget_id, rest_duration_secs))
|
||||
.show_titlebar(false)
|
||||
.menu(MenuDesc::empty())
|
||||
.set_position((x, y))
|
||||
|
@ -21,16 +21,21 @@ pub fn create(parent_widget_id: WidgetId, rest_duration: f64) -> WindowDesc<stat
|
|||
.window_size((win_width, win_height));
|
||||
}
|
||||
|
||||
fn build(parent_widget_id: WidgetId, rest_duration: f64) -> impl Widget<state::App> {
|
||||
fn build(parent_widget_id: WidgetId, rest_duration_secs: f64) -> impl Widget<state::App> {
|
||||
Flex::column()
|
||||
.with_child(build_idle_timer(parent_widget_id, rest_duration).lens(state::App::notifier))
|
||||
.with_child(
|
||||
build_idle_timer(parent_widget_id, rest_duration_secs).lens(state::App::notifier),
|
||||
)
|
||||
.padding((8.0, 8.0))
|
||||
}
|
||||
|
||||
fn build_idle_timer(parent_widget_id: WidgetId, rest_duration: f64) -> impl Widget<state::Timer> {
|
||||
fn build_idle_timer(
|
||||
parent_widget_id: WidgetId,
|
||||
rest_duration_secs: f64,
|
||||
) -> impl Widget<state::Timer> {
|
||||
comp::timer::build()
|
||||
.controller(
|
||||
comp::timer::TimerController::new(move |ctx| {
|
||||
comp::timer::TimerController::new(move |ctx, _| {
|
||||
ctx.submit_command(cmd::DEINIT_COMP.to(Target::Widget(ctx.widget_id())));
|
||||
ctx.submit_command(cmd::UNPAUSE_ALL_TIMER_COMP.with(false).to(Target::Global));
|
||||
ctx.submit_command(cmd::RESTART_TIMER_COMP.to(Target::Widget(parent_widget_id)));
|
||||
|
@ -39,5 +44,5 @@ fn build_idle_timer(parent_widget_id: WidgetId, rest_duration: f64) -> impl Widg
|
|||
.with_init_duration_env(env::BREAK_NOTIFIER_TIMER_DURATION),
|
||||
)
|
||||
.controller(comp::deinit::DeinitController::default())
|
||||
.env_scope(move |env, _| env.set(env::TIMER_DURATION, rest_duration))
|
||||
.env_scope(move |env, _| env.set(env::TIMER_DURATION, rest_duration_secs))
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ fn build() -> impl Widget<state::App> {
|
|||
"Micro",
|
||||
env::MICRO_BREAK_TIMER_DURATION,
|
||||
env::MICRO_BREAK_TIMER_POSTPONE_DURATION,
|
||||
env::MICRO_BREAK_TIMER_REST_DURATION,
|
||||
)
|
||||
.lens(state::App::micro_break),
|
||||
)
|
||||
|
@ -32,6 +33,7 @@ fn build() -> impl Widget<state::App> {
|
|||
"Rest",
|
||||
env::REST_BREAK_TIMER_DURATION,
|
||||
env::REST_BREAK_TIMER_POSTPONE_DURATION,
|
||||
env::REST_BREAK_TIMER_REST_DURATION,
|
||||
)
|
||||
.lens(state::App::rest_break),
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue