gask/model.go

236 lines
5.1 KiB
Go

package main
import (
"sort"
"strings"
"time"
todotxt "git.bullercodeworks.com/brian/go-todotxt"
)
// diskListChanged returns true if the task list in todo.txt
// is different than what we have previously loaded.
func (a *AppState) diskListChanged() bool {
if !a.taskListLoaded {
return false
}
curr, err := todotxt.LoadFromFilename(a.getTodoFile())
if err != nil {
return false
}
return curr.String() != a.TodoList.String()
}
// diskDoneListChanged returns true if the task list in done.txt
// is different than what we have previously loaded.
func (a *AppState) diskDoneListChanged() bool {
if !a.doneListLoaded {
return false
}
curr, err := todotxt.LoadFromFilename(a.getDoneFile())
if err != nil {
return false
}
return curr.String() != a.DoneList.String()
}
func (a *AppState) addTodo(taskString string) error {
if a.diskListChanged() {
return a.e(ResStrListChanged)
}
t, err := todotxt.ParseTodo(taskString)
if err != nil {
return err
}
if t.CreatedDate.IsZero() {
t.CreatedDate = time.Now()
}
a.TodoList.AddTodo(t)
return a.WriteList()
}
func (a *AppState) saveTodo(t *todotxt.Todo) error {
lt, err := a.TodoList.GetTodo(t.Id)
if err != nil {
return err
}
lt.Todo = t.Todo
lt.Priority = t.Priority
lt.Projects = t.Projects
lt.Contexts = t.Contexts
lt.AdditionalTags = t.AdditionalTags
return a.WriteList()
}
func (a *AppState) toggleTodoComplete(id int) error {
if a.diskListChanged() {
return a.e(ResStrListChanged)
}
var task *todotxt.Todo
var err error
if task, err = a.TodoList.GetTodo(id); err != nil {
return err
}
if task.Completed {
task.Reopen()
} else {
task.Complete()
}
return a.WriteList()
}
func (a *AppState) archiveTodo(id int) error {
if a.diskListChanged() {
return a.e(ResStrListChanged)
}
var err error
var task *todotxt.Todo
if task, err = a.TodoList.GetTodo(id); err != nil {
return err
}
if err := a.TodoList.ArchiveTodoToFile(*task, a.getDoneFile()); err != nil {
return err
}
a.TodoList.RemoveTodo(*task)
return a.WriteList()
}
func (a *AppState) unarchiveTodo(id int) error {
if a.diskListChanged() {
return a.e(ResStrListChanged)
}
var err error
var task *todotxt.Todo
if task, err = a.DoneList.GetTodo(id); err != nil {
return err
}
a.TodoList.AddTodo(task)
if err = a.WriteList(); err != nil {
return err
}
a.DoneList.RemoveTodo(*task)
return a.WriteDoneList()
}
func (a *AppState) getFilterPredicate(filter string) func(todotxt.Todo) bool {
var predicates []func(todotxt.Todo) bool
// If none of the 'filter' is in upper-case, do a case-insensitive filter
checkCase := true
if strings.ToLower(filter) == filter {
checkCase = false
}
filterParts := strings.Split(filter, " ")
for _, part := range filterParts {
if part == ":x" {
predicates = append(predicates, func(t todotxt.Todo) bool {
return t.Completed
})
} else if part == ":-x" || part == ":o" {
predicates = append(predicates, func(t todotxt.Todo) bool {
return !t.Completed
})
}
if strings.HasPrefix(part, "@") {
predicates = append(predicates, func(t todotxt.Todo) bool {
for _, v := range t.Contexts {
if "@"+v == part {
return true
}
}
return false
})
} else if strings.HasPrefix(part, "+") {
predicates = append(predicates, func(t todotxt.Todo) bool {
for _, v := range t.Projects {
if "+"+v == part {
return true
}
}
return false
})
} else {
predicates = append(predicates, func(t todotxt.Todo) bool {
val := t.Original
if !checkCase {
val = strings.ToLower(t.Original)
}
return strings.Contains(val, part)
})
}
}
return func(t todotxt.Todo) bool {
for _, v := range predicates {
if v(t) {
return true
}
}
return false
}
}
func (a *AppState) LoadTodoList() error {
tl, err := todotxt.LoadFromFilename(a.getTodoFile())
a.TodoList = tl
a.taskListLoaded = true
return err
}
func (a *AppState) LoadDoneList() error {
tl, err := todotxt.LoadFromFilename(a.getDoneFile())
a.DoneList = tl
a.doneListLoaded = true
return err
}
func (a *AppState) WriteList() error {
if !a.taskListLoaded {
return a.e(ResStrTodoListNotLoaded)
}
return a.TodoList.WriteToFilename(a.getTodoFile())
}
func (a *AppState) WriteDoneList() error {
if !a.doneListLoaded {
return a.e(ResStrDoneListNotLoaded)
}
return a.DoneList.WriteToFilename(a.getDoneFile())
}
func (a *AppState) AdvancedPrioritySort(t1, t2 *todotxt.Todo) bool {
if t1.HasPriority() && t2.HasPriority() {
return t1.Priority < t2.Priority
} else if t1.HasPriority() && !t2.HasPriority() {
return t1.Priority <= "Y"
} else if !t1.HasPriority() && t2.HasPriority() {
return "Y" <= t2.Priority
}
return t1.HasPriority()
}
type customSort struct {
list []todotxt.Todo
by func(t1, t2 *todotxt.Todo) bool
}
func (c *customSort) Len() int {
return len(c.list)
}
func (c *customSort) Swap(l, r int) {
c.list[l], c.list[r] = c.list[r], c.list[l]
}
func (c *customSort) Less(l, r int) bool {
return c.by(&c.list[l], &c.list[r])
}
type By func(t1, t2 *todotxt.Todo) bool
func (by By) Sort(list []todotxt.Todo) {
ts := &customSort{
list: list,
by: by,
}
sort.Sort(ts)
}