From 25413a6b00e514abf308525451f01eef5eeafae0 Mon Sep 17 00:00:00 2001 From: Erik Winter Date: Sun, 23 Oct 2022 12:45:21 +0200 Subject: [PATCH] save state --- .gitignore | 2 +- cmd/android-app/component/logger.go | 2 +- cmd/android-app/component/tasks.go | 22 +++++++-- cmd/android-app/main.go | 6 +-- cmd/android-app/runner/runner.go | 70 +++++++++++++++++++++++++++-- cmd/android-app/screen/tasks.go | 11 +++-- internal/storage/memory.go | 12 ++++- internal/task/date.go | 16 +++++++ internal/task/task.go | 16 +++---- 9 files changed, 133 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 4701367..e8f1dea 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ /gte-daemon test.db *.apk - +tasks.json diff --git a/cmd/android-app/component/logger.go b/cmd/android-app/component/logger.go index e1a0ae8..f504e32 100644 --- a/cmd/android-app/component/logger.go +++ b/cmd/android-app/component/logger.go @@ -16,7 +16,7 @@ func NewLogger() *Logger { } func (l *Logger) Log(line string) { - l.lines = append(l.lines, fmt.Sprintf("%s: %s", time.Now().Format(time.Stamp), line)) + l.lines = append(l.lines, fmt.Sprintf("%s: %s", time.Now().Format(time.StampMicro), line)) if len(l.lines) > 50 { l.lines = l.lines[1:] } diff --git a/cmd/android-app/component/tasks.go b/cmd/android-app/component/tasks.go index 4481c4a..082839f 100644 --- a/cmd/android-app/component/tasks.go +++ b/cmd/android-app/component/tasks.go @@ -18,8 +18,8 @@ type Tasks struct { disp *storage.Dispatcher } -func NewTasks(conf *Configuration) (*Tasks, error) { - local := storage.NewMemory() +func NewTasks(conf *Configuration, tasks []*task.Task) *Tasks { + local := storage.NewMemory(tasks...) remote := storage.NewRemoteRepository(mstore.NewIMAP(conf.IMAP())) disp := storage.NewDispatcher(msend.NewSSLSMTP(conf.SMTP())) @@ -27,7 +27,23 @@ func NewTasks(conf *Configuration) (*Tasks, error) { local: local, remote: remote, disp: disp, - }, nil + } +} + +func (t *Tasks) All() ([]*task.Task, error) { + lts, err := t.local.FindAll() + if err != nil { + return []*task.Task{}, err + } + for _, lt := range lts { + lt.ApplyUpdate() + } + ts := []*task.Task{} + for _, lt := range lts { + ts = append(ts, <.Task) + } + + return ts, nil } func (t *Tasks) Today() (map[string]string, error) { diff --git a/cmd/android-app/main.go b/cmd/android-app/main.go index e816ad6..7f6a7ee 100644 --- a/cmd/android-app/main.go +++ b/cmd/android-app/main.go @@ -13,10 +13,10 @@ func main() { conf.Load() logger := component.NewLogger() - runner := runner.NewRunner(conf, logger) - tabs := runner.Init() + r := runner.NewRunner(conf, logger) + tabs := r.Init() w.SetContent(tabs) - go runner.Run() + go r.Run() w.ShowAndRun() } diff --git a/cmd/android-app/runner/runner.go b/cmd/android-app/runner/runner.go index 2b9be57..610ee6b 100644 --- a/cmd/android-app/runner/runner.go +++ b/cmd/android-app/runner/runner.go @@ -1,14 +1,18 @@ package runner import ( + "encoding/json" "fmt" + "io" "sync" "time" "ewintr.nl/gte/cmd/android-app/component" "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" ) var runnerLock = sync.Mutex{} @@ -45,11 +49,12 @@ func (r *Runner) Init() fyne.CanvasObject { configTab := container.NewTabItem("config", configScreen.Content()) r.screens = append(r.screens, configScreen) - tasks, err := component.NewTasks(r.conf) + stored, err := load() if err != nil { r.logger.Log(err.Error()) } - r.tasks = tasks + 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) @@ -88,8 +93,19 @@ func (r *Runner) processRequest() { r.logger.Log(fmt.Sprintf("task sync: dispatched: %d, fetched: %d", countDisp, countFetch)) //} r.status = "ready" - r.logger.Log("sync request done") + r.logger.Log("fetching all") + all, err := r.tasks.All() + if err != nil { + r.logger.Log(err.Error()) + break + } + r.logger.Log("saving all") + if err := save(all); err != nil { + r.logger.Log(err.Error()) + break + } + r.logger.Log("sync request done") case screen.MarkTaskDoneRequest: if err := r.tasks.MarkDone(v.ID); err != nil { r.logger.Log(err.Error()) @@ -111,6 +127,7 @@ func (r *Runner) refresher() { if err != nil { r.logger.Log(err.Error()) } + r.logger.Log(fmt.Sprintf("found %d tasks", len(tasks))) sTasks := []screen.Task{} for id, action := range tasks { sTasks = append(sTasks, screen.Task{ @@ -139,3 +156,50 @@ func (r *Runner) backgroundSync() { <-ticker.C } } + +func load() ([]*task.Task, error) { + uri := storage.NewFileURI("tasks.json") + fr, err := storage.Reader(uri) + if err != nil { + return []*task.Task{}, err + } + defer fr.Close() + + exists, err := storage.Exists(uri) + if !exists { + return []*task.Task{}, fmt.Errorf("uri does not exist") + } + if err != nil { + return []*task.Task{}, err + } + data, err := io.ReadAll(fr) + if err != nil { + return []*task.Task{}, err + } + + storedTasks := []*task.Task{} + if err := json.Unmarshal(data, &storedTasks); err != nil { + return []*task.Task{}, err + } + + return storedTasks, nil +} + +func save(tasks []*task.Task) error { + uri := storage.NewFileURI("tasks.json") + fw, err := storage.Writer(uri) + if err != nil { + return err + } + + data, err := json.Marshal(tasks) + if err != nil { + return err + } + if _, err := fw.Write(data); err != nil { + return err + } + defer fw.Close() + + return nil +} diff --git a/cmd/android-app/screen/tasks.go b/cmd/android-app/screen/tasks.go index b0f66b6..723903e 100644 --- a/cmd/android-app/screen/tasks.go +++ b/cmd/android-app/screen/tasks.go @@ -21,6 +21,7 @@ type Tasks struct { tasks []Task taskLabels binding.StringList selectedTask string + list *widget.List out chan interface{} } @@ -44,6 +45,9 @@ func (t *Tasks) Refresh(state State) { tls = append(tls, t.Action) } t.taskLabels.Set(tls) + if t.selectedTask == "" { + t.list.UnselectAll() + } } func (t *Tasks) Content() fyne.CanvasObject { @@ -53,7 +57,7 @@ func (t *Tasks) Content() fyne.CanvasObject { doneButton := widget.NewButton("done", func() { t.markDone() }) - list := widget.NewListWithData( + t.list = widget.NewListWithData( t.taskLabels, func() fyne.CanvasObject { return widget.NewLabel("template") @@ -62,14 +66,14 @@ func (t *Tasks) Content() fyne.CanvasObject { o.(*widget.Label).Bind(i.(binding.String)) }, ) - list.OnSelected = t.selectItem + t.list.OnSelected = t.selectItem return container.NewBorder( container.NewHBox(statusLabel), doneButton, nil, nil, - list, + t.list, ) } @@ -89,4 +93,5 @@ func (t *Tasks) markDone() { t.out <- MarkTaskDoneRequest{ ID: t.selectedTask, } + t.selectedTask = "" } diff --git a/internal/storage/memory.go b/internal/storage/memory.go index e1fa192..32df2fa 100644 --- a/internal/storage/memory.go +++ b/internal/storage/memory.go @@ -13,9 +13,17 @@ type Memory struct { latestSync time.Time } -func NewMemory() *Memory { +func NewMemory(initTasks ...*task.Task) *Memory { + tasks := map[string]*task.LocalTask{} + for _, t := range initTasks { + tasks[t.Id] = &task.LocalTask{ + Task: *t, + LocalUpdate: &task.LocalUpdate{}, + } + } + return &Memory{ - tasks: map[string]*task.LocalTask{}, + tasks: tasks, } } diff --git a/internal/task/date.go b/internal/task/date.go index dea286b..84544d1 100644 --- a/internal/task/date.go +++ b/internal/task/date.go @@ -1,6 +1,7 @@ package task import ( + "encoding/json" "fmt" "sort" "strings" @@ -49,6 +50,21 @@ type Date struct { t time.Time } +func (d *Date) MarshalJSON() ([]byte, error) { + return json.Marshal(d.String()) +} + +func (d *Date) UnmarshalJSON(data []byte) error { + dateString := "" + if err := json.Unmarshal(data, &dateString); err != nil { + return err + } + nd := NewDateFromString(dateString) + d.t = nd.Time() + + return nil +} + func NewDate(year, month, day int) Date { if year == 0 || month == 0 || month > 12 || day == 0 { diff --git a/internal/task/task.go b/internal/task/task.go index 40271cd..bff5be8 100644 --- a/internal/task/task.go +++ b/internal/task/task.go @@ -64,15 +64,15 @@ type Task struct { // local situations. It will be filtered out in LocalRepository.SetTasks() Message *mstore.Message - Id string - Version int - Folder string + Id string `json:"id"` + Version int `json:"version"` + Folder string `json:"folder"` - Action string - Project string - Due Date - Recur Recurrer - Done bool + Action string `json:"action"` + Project string `json:"project"` + Due Date `json:"date"` + Recur Recurrer `json:"-"` + Done bool `json:"done"` } func NewFromMessage(msg *mstore.Message) *Task {