tui/task.go

273 lines
5.7 KiB
Go

package main
import (
"fmt"
"strings"
beryl "codeberg.org/beryl/go"
"github.com/google/uuid"
"golang.org/x/exp/slices"
)
type TaskView struct {
ID uuid.UUID
Task *beryl.Task
Parent *TaskView
Children []*TaskView
Expanded bool
}
func (taskv *TaskView) Delete(m model) *TaskView {
parent := taskv.Parent
idx := taskv.GetIDX()
if parent == nil {
return taskv
}
if parent.ID == m.taskView.ID {
parent = m.taskView
}
// delete task with same idx in parent task
if parent.Task != nil {
parent.Task.SubTasks = append(parent.Task.SubTasks[:idx], parent.Task.SubTasks[idx+1:]...)
}
// delete taskv with idx
parent.Children = append(parent.Children[:idx], parent.Children[idx+1:]...)
// return pointer of current idx
newCount := len(parent.Children)
if newCount == 0 {
return parent
}
if newCount == 1 {
return parent.Children[0]
}
if idx == 0 {
return parent.Children[idx]
}
return parent.Children[idx-1]
}
func (taskv *TaskView) AddSubtask() *TaskView {
newTask := beryl.Task{}
newTaskv := TaskView{
ID: uuid.New(),
Task: &newTask,
Parent: taskv,
}
taskv.Task.SubTasks = append(taskv.Task.SubTasks, &newTask)
taskv.Children = append(taskv.Children, &newTaskv)
return &newTaskv
}
func (taskv *TaskView) AddSibling() *TaskView {
idx := taskv.GetIDX()
//create actual task
newTask := beryl.Task{}
newTaskv := TaskView{
ID: uuid.New(),
Task: &newTask,
Parent: taskv.Parent,
}
if taskv.Parent.Task != nil {
// taskv.Parent.Task.SubTasks = append(taskv.Parent.Task.SubTasks, &newTask)
taskv.Parent.Task.SubTasks = append(taskv.Parent.Task.SubTasks[:idx+1], taskv.Parent.Task.SubTasks[idx:]...)
taskv.Parent.Task.SubTasks[idx] = &newTask
}
// get slice before idx, and after idx
// taskv.Parent.Children = append(taskv.Parent.Children, &newTaskv)
taskv.Parent.Children = append(taskv.Parent.Children[:idx+1], taskv.Parent.Children[idx:]...)
taskv.Parent.Children[idx] = &newTaskv
return &newTaskv
}
func (taskv TaskView) DownLast() *TaskView {
//check for children
// if none or collapsed return
numChildren := len(taskv.Children)
if !taskv.Expanded || numChildren == 0 {
return &taskv
}
// get last child
lastChild := taskv.Children[numChildren-1]
// return recurse on that child
return lastChild.DownLast()
}
func (taskv TaskView) GetLast() *TaskView {
parent := taskv.Parent
idx := taskv.GetIDX()
if parent.Parent == nil && idx == 0 {
return &taskv
}
//are we the 0th tast? return
if idx == 0 {
return taskv.Parent
}
// get task above
aboveSibling := parent.Children[idx-1]
// if not expanded, return it
if !aboveSibling.Expanded {
return aboveSibling
}
// count children
aboveChildren := len(aboveSibling.Children)
// if none, return it
if aboveChildren == 0 {
return aboveSibling
}
// call get last on it
return aboveSibling.Children[aboveChildren-1].DownLast()
}
func (taskv *TaskView) UpNext() *TaskView {
// get parent
parent := taskv.Parent
if parent == nil {
//taskv is the root task, just return the last item, we're not supposed to get all the way up here
// this should probably just return the actual final thing
return taskv.Children[len(taskv.Children)-1]
// return nil
}
// get current idx
idx := taskv.GetIDX()
// get parent children length
siblings := len(parent.Children)
// check if parent has a next child
if siblings > idx+1 {
return parent.Children[idx+1]
} else {
return parent.UpNext()
}
}
func (taskv *TaskView) GetNext() *TaskView {
if taskv.Expanded && len(taskv.Children) > 0 {
return taskv.Children[0]
}
idx := taskv.GetIDX()
length := len(taskv.Parent.Children)
if length > idx+1 {
return taskv.Parent.Children[idx+1]
}
// if the last item in arr
if length == idx+1 {
result := taskv.UpNext()
if result == nil {
return taskv
} else {
return result
}
}
// recursivly look up the parent tree to see if there is ever another sibling
return taskv
}
func (taskv TaskView) GetIDX() int {
return slices.IndexFunc(taskv.Parent.Children, func(c *TaskView) bool { return c.ID == taskv.ID })
}
func BuildRootViewTree(tasks []*beryl.Task) *TaskView {
tree := TaskView{}
// root
tree.Children = BuildViewTree(tasks, &tree)
// for _, child := tree.Children {
// tree.
// }
return &tree
}
func BuildViewTree(tasks []*beryl.Task, parent *TaskView) []*TaskView {
tree := []*TaskView{}
for _, task := range tasks {
newView := TaskView{
ID: uuid.New(),
Task: task,
Parent: parent,
Expanded: true,
}
children := BuildViewTree(task.SubTasks, &newView)
newView.Children = children
tree = append(tree, &newView)
}
return tree
}
// todo: what does move up and down mean in the context of subtask?
// func moveUp(arr []TaskView, i int) []TaskView {
// temp := arr[i]
// arr[i] = arr[i-1]
// arr[i-1] = temp
// return arr
// }
//
// func moveDown(arr []*beryl.Task, i int) []*beryl.Task {
// temp := arr[i]
// arr[i] = arr[i+1]
// arr[i+1] = temp
// return arr
// }
func FormatTask(m model, choice *TaskView, i int) string {
s := ""
cursor := "-" // no cursor
if m.cursor.ID == choice.ID {
cursor = ">" // cursor!
}
checked := " " // not selected
if choice.Task.Completed {
checked = "x" // selected!
}
if choice.ID == m.cursor.ID && m.isEditing {
s += fmt.Sprintf("%s [%s] ", cursor, checked)
s += m.editing.View()
} else {
s += fmt.Sprintf("%s [%s] %s", cursor, checked, choice.Task.Title)
}
// s += fmt.Sprintf(" me:%p p:%p", choice, choice.Parent)
s += "\n"
if choice.Expanded {
subString := ""
for _, choice2 := range choice.Children {
subString += FormatTask(m, choice2, -1)
}
subString = strings.Replace(subString, "- [", "\t- [", -1)
subString = strings.Replace(subString, "> [", "\t> [", -1)
s += subString
}
return s
}