Files
MujicaUI/snooze_picker.go
T

140 lines
4.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package mujica
import (
"log/slog"
"time"
"github.com/egoist/mygo/ui"
"mujicaui/internal"
"mujicaui/theme"
)
// SnoozePickerOptions configure a SnoozePicker.
type SnoozePickerOptions struct {
// Location is the user's time zone; nil means local.
Location *time.Location
// MorningHour defaults to 9; valid values are 0–23.
MorningHour int
// Now defaults to the frame clock.
Now time.Time
Disabled bool
}
// SnoozeChoice pairs a message key with a reminder time.
type SnoozeChoice struct {
Key string
At time.Time
}
// SnoozeChoices returns localized-day shortcuts using morning hours.
func SnoozeChoices(now time.Time, morning int) []SnoozeChoice {
if morning < 0 || morning > 23 {
panic("mujica: SnoozeChoices morning outside 0..23")
}
day := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
at := func(days int) time.Time {
return time.Date(day.Year(), day.Month(), day.Day()+days, morning, 0, 0, 0, now.Location())
}
var out []SnoozeChoice
if later := now.Add(3 * time.Hour).Truncate(time.Hour); later.Day() == now.Day() {
out = append(out, SnoozeChoice{"snooze_picker.later", later})
}
out = append(out, SnoozeChoice{"snooze_picker.tomorrow", at(1)})
if wd := now.Weekday(); wd != time.Saturday && wd != time.Sunday {
out = append(out, SnoozeChoice{"snooze_picker.weekend", at(int(time.Saturday - wd))})
}
monday := (8 - int(now.Weekday())) % 7
if monday == 0 {
monday = 7
}
return append(out, SnoozeChoice{"snooze_picker.nextWeek", at(monday)})
}
type snoozeState struct {
custom bool
pick time.Time
}
type snoozeKey struct{}
// SnoozePicker offers shortcuts and custom reminder times.
func SnoozePicker(c *ui.Context, until *time.Time, opts SnoozePickerOptions) ChoiceResult {
if opts.MorningHour < 0 || opts.MorningHour > 23 {
panic("mujica: SnoozePicker MorningHour outside 0..23")
}
loc := opts.Location
if loc == nil {
loc = time.Local
}
morning := opts.MorningHour
if morning == 0 {
morning = 9
}
k := Tokens(c)
d := Density(c)
u := d.Unit()
now := opts.Now
if now.IsZero() {
now = c.Now()
}
now = now.In(loc)
old := *until
col := ui.Column(c).Width(300).Padding(u).FocusGroup(ui.Vertical).Role(ui.RoleList).Label(msg(c, "snooze_picker.label")).
Disabled(opts.Disabled)
st := ui.Local(col, snoozeKey{}, func() *snoozeState { return &snoozeState{} })
s := *st
col.Children(func() {
row := func(name, when string, on bool) bool {
b := ui.ButtonBase(c).MinHeight(d.ControlHeight()).Justify(ui.Start).Gap(u*2).Padding(0, u*3).Radius(theme.ControlRadius).
Role(ui.RoleListItem).Label(name + ", " + when).Selected(on).Background(ui.Transparent).Transition(colorFade)
internal.Ring(b, k.Focus, theme.ControlRadius)
switch {
case on:
b.Background(k.Selection).BorderWidth(0, 0, 0, 3).BorderColor(k.AccentText)
case b.Hovered():
b.Background(k.SurfaceHover)
}
b.Children(func() {
ui.Text(c, name).Grow(1).SingleLine()
ui.Text(c, when).FontSize(FontSize(c, theme.CaptionSize)).TextColor(k.TextMuted).FontFeatures("tnum").SingleLine()
})
return b.Clicked() && !b.IsDisabled()
}
for _, ch := range SnoozeChoices(now, morning) {
ui.Box(c).Key(ch.Key).Children(func() {
if row(msg(c, ch.Key), snoozeWhen(c, now, ch.At), until.Equal(ch.At)) {
*until, s.custom = ch.At, false
}
})
}
ui.Box(c).Height(1).Margin(u, 0).Background(k.Border)
if row(msg(c, "snooze_picker.custom"), "", s.custom) {
s.custom = !s.custom
if s.pick.IsZero() {
s.pick = SnoozeChoices(now, morning)[0].At
}
}
if s.custom {
ui.Column(c).Gap(u * 2).Padding(u * 2).Children(func() {
DateTimePicker(c, &s.pick, DateTimePickerOptions{Location: loc, Min: now, Label: msg(c, "snooze_picker.custom"), Disabled: opts.Disabled})
if Button(c, msg(c, "snooze_picker.set"), ButtonOptions{Disabled: !s.pick.After(now)}).Clicked() {
*until = s.pick
}
})
}
})
changed := !until.Equal(old)
if changed {
slog.Debug("mujica: snooze_picker set", "until", *until)
}
return ChoiceResult{Element: col, changed: changed}
}
func snoozeWhen(c *ui.Context, now, t time.Time) string {
if t.Year() == now.Year() && t.YearDay() == now.YearDay() {
return t.Format("15:04")
}
return messagingDate(c, t, "snooze_picker.when")
}