diff --git a/cmd/android-app/main.go b/cmd/android-app/main.go index 5b4fc60..76af404 100644 --- a/cmd/android-app/main.go +++ b/cmd/android-app/main.go @@ -9,7 +9,7 @@ import ( func main() { fyneApp := app.NewWithID("nl.ewintr.gte") - w := fyneApp.NewWindow("gte - getting things email") + fyneWindow := fyneApp.NewWindow("gte - getting things email") conf := component.NewConfigurationFromPreferences(fyneApp.Preferences()) conf.Load() logger := component.NewLogger() @@ -20,9 +20,9 @@ func main() { } r := runner.NewRunner(conf, tasksURI, logger) - tabs := r.Init() - w.SetContent(tabs) + rootContainer := r.Init() + fyneWindow.SetContent(rootContainer) go r.Run() - w.ShowAndRun() + fyneWindow.ShowAndRun() } diff --git a/cmd/android-app/runner/runner.go b/cmd/android-app/runner/runner.go index 779d2b9..cbfc7f1 100644 --- a/cmd/android-app/runner/runner.go +++ b/cmd/android-app/runner/runner.go @@ -11,7 +11,6 @@ import ( "ewintr.nl/gte/cmd/android-app/screen" "ewintr.nl/gte/internal/task" "fyne.io/fyne/v2" - "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/storage" ) @@ -23,11 +22,11 @@ type Runner struct { conf *component.Configuration logger *component.Logger tasks *component.Tasks - screens []screen.Screen status string requests chan interface{} refresh chan bool fileURI fyne.URI + screenSet *screen.ScreenSet } func NewRunner(conf *component.Configuration, fileURI fyne.URI, logger *component.Logger) *Runner { @@ -42,30 +41,20 @@ func NewRunner(conf *component.Configuration, fileURI fyne.URI, logger *componen } func (r *Runner) Init() fyne.CanvasObject { - - logScreen := screen.NewLog() - logTab := container.NewTabItem("log", logScreen.Content()) - r.screens = append(r.screens, logScreen) - - configScreen := screen.NewConfig(r.requests) - configTab := container.NewTabItem("config", configScreen.Content()) - r.screens = append(r.screens, configScreen) - stored, err := load(r.fileURI) if err != nil { r.logger.Log(err.Error()) } r.logger.Log(fmt.Sprintf("loaded %d tasks from file", len(stored))) r.tasks = component.NewTasks(r.conf, stored) - taskScreen := screen.NewTasks(r.requests) - taskTab := container.NewTabItem("tasks", taskScreen.Content()) - r.screens = append(r.screens, taskScreen) - tabs := container.NewAppTabs(taskTab, configTab, logTab) - return tabs + r.screenSet = screen.NewScreenSet(r.requests) + + return r.screenSet.Content() } func (r *Runner) Run() { + go r.screenSet.Run() go r.refresher() go r.processRequest() r.backgroundSync() @@ -80,7 +69,7 @@ func (r *Runner) processRequest() { for k, val := range v.Fields { r.conf.Set(k, val) } - r.status = "ready" + r.status = "config saved" r.logger.Log("config saved") case screen.SyncTasksRequest: r.status = "syncing..." @@ -92,7 +81,7 @@ func (r *Runner) processRequest() { if countDisp > 0 || countFetch > 0 { r.logger.Log(fmt.Sprintf("task sync: dispatched: %d, fetched: %d", countDisp, countFetch)) } - r.status = "ready" + r.status = "synced" all, err := r.tasks.All() if err != nil { r.logger.Log(err.Error()) @@ -103,10 +92,13 @@ func (r *Runner) processRequest() { break } case screen.MarkTaskDoneRequest: + r.status = "marking done..." + r.refresh <- true if err := r.tasks.MarkDone(v.ID); err != nil { r.logger.Log(err.Error()) } r.logger.Log(fmt.Sprintf("marked task %q done", v.ID)) + r.status = "marked done" default: r.logger.Log("request unknown") } @@ -135,9 +127,7 @@ func (r *Runner) refresher() { Logs: r.logger.Lines(), } - for _, s := range r.screens { - s.Refresh(state) - } + r.screenSet.Refresh(state) } } diff --git a/cmd/android-app/screen/config.go b/cmd/android-app/screen/config.go index ae0e69e..27021d0 100644 --- a/cmd/android-app/screen/config.go +++ b/cmd/android-app/screen/config.go @@ -4,6 +4,7 @@ import ( "sync" "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/data/binding" "fyne.io/fyne/v2/widget" ) @@ -45,11 +46,13 @@ func (ff *FormField) GetValue() string { } type Config struct { - fields []*FormField - out chan interface{} + fields []*FormField + commands chan interface{} + show chan string + root *fyne.Container } -func NewConfig(out chan interface{}) *Config { +func NewConfig(commands chan interface{}, show chan string) *Config { fields := []*FormField{} for _, f := range [][2]string{ {"ConfigIMAPURL", "imap url"}, @@ -68,10 +71,14 @@ func NewConfig(out chan interface{}) *Config { fields = append(fields, NewFormField(f[0], f[1])) } - return &Config{ - fields: fields, - out: out, + config := &Config{ + fields: fields, + commands: commands, + show: show, } + config.Init() + + return config } func (cf *Config) Save() { @@ -81,7 +88,8 @@ func (cf *Config) Save() { for _, f := range cf.fields { req.Fields[f.Key] = f.GetValue() } - cf.out <- req + cf.commands <- req + cf.show <- "tasks" } func (cf *Config) Refresh(state State) { @@ -92,7 +100,7 @@ func (cf *Config) Refresh(state State) { } } -func (cf *Config) Content() fyne.CanvasObject { +func (cf *Config) Init() { configForm := widget.NewForm() for _, f := range cf.fields { w := widget.NewEntry() @@ -104,5 +112,23 @@ func (cf *Config) Content() fyne.CanvasObject { configForm.OnSubmit = cf.Save configForm.Enable() - return configForm + cf.root = container.NewBorder( + nil, + nil, + nil, + nil, + configForm, + ) +} + +func (cf *Config) Content() *fyne.Container { + return cf.root +} + +func (cf *Config) Hide() { + cf.root.Hide() +} + +func (cf *Config) Show() { + cf.root.Show() } diff --git a/cmd/android-app/screen/log.go b/cmd/android-app/screen/log.go index da42a4b..b446012 100644 --- a/cmd/android-app/screen/log.go +++ b/cmd/android-app/screen/log.go @@ -2,25 +2,30 @@ package screen import ( "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/data/binding" "fyne.io/fyne/v2/widget" ) type Log struct { lines binding.StringList + root *fyne.Container } func NewLog() *Log { - return &Log{ + logs := &Log{ lines: binding.NewStringList(), } + logs.Init() + + return logs } func (l *Log) Refresh(state State) { l.lines.Set(state.Logs) } -func (l *Log) Content() fyne.CanvasObject { +func (l *Log) Init() { list := widget.NewListWithData( l.lines, func() fyne.CanvasObject { @@ -30,5 +35,23 @@ func (l *Log) Content() fyne.CanvasObject { o.(*widget.Label).Bind(i.(binding.String)) }, ) - return list + l.root = container.NewBorder( + nil, + nil, + nil, + nil, + list, + ) +} + +func (l *Log) Content() *fyne.Container { + return l.root +} + +func (l *Log) Hide() { + l.root.Hide() +} + +func (l *Log) Show() { + l.root.Show() } diff --git a/cmd/android-app/screen/screen.go b/cmd/android-app/screen/screen.go index 00e5580..f931850 100644 --- a/cmd/android-app/screen/screen.go +++ b/cmd/android-app/screen/screen.go @@ -1,6 +1,13 @@ package screen -import "fyne.io/fyne/v2" +import ( + "fmt" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/data/binding" + "fyne.io/fyne/v2/widget" +) type Task struct { ID string @@ -8,13 +15,92 @@ type Task struct { } type State struct { - Status string - Tasks []Task - Config map[string]string - Logs []string + Status string + CurrentScreen string + Tasks []Task + Config map[string]string + Logs []string } type Screen interface { - Content() fyne.CanvasObject + Content() *fyne.Container Refresh(state State) + Hide() + Show() +} + +type ScreenSet struct { + current string + show chan string + status binding.String + menu *fyne.Container + screens map[string]Screen + root *fyne.Container +} + +func NewScreenSet(requests chan interface{}) *ScreenSet { + status := binding.NewString() + show := make(chan string) + + tasksButton := widget.NewButton("tasks", func() { + show <- "tasks" + }) + configButton := widget.NewButton("config", func() { + show <- "config" + }) + logsButton := widget.NewButton("logs", func() { + show <- "logs" + }) + statusLabel := widget.NewLabel("> init...") + statusLabel.Bind(status) + statusLabel.TextStyle.Italic = true + menu := container.NewHBox(tasksButton, configButton, logsButton, statusLabel) + + screens := map[string]Screen{ + "tasks": NewTasks(requests, show), + "logs": NewLog(), + "config": NewConfig(requests, show), + } + + cs := []fyne.CanvasObject{} + for _, s := range screens { + s.Hide() + cs = append(cs, s.Content()) + } + screens["tasks"].Show() + + root := container.NewBorder(menu, nil, nil, nil, cs...) + + return &ScreenSet{ + status: status, + current: "tasks", + show: show, + screens: screens, + root: root, + } +} + +func (ss *ScreenSet) Run() { + for s := range ss.show { + if s != ss.current { + ss.screens[ss.current].Hide() + ss.screens[s].Show() + ss.current = s + + ss.root.Refresh() + } + } +} + +func (ss *ScreenSet) Refresh(state State) { + ss.status.Set(fmt.Sprintf("> %s", state.Status)) + for _, s := range ss.screens { + s.Refresh(state) + } + + ss.root.Refresh() +} + +func (ss *ScreenSet) Content() *fyne.Container { + return ss.root } diff --git a/cmd/android-app/screen/tasks.go b/cmd/android-app/screen/tasks.go index 723903e..d82870f 100644 --- a/cmd/android-app/screen/tasks.go +++ b/cmd/android-app/screen/tasks.go @@ -1,7 +1,6 @@ package screen import ( - "fmt" "sort" "fyne.io/fyne/v2" @@ -17,25 +16,28 @@ type MarkTaskDoneRequest struct { } type Tasks struct { - status binding.String tasks []Task taskLabels binding.StringList selectedTask string list *widget.List - out chan interface{} + commands chan interface{} + show chan string + root *fyne.Container } -func NewTasks(out chan interface{}) *Tasks { - return &Tasks{ - status: binding.NewString(), +func NewTasks(commands chan interface{}, show chan string) *Tasks { + tasks := &Tasks{ tasks: []Task{}, taskLabels: binding.NewStringList(), - out: out, + commands: commands, + show: show, } + tasks.Init() + + return tasks } func (t *Tasks) Refresh(state State) { - t.status.Set(fmt.Sprintf("> %s", state.Status)) t.tasks = state.Tasks sort.Slice(t.tasks, func(i, j int) bool { return t.tasks[i].Action < t.tasks[j].Action @@ -50,10 +52,7 @@ func (t *Tasks) Refresh(state State) { } } -func (t *Tasks) Content() fyne.CanvasObject { - statusLabel := widget.NewLabel("> init...") - statusLabel.Bind(t.status) - statusLabel.TextStyle.Italic = true +func (t *Tasks) Init() { doneButton := widget.NewButton("done", func() { t.markDone() }) @@ -68,8 +67,8 @@ func (t *Tasks) Content() fyne.CanvasObject { ) t.list.OnSelected = t.selectItem - return container.NewBorder( - container.NewHBox(statusLabel), + t.root = container.NewBorder( + nil, doneButton, nil, nil, @@ -77,6 +76,18 @@ func (t *Tasks) Content() fyne.CanvasObject { ) } +func (t *Tasks) Content() *fyne.Container { + return t.root +} + +func (t *Tasks) Hide() { + t.root.Hide() +} + +func (t *Tasks) Show() { + t.root.Show() +} + func (t *Tasks) selectItem(lid widget.ListItemID) { id := int(lid) if id < 0 || id >= len(t.tasks) { @@ -90,7 +101,7 @@ func (t *Tasks) markDone() { if t.selectedTask == "" { return } - t.out <- MarkTaskDoneRequest{ + t.commands <- MarkTaskDoneRequest{ ID: t.selectedTask, } t.selectedTask = ""