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) }