From 4012dd31f198d53b83722b1ec22fd43677ea21cf Mon Sep 17 00:00:00 2001 From: Ronald Record Date: Thu, 23 Feb 2023 21:29:02 -0800 Subject: [PATCH] Add keyboard controls to lunarphase module (#1444) * Add keyboard controls * Fix lint error from golangci-lint in pull request checks * More 'gofmt -s' updates to satisfy lint check in pull request * Fix hang with rapid requests from keyboard input * Remove unused 'today' variable --- app/widget_maker.go | 6 +- modules/lunarphase/keyboard.go | 22 ++++++ modules/lunarphase/settings.go | 10 ++- modules/lunarphase/widget.go | 128 +++++++++++++++++++++++++++++---- 4 files changed, 147 insertions(+), 19 deletions(-) create mode 100644 modules/lunarphase/keyboard.go diff --git a/app/widget_maker.go b/app/widget_maker.go index 1ea26508a..351501183 100644 --- a/app/widget_maker.go +++ b/app/widget_maker.go @@ -246,12 +246,12 @@ func MakeWidget( case "logger": settings := logger.NewSettingsFromYAML(moduleName, moduleConfig, config) widget = logger.NewWidget(tviewApp, redrawChan, settings) + case "lunarphase": + settings := lunarphase.NewSettingsFromYAML(moduleName, moduleConfig, config) + widget = lunarphase.NewWidget(tviewApp, redrawChan, pages, settings) case "mercurial": settings := mercurial.NewSettingsFromYAML(moduleName, moduleConfig, config) widget = mercurial.NewWidget(tviewApp, redrawChan, pages, settings) - case "lunarphase": - settings := lunarphase.NewSettingsFromYAML(moduleName, moduleConfig, config) - widget = lunarphase.NewWidget(tviewApp, redrawChan, settings) case "mempool": settings := mempool.NewSettingsFromYAML(moduleName, moduleConfig, config) widget = mempool.NewWidget(tviewApp, redrawChan, pages, settings) diff --git a/modules/lunarphase/keyboard.go b/modules/lunarphase/keyboard.go new file mode 100644 index 000000000..478507f60 --- /dev/null +++ b/modules/lunarphase/keyboard.go @@ -0,0 +1,22 @@ +package lunarphase + +import "github.com/gdamore/tcell/v2" + +func (widget *Widget) initializeKeyboardControls() { + widget.InitializeHelpTextKeyboardControl(widget.ShowHelp) + widget.InitializeRefreshKeyboardControl(widget.Refresh) + + widget.SetKeyboardChar("n", widget.NextDay, "Show next day lunar phase") + widget.SetKeyboardChar("p", widget.PrevDay, "Show previous day lunar phase") + widget.SetKeyboardChar("t", widget.Today, "Show today lunar phase") + widget.SetKeyboardChar("N", widget.NextWeek, "Show next week lunar phase") + widget.SetKeyboardChar("P", widget.PrevWeek, "Show previous week lunar phase") + widget.SetKeyboardChar("o", widget.OpenMoonPhase, "Open 'Moon Phase for Today' in browser") + + widget.SetKeyboardKey(tcell.KeyLeft, widget.PrevDay, "Show previous day lunar phase") + widget.SetKeyboardKey(tcell.KeyRight, widget.NextDay, "Show next day lunar phase") + widget.SetKeyboardKey(tcell.KeyUp, widget.NextWeek, "Show next week lunar phase") + widget.SetKeyboardKey(tcell.KeyDown, widget.PrevWeek, "Show previous week lunar phase") + widget.SetKeyboardKey(tcell.KeyEnter, widget.OpenMoonPhase, "Open 'Moon Phase for Today' in browser") + widget.SetKeyboardKey(tcell.KeyCtrlD, widget.DisableWidget, "Disable/Enable this widget instance") +} diff --git a/modules/lunarphase/settings.go b/modules/lunarphase/settings.go index 9b3e668d7..92ec59cac 100644 --- a/modules/lunarphase/settings.go +++ b/modules/lunarphase/settings.go @@ -6,21 +6,25 @@ import ( ) const ( - defaultFocusable = false + defaultFocusable = true defaultTitle = "Phase of the Moon" + dateFormat = "2006-01-02" + phaseFormat = "01-02-2006" ) type Settings struct { *cfg.Common - language string + language string + requestTimeout int } func NewSettingsFromYAML(name string, ymlConfig *config.Config, globalConfig *config.Config) *Settings { settings := Settings{ Common: cfg.NewCommonSettingsFromModule(name, defaultTitle, defaultFocusable, ymlConfig, globalConfig), - language: ymlConfig.UString("language", "en"), + language: ymlConfig.UString("language", "en"), + requestTimeout: ymlConfig.UInt("timeout", 30), } settings.SetDocumentationPath("lunarphase") diff --git a/modules/lunarphase/widget.go b/modules/lunarphase/widget.go index 40fa68274..9614d87ce 100644 --- a/modules/lunarphase/widget.go +++ b/modules/lunarphase/widget.go @@ -4,42 +4,87 @@ import ( "io" "net/http" "strings" + "time" "github.com/rivo/tview" + "github.com/wtfutil/wtf/utils" "github.com/wtfutil/wtf/view" "github.com/wtfutil/wtf/wtf" ) type Widget struct { - view.TextWidget + view.ScrollableWidget + + current bool + day string + date time.Time + last string + result string + settings *Settings + timeout time.Duration + titleBase string +} + +func NewWidget(tviewApp *tview.Application, redrawChan chan bool, pages *tview.Pages, settings *Settings) *Widget { + widget := &Widget{ + ScrollableWidget: view.NewScrollableWidget(tviewApp, redrawChan, pages, settings.Common), + settings: settings, + } + + widget.current = true + widget.date = time.Now() + widget.day = widget.date.Format(dateFormat) + widget.last = "" + widget.timeout = time.Duration(widget.settings.requestTimeout) * time.Second + widget.titleBase = widget.settings.Title - result string - settings *Settings + widget.SetRenderFunction(widget.Refresh) + widget.initializeKeyboardControls() + + return widget } -func NewWidget(tviewApp *tview.Application, redrawChan chan bool, settings *Settings) *Widget { - widget := Widget{ - TextWidget: view.NewTextWidget(tviewApp, redrawChan, nil, settings.Common), +func (widget *Widget) Refresh() { + if widget.current { + widget.date = time.Now() + widget.day = widget.date.Format(dateFormat) + } + if widget.day != widget.last { + widget.lunarPhase() + } - settings: settings, + if !widget.settings.Enabled { + widget.settings.Common.Title = widget.titleBase + " " + widget.day + " [ Disabled ]" + widget.Redraw(func() (string, string, bool) { return widget.CommonSettings().Title, "", false }) + widget.View.Clear() + return } + widget.settings.Common.Title = widget.titleBase + " " + widget.day - return &widget + widget.Redraw(func() (string, string, bool) { return widget.CommonSettings().Title, widget.result, false }) } -func (widget *Widget) Refresh() { - widget.lunarPhase() +func (widget *Widget) RefreshTitle() { + if !widget.settings.Enabled { + widget.settings.Common.Title = widget.titleBase + " " + widget.day + " [ Disabled ]" + widget.Redraw(func() (string, string, bool) { return widget.CommonSettings().Title, "", false }) + widget.View.Clear() + return + } + widget.settings.Common.Title = widget.titleBase + " [" + widget.day + "]" widget.Redraw(func() (string, string, bool) { return widget.CommonSettings().Title, widget.result, false }) } // this method reads the config and calls wttr.in for lunar phase func (widget *Widget) lunarPhase() { - client := &http.Client{} + client := &http.Client{ + Timeout: widget.timeout, + } language := widget.settings.language - req, err := http.NewRequest("GET", "https://wttr.in/Moon?AF"+language, http.NoBody) + req, err := http.NewRequest("GET", "https://wttr.in/Moon@"+widget.day+"?AF&lang="+language, http.NoBody) if err != nil { widget.result = err.Error() return @@ -51,7 +96,6 @@ func (widget *Widget) lunarPhase() { if err != nil { widget.result = err.Error() return - } defer func() { _ = response.Body.Close() }() @@ -61,5 +105,63 @@ func (widget *Widget) lunarPhase() { return } + widget.last = widget.day widget.result = strings.TrimSpace(wtf.ASCIItoTviewColors(string(contents))) } + +// NextDay shows the next day's lunar phase (KeyRight / 'n') +func (widget *Widget) NextDay() { + widget.current = false + tomorrow := widget.date.AddDate(0, 0, 1) + widget.setDay(tomorrow) +} + +// NextWeek shows the next week's lunar phase (KeyUp / 'N') +func (widget *Widget) NextWeek() { + widget.current = false + nextweek := widget.date.AddDate(0, 0, 7) + widget.setDay(nextweek) +} + +// PrevDay shows the previous day's lunar phase (KeyLeft / 'p') +func (widget *Widget) PrevDay() { + widget.current = false + yesterday := widget.date.AddDate(0, 0, -1) + widget.setDay(yesterday) +} + +// Today shows the current day's lunar phase ('t') +func (widget *Widget) Today() { + widget.current = true + widget.Refresh() +} + +// PrevWeek shows the previous week's lunar phase (KeyDown / 'P') +func (widget *Widget) PrevWeek() { + widget.current = false + lastweek := widget.date.AddDate(0, 0, -7) + widget.setDay(lastweek) +} + +func (widget *Widget) setDay(ts time.Time) { + widget.date = ts + widget.day = widget.date.Format(dateFormat) + widget.RefreshTitle() +} + +// Open nineplanets.org in a browser (Enter / 'o') +func (widget *Widget) OpenMoonPhase() { + phasedate := widget.date.Format(phaseFormat) + utils.OpenFile("https://nineplanets.org/moon/phase/" + phasedate + "/") +} + +// Disable/Enable the widget (Ctrl-D) +func (widget *Widget) DisableWidget() { + if widget.settings.Enabled { + widget.settings.Enabled = false + widget.RefreshTitle() + } else { + widget.settings.Enabled = true + widget.Refresh() + } +}