2022-10-18 16:58:12 +02:00
|
|
|
package runner
|
|
|
|
|
|
|
|
import (
|
2022-10-23 12:45:21 +02:00
|
|
|
"encoding/json"
|
2022-10-18 16:58:12 +02:00
|
|
|
"fmt"
|
2022-10-23 12:45:21 +02:00
|
|
|
"io"
|
2022-10-23 10:25:11 +02:00
|
|
|
"sync"
|
2022-10-20 13:58:48 +02:00
|
|
|
"time"
|
2022-10-18 16:58:12 +02:00
|
|
|
|
|
|
|
"ewintr.nl/gte/cmd/android-app/component"
|
|
|
|
"ewintr.nl/gte/cmd/android-app/screen"
|
2022-10-23 12:45:21 +02:00
|
|
|
"ewintr.nl/gte/internal/task"
|
2022-10-18 16:58:12 +02:00
|
|
|
"fyne.io/fyne/v2"
|
2022-10-23 12:45:21 +02:00
|
|
|
"fyne.io/fyne/v2/storage"
|
2022-10-18 16:58:12 +02:00
|
|
|
)
|
|
|
|
|
2022-10-23 10:25:11 +02:00
|
|
|
var runnerLock = sync.Mutex{}
|
|
|
|
|
2022-10-18 16:58:12 +02:00
|
|
|
type Runner struct {
|
|
|
|
fyneApp fyne.App
|
|
|
|
fyneWindow fyne.Window
|
|
|
|
conf *component.Configuration
|
|
|
|
logger *component.Logger
|
|
|
|
tasks *component.Tasks
|
2022-10-20 08:50:52 +02:00
|
|
|
status string
|
2022-10-18 16:58:12 +02:00
|
|
|
requests chan interface{}
|
2022-10-20 08:50:52 +02:00
|
|
|
refresh chan bool
|
2022-10-23 14:08:19 +02:00
|
|
|
fileURI fyne.URI
|
2022-10-24 15:57:55 +02:00
|
|
|
screenSet *screen.ScreenSet
|
2022-10-18 16:58:12 +02:00
|
|
|
}
|
|
|
|
|
2022-10-23 14:08:19 +02:00
|
|
|
func NewRunner(conf *component.Configuration, fileURI fyne.URI, logger *component.Logger) *Runner {
|
2022-10-18 16:58:12 +02:00
|
|
|
return &Runner{
|
2022-10-23 10:25:11 +02:00
|
|
|
status: "init",
|
|
|
|
conf: conf,
|
|
|
|
logger: logger,
|
|
|
|
requests: make(chan interface{}),
|
2022-10-20 08:50:52 +02:00
|
|
|
refresh: make(chan bool),
|
2022-10-23 14:08:19 +02:00
|
|
|
fileURI: fileURI,
|
2022-10-18 16:58:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-23 10:25:11 +02:00
|
|
|
func (r *Runner) Init() fyne.CanvasObject {
|
2022-10-23 14:08:19 +02:00
|
|
|
stored, err := load(r.fileURI)
|
2022-10-18 16:58:12 +02:00
|
|
|
if err != nil {
|
|
|
|
r.logger.Log(err.Error())
|
|
|
|
}
|
2022-10-23 12:45:21 +02:00
|
|
|
r.logger.Log(fmt.Sprintf("loaded %d tasks from file", len(stored)))
|
|
|
|
r.tasks = component.NewTasks(r.conf, stored)
|
2022-10-18 16:58:12 +02:00
|
|
|
|
2022-10-24 15:57:55 +02:00
|
|
|
r.screenSet = screen.NewScreenSet(r.requests)
|
|
|
|
|
|
|
|
return r.screenSet.Content()
|
2022-10-18 16:58:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Runner) Run() {
|
2022-10-24 15:57:55 +02:00
|
|
|
go r.screenSet.Run()
|
2022-10-20 08:50:52 +02:00
|
|
|
go r.refresher()
|
2022-10-18 16:58:12 +02:00
|
|
|
go r.processRequest()
|
2022-10-23 10:25:11 +02:00
|
|
|
r.backgroundSync()
|
2022-10-18 16:58:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Runner) processRequest() {
|
|
|
|
for req := range r.requests {
|
|
|
|
switch v := req.(type) {
|
|
|
|
case screen.SaveConfigRequest:
|
2022-10-20 10:40:46 +02:00
|
|
|
r.status = "saving..."
|
|
|
|
r.refresh <- true
|
2022-10-18 16:58:12 +02:00
|
|
|
for k, val := range v.Fields {
|
|
|
|
r.conf.Set(k, val)
|
|
|
|
}
|
2022-10-24 15:57:55 +02:00
|
|
|
r.status = "config saved"
|
2022-10-23 16:46:37 +02:00
|
|
|
r.logger.Log("config saved")
|
2022-10-18 16:58:12 +02:00
|
|
|
case screen.SyncTasksRequest:
|
2022-10-20 08:50:52 +02:00
|
|
|
r.status = "syncing..."
|
|
|
|
r.refresh <- true
|
2022-10-23 16:46:37 +02:00
|
|
|
countDisp, countFetch, err := r.tasks.Sync()
|
2022-10-18 16:58:12 +02:00
|
|
|
if err != nil {
|
|
|
|
r.logger.Log(err.Error())
|
|
|
|
}
|
2022-10-23 16:46:37 +02:00
|
|
|
if countDisp > 0 || countFetch > 0 {
|
|
|
|
r.logger.Log(fmt.Sprintf("task sync: dispatched: %d, fetched: %d", countDisp, countFetch))
|
|
|
|
}
|
2022-10-24 15:57:55 +02:00
|
|
|
r.status = "synced"
|
2022-10-23 12:45:21 +02:00
|
|
|
all, err := r.tasks.All()
|
|
|
|
if err != nil {
|
|
|
|
r.logger.Log(err.Error())
|
|
|
|
break
|
|
|
|
}
|
2022-10-23 14:08:19 +02:00
|
|
|
if err := save(r.fileURI, all); err != nil {
|
2022-10-23 12:45:21 +02:00
|
|
|
r.logger.Log(err.Error())
|
|
|
|
break
|
|
|
|
}
|
2022-10-20 10:40:46 +02:00
|
|
|
case screen.MarkTaskDoneRequest:
|
2022-10-24 15:57:55 +02:00
|
|
|
r.status = "marking done..."
|
|
|
|
r.refresh <- true
|
2022-10-20 10:40:46 +02:00
|
|
|
if err := r.tasks.MarkDone(v.ID); err != nil {
|
|
|
|
r.logger.Log(err.Error())
|
|
|
|
}
|
2022-10-20 14:49:33 +02:00
|
|
|
r.logger.Log(fmt.Sprintf("marked task %q done", v.ID))
|
2022-10-24 15:57:55 +02:00
|
|
|
r.status = "marked done"
|
2022-10-31 09:18:36 +01:00
|
|
|
case screen.SaveNewTaskRequest:
|
|
|
|
r.status = "saving..."
|
|
|
|
r.refresh <- true
|
|
|
|
if err := r.tasks.Add(v.Fields); err != nil {
|
|
|
|
r.logger.Log(err.Error())
|
|
|
|
}
|
|
|
|
r.status = "saved"
|
|
|
|
r.refresh <- true
|
2022-10-31 15:59:58 +01:00
|
|
|
case screen.UpdateTaskRequest:
|
|
|
|
r.status = "saving..."
|
|
|
|
r.refresh <- true
|
|
|
|
if err := r.tasks.Update(v.ID, v.Due); err != nil {
|
|
|
|
r.logger.Log(err.Error())
|
|
|
|
}
|
|
|
|
r.logger.Log(fmt.Sprintf("updated due date task %q", v.ID))
|
|
|
|
r.status = "saved"
|
|
|
|
r.refresh <- true
|
2022-10-18 16:58:12 +02:00
|
|
|
default:
|
|
|
|
r.logger.Log("request unknown")
|
|
|
|
}
|
2022-10-23 10:25:11 +02:00
|
|
|
r.refresh <- true
|
2022-10-18 16:58:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-20 08:50:52 +02:00
|
|
|
func (r *Runner) refresher() {
|
2022-10-23 10:25:11 +02:00
|
|
|
for <-r.refresh {
|
2022-10-20 08:50:52 +02:00
|
|
|
tasks, err := r.tasks.Today()
|
|
|
|
if err != nil {
|
|
|
|
r.logger.Log(err.Error())
|
|
|
|
}
|
2022-10-20 10:40:46 +02:00
|
|
|
sTasks := []screen.Task{}
|
|
|
|
for id, action := range tasks {
|
|
|
|
sTasks = append(sTasks, screen.Task{
|
|
|
|
ID: id,
|
|
|
|
Action: action,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-10-20 08:50:52 +02:00
|
|
|
state := screen.State{
|
|
|
|
Status: r.status,
|
2022-10-20 10:40:46 +02:00
|
|
|
Tasks: sTasks,
|
2022-10-20 08:50:52 +02:00
|
|
|
Config: r.conf.Fields(),
|
|
|
|
Logs: r.logger.Lines(),
|
|
|
|
}
|
2022-10-23 10:25:11 +02:00
|
|
|
|
2022-10-24 15:57:55 +02:00
|
|
|
r.screenSet.Refresh(state)
|
2022-10-18 16:58:12 +02:00
|
|
|
}
|
|
|
|
}
|
2022-10-20 13:58:48 +02:00
|
|
|
|
|
|
|
func (r *Runner) backgroundSync() {
|
2022-10-23 10:25:11 +02:00
|
|
|
ticker := time.NewTicker(15 * time.Second)
|
2022-10-20 13:58:48 +02:00
|
|
|
for {
|
|
|
|
r.requests <- screen.SyncTasksRequest{}
|
2022-10-23 10:25:11 +02:00
|
|
|
<-ticker.C
|
2022-10-20 13:58:48 +02:00
|
|
|
}
|
|
|
|
}
|
2022-10-23 12:45:21 +02:00
|
|
|
|
2022-10-23 14:08:19 +02:00
|
|
|
func load(fu fyne.URI) ([]*task.Task, error) {
|
|
|
|
fr, err := storage.Reader(fu)
|
2022-10-23 12:45:21 +02:00
|
|
|
if err != nil {
|
|
|
|
return []*task.Task{}, err
|
|
|
|
}
|
|
|
|
defer fr.Close()
|
|
|
|
|
2022-10-23 14:08:19 +02:00
|
|
|
exists, err := storage.Exists(fu)
|
2022-10-23 12:45:21 +02:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2022-10-23 14:08:19 +02:00
|
|
|
func save(fu fyne.URI, tasks []*task.Task) error {
|
|
|
|
fw, err := storage.Writer(fu)
|
2022-10-23 12:45:21 +02:00
|
|
|
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
|
|
|
|
}
|