diff --git a/cmd/gui/README.md b/cmd/gui/README.md index d3f937c..086d55e 100644 --- a/cmd/gui/README.md +++ b/cmd/gui/README.md @@ -9,7 +9,8 @@ The GUI will work off a config similar to the following. Use the ```generate con ``` [slideshow] -duration = "300s" +slideinterval = "300s" +restartinterval = "7d" [hdmi] # These are SYSTEMD.TIME formatted times diff --git a/cmd/gui/gui.go b/cmd/gui/gui.go index 0e987ad..2184c38 100644 --- a/cmd/gui/gui.go +++ b/cmd/gui/gui.go @@ -15,27 +15,6 @@ import ( "git.kemonine.info/PiFrame/ui" ) -const ( - CLI_FLAG_CONFIG_ONLY = "config-ui-only" -) - -const ( - CONFIG_FILE_PATH = "/etc/default/pf.toml" - CONFIG_KEY_SLIDESHOW_DURATION = "slideshow.duration" - CONFIG_KEY_HDMI_OFF = "hdmi.off" - CONFIG_KEY_HDMI_ON = "hdmi.on" - CONFIG_KEY_ALBUMS_ROOT = "albums.root" - CONFIG_KEY_ALBUMS_SELECTED = "albums.selected" -) - -const ( - DEFAULT_SLIDESHOW_DURATION = "300s" - DEFAULT_HDMI_OFF = "*-*-* 00:00:00" - DEFAULT_HDMI_ON = "*-*-* 06:00:00" - DEFAULT_ALBUMS_ROOT = "/tank/pictures" - DEFAULT_ALBUM_SELECTED = "/" -) - func main() { // Command line flag handler f := flag.NewFlagSet("piframe", flag.ContinueOnError) @@ -44,8 +23,8 @@ func main() { os.Exit(0) } // Command line flags - f.Bool(CLI_FLAG_CONFIG_ONLY, false, "Only show the config UI, NOT the slideshow") - cliFlag := f.Lookup(CLI_FLAG_CONFIG_ONLY) + f.Bool(ui.CLI_FLAG_CONFIG_ONLY, false, "Only show the config UI, NOT the slideshow") + cliFlag := f.Lookup(ui.CLI_FLAG_CONFIG_ONLY) if cliFlag != nil { cliFlag.NoOptDefVal = "true" } @@ -57,23 +36,22 @@ func main() { // Setup some defaults pfConfig.Load(confmap.Provider(map[string]interface{}{ - CONFIG_KEY_SLIDESHOW_DURATION: DEFAULT_SLIDESHOW_DURATION, - CONFIG_KEY_HDMI_OFF: DEFAULT_HDMI_OFF, - CONFIG_KEY_HDMI_ON: DEFAULT_HDMI_ON, - CONFIG_KEY_ALBUMS_ROOT: DEFAULT_ALBUMS_ROOT, - CONFIG_KEY_ALBUMS_SELECTED: []string{DEFAULT_ALBUM_SELECTED}, + ui.CONFIG_KEY_SLIDESHOW_INTERVAL: ui.DEFAULT_SLIDESHOW_INTERVAL, + ui.CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL: ui.DEFAULT_SLIDESHOW_RESTART_INTERVAL, + ui.CONFIG_KEY_HDMI_OFF: ui.DEFAULT_HDMI_OFF, + ui.CONFIG_KEY_HDMI_ON: ui.DEFAULT_HDMI_ON, + ui.CONFIG_KEY_ALBUMS_ROOT: ui.DEFAULT_ALBUMS_ROOT, + ui.CONFIG_KEY_ALBUMS_SELECTED: []string{ui.DEFAULT_ALBUM_SELECTED}, }, "."), nil) // Bring in /etc/defaults/pf.toml if it exists - configFileProvider := file.Provider(CONFIG_FILE_PATH) - _, err := os.Stat(CONFIG_FILE_PATH) - if err != nil { - if os.IsNotExist(err) { - // log.Printf("%s does not exist, USING DEFAULTS", CONFIG_FILE_PATH) - } else { - if errConfigFile := pfConfig.Load(configFileProvider, toml.Parser()); errConfigFile != nil { - log.Fatalf("Error loading config : %s", err) - } + configFileProvider := file.Provider(ui.CONFIG_FILE_PATH) + _, err := os.Stat(ui.CONFIG_FILE_PATH) + if os.IsNotExist(err) { + //log.Printf("%s does not exist, USING DEFAULTS", ui.CONFIG_FILE_PATH) + } else { + if errConfigFile := pfConfig.Load(configFileProvider, toml.Parser()); errConfigFile != nil { + log.Fatalf("Error loading config : %s", err) } } @@ -92,9 +70,9 @@ func main() { log.Fatalf("Error loading command line flags : %s", err) } - if !pfConfig.Bool(CLI_FLAG_CONFIG_ONLY) { - ui.Slideshow() + if !pfConfig.Bool(ui.CLI_FLAG_CONFIG_ONLY) { + ui.Slideshow(pfConfig) } - ui.ConfigGui() + ui.ConfigGui(pfConfig) } diff --git a/ui/config.go b/ui/config.go index a9b8d53..985ade4 100644 --- a/ui/config.go +++ b/ui/config.go @@ -14,6 +14,7 @@ import ( "github.com/gdamore/tcell" "github.com/guillermo/go.procmeminfo" + "github.com/knadh/koanf" "github.com/rivo/tview" "git.kemonine.info/PiFrame/wifi" @@ -24,7 +25,6 @@ const ( CMD_FINDMNT = "/usr/bin/findmnt" CMD_VCGENCMD = "/opt/vc/bin/vcgencmd" FILE_CPU_TEMP = "/sys/class/thermal/thermal_zone0/temp" - ALBUM_ROOT_DIR = "/tank/pictures/" SYNCTHING_FOLDER_SKIP = ".stfolder" ) @@ -35,7 +35,7 @@ const ( PAGE_POWEROFF = "PAGE_POWEROFF" ) -func ConfigGui() { +func ConfigGui(config *koanf.Koanf) { // Memory info for status panel meminfo := &procmeminfo.MemInfo{} err := meminfo.Update() @@ -80,7 +80,7 @@ func ConfigGui() { // Get list of all folders that can be used as albums var albums []string - err = filepath.Walk(ALBUM_ROOT_DIR, func(path string, fi os.FileInfo, err error) error { + err = filepath.Walk(config.String(CONFIG_KEY_ALBUMS_ROOT), func(path string, fi os.FileInfo, err error) error { if err != nil { return err } @@ -88,7 +88,7 @@ func ConfigGui() { if strings.Contains(path, SYNCTHING_FOLDER_SKIP) { return nil } - albumName := strings.TrimPrefix(path, ALBUM_ROOT_DIR) + albumName := strings.TrimPrefix(path, config.String(CONFIG_KEY_ALBUMS_ROOT)) if albumName == "" { albumName = "Main Folder" } @@ -154,7 +154,9 @@ func ConfigGui() { SetTitle("Menu"). SetTitleColor(tcell.ColorAqua) menu.AddItem("Select Albums", "", '1', nil) - menu.AddItem("Configure WiFi", "", '2', nil) + menu.AddItem("Intervals", "", '2', nil) + menu.AddItem("WiFi", "", '3', nil) + menu.AddItem("HDMI On/Off", "", '5', nil) // Setup base var for main column so the menu setup is easier to manage main := tview.NewFlex(). @@ -165,6 +167,39 @@ func ConfigGui() { SetBorder(true). SetTitleColor(tcell.ColorAqua) + // Select Albums Form + selectAlbumsForm := tview.NewForm() + configSelectedAlbums := config.Strings(CONFIG_KEY_ALBUMS_SELECTED) + for _, album := range albums { + albumSelected := false + for _, configSelectedAlbum := range configSelectedAlbums { + if configSelectedAlbum == "/" { + configSelectedAlbum = "Main Folder" + } + if album == configSelectedAlbum { + albumSelected = true + } + } + selectAlbumsForm.AddCheckbox(album, albumSelected, nil) + } + selectAlbumsForm.AddButton("Apply", nil) + selectAlbumsForm.AddButton("Cancel", func() { + main.Clear() + app.SetFocus(menu) + }) + + // Slide Interval Form + intervalsForm := tview.NewForm() + configSlideInterval := config.String(CONFIG_KEY_SLIDESHOW_INTERVAL) + configRestartInterval := config.String(CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL) + intervalsForm.AddInputField("Slide", configSlideInterval, 0, nil, nil) + intervalsForm.AddInputField("Restart/Reshuffle", configRestartInterval, 0, nil, nil) + intervalsForm.AddButton("Apply", nil) + intervalsForm.AddButton("Cancel", func() { + main.Clear() + app.SetFocus(menu) + }) + // WiFi Config Form wifiConfigForm := tview.NewForm() wifiConfigAccessPoint := "" @@ -185,13 +220,14 @@ func ConfigGui() { app.SetFocus(menu) }) - // Select Albums Form - selectAlbumsForm := tview.NewForm() - for _, album := range albums { - selectAlbumsForm.AddCheckbox(album, true, nil) - } - selectAlbumsForm.AddButton("Apply", nil) - selectAlbumsForm.AddButton("Cancel", func() { + // HDMI On/Off Form + hdmiForm := tview.NewForm() + configHDMIOff := config.String(CONFIG_KEY_HDMI_OFF) + configHDMIOn := config.String(CONFIG_KEY_HDMI_ON) + hdmiForm.AddInputField("HDMI Off Schedule", configHDMIOff, 0, nil, nil) + hdmiForm.AddInputField("HDMI On Schedule", configHDMIOn, 0, nil, nil) + hdmiForm.AddButton("Apply", nil) + hdmiForm.AddButton("Cancel", func() { main.Clear() app.SetFocus(menu) }) @@ -204,12 +240,24 @@ func ConfigGui() { main.AddItem(selectAlbumsForm, 0, 1, true) app.SetFocus(selectAlbumsForm) } - if title == "Configure WiFi" { + if title == "WiFi" { main.SetTitle("Configure WiFi") main.Clear() main.AddItem(wifiConfigForm, 0, 1, true) app.SetFocus(wifiConfigForm) } + if title == "Intervals" { + main.SetTitle("Configure Intervals") + main.Clear() + main.AddItem(intervalsForm, 0, 1, true) + app.SetFocus(intervalsForm) + } + if title == "HDMI On/Off" { + main.SetTitle("Configure HDMI On/Off") + main.Clear() + main.AddItem(hdmiForm, 0, 1, true) + app.SetFocus(hdmiForm) + } }) // Side bar fields @@ -364,9 +412,14 @@ func ConfigGui() { // Override some of the default behavior so up/dn move between fields in forms // Per API GetFocusedItemIndex on a form will be -1 if a form item isn't currently focused // We use this as a bit of a cheat to figure out if we're inside of a form that needs better nav options for users (ie. tab doesn't exist on a remote) - wifiField, wifiButton := wifiConfigForm.GetFocusedItemIndex() albumField, albumButton := selectAlbumsForm.GetFocusedItemIndex() - if wifiField != -1 || wifiButton != -1 || albumField != -1 || albumButton != -1 { + intervalField, intervalButton := intervalsForm.GetFocusedItemIndex() + wifiField, wifiButton := wifiConfigForm.GetFocusedItemIndex() + hdmiField, hdmiButton := hdmiForm.GetFocusedItemIndex() + if (wifiField != -1 || wifiButton != -1 || + albumField != -1 || albumButton != -1 || + intervalField != -1 || intervalButton != -1 || + hdmiField != -1 || hdmiButton != -1) { switch event.Key() { case tcell.KeyUp: return tcell.NewEventKey(tcell.KeyBacktab, 0, event.Modifiers()) diff --git a/ui/constants.go b/ui/constants.go new file mode 100644 index 0000000..0a49d8c --- /dev/null +++ b/ui/constants.go @@ -0,0 +1,24 @@ +package ui + +const ( + CLI_FLAG_CONFIG_ONLY = "config-ui-only" +) + +const ( + CONFIG_FILE_PATH = "/etc/default/pf.toml" + CONFIG_KEY_SLIDESHOW_INTERVAL = "slideshow.slideinterval" + CONFIG_KEY_SLIDESHOW_RESTART_INTERVAL = "slideshow.restartinterval" + CONFIG_KEY_HDMI_OFF = "hdmi.off" + CONFIG_KEY_HDMI_ON = "hdmi.on" + CONFIG_KEY_ALBUMS_ROOT = "albums.root" + CONFIG_KEY_ALBUMS_SELECTED = "albums.selected" +) + +const ( + DEFAULT_SLIDESHOW_INTERVAL = "300s" + DEFAULT_SLIDESHOW_RESTART_INTERVAL = "7d" + DEFAULT_HDMI_OFF = "*-*-* 00:00:00" + DEFAULT_HDMI_ON = "*-*-* 06:00:00" + DEFAULT_ALBUMS_ROOT = "/tank/pictures" + DEFAULT_ALBUM_SELECTED = "/" +) diff --git a/ui/slideshow.go b/ui/slideshow.go index ba5e7db..8647451 100644 --- a/ui/slideshow.go +++ b/ui/slideshow.go @@ -9,14 +9,14 @@ import ( "time" "github.com/eiannone/keyboard" + "github.com/knadh/koanf" ) const ( - CMD_FIM = "/usr/local/bin/pf-fim.sh" - SLIDESHOW_INTERVAL = 300 * time.Second + CMD_FIM = "/usr/local/bin/pf-fim.sh" ) -func Slideshow() { +func Slideshow(config *koanf.Koanf) { // fim placeholder so we can operate on it when a exit slideshow is received var fim *exec.Cmd = nil @@ -32,7 +32,7 @@ func Slideshow() { } // Advance slideshow every interval as defined in const() - ticker := time.NewTicker(SLIDESHOW_INTERVAL) + ticker := time.NewTicker(config.Duration(CONFIG_KEY_SLIDESHOW_INTERVAL)) stop_ticker := make(chan struct{}) go func() { for { @@ -68,7 +68,6 @@ func Slideshow() { if event.Err != nil { log.Fatalf("Error listening to key events : %s", err) } - log.Printf("You pressed: key %X\n", event.Key) // Keys for fim event management (previous/next in particular) fimKey := "" @@ -100,7 +99,7 @@ func Slideshow() { if err != nil { log.Fatalf("Error controlling fim : %s", err) } - ticker.Reset(SLIDESHOW_INTERVAL) + ticker.Reset(config.Duration(CONFIG_KEY_SLIDESHOW_INTERVAL)) } } }