2019-02-15 17:15:26 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2021-03-17 17:37:26 +00:00
|
|
|
todotxt "git.bullercodeworks.com/brian/go-todotxt"
|
|
|
|
termboxScreen "git.bullercodeworks.com/brian/termbox-screen"
|
|
|
|
termboxUtil "git.bullercodeworks.com/brian/termbox-util"
|
2019-02-15 17:15:26 +00:00
|
|
|
termbox "github.com/nsf/termbox-go"
|
|
|
|
)
|
|
|
|
|
2019-03-14 15:29:33 +00:00
|
|
|
const (
|
2023-09-07 19:39:45 +00:00
|
|
|
FieldTodoTodo = iota
|
|
|
|
FieldTodoPriority
|
|
|
|
FieldTodoProjects
|
|
|
|
FieldTodoContexts
|
|
|
|
FieldTodoTags
|
|
|
|
FieldTodoError
|
2019-02-28 13:44:03 +00:00
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
TodoBundleTodoIdKey = "todoscreen.todoid"
|
2019-03-14 15:29:33 +00:00
|
|
|
)
|
2019-02-15 17:15:26 +00:00
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
type TodoScreen struct {
|
2019-03-14 15:29:33 +00:00
|
|
|
message *Message
|
|
|
|
cursor int
|
2019-02-15 17:15:26 +00:00
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
currentTodoId int
|
|
|
|
displayTodo *todotxt.Todo
|
2019-03-14 15:29:33 +00:00
|
|
|
fieldLabels map[int]string
|
|
|
|
editing bool
|
|
|
|
|
|
|
|
inputField *termboxUtil.InputField
|
2019-02-15 17:15:26 +00:00
|
|
|
}
|
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) GetFieldValue(fld int) string {
|
2019-03-14 15:29:33 +00:00
|
|
|
switch fld {
|
2023-09-07 19:39:45 +00:00
|
|
|
case FieldTodoTodo:
|
|
|
|
return screen.displayTodo.Todo
|
|
|
|
case FieldTodoPriority:
|
|
|
|
return screen.displayTodo.Priority
|
|
|
|
case FieldTodoProjects:
|
|
|
|
return strings.Join(screen.displayTodo.Projects, ",")
|
|
|
|
case FieldTodoContexts:
|
|
|
|
return strings.Join(screen.displayTodo.Contexts, ",")
|
|
|
|
case FieldTodoTags:
|
2019-03-14 15:29:33 +00:00
|
|
|
var ret []string
|
2023-09-07 19:39:45 +00:00
|
|
|
for k, v := range screen.displayTodo.AdditionalTags {
|
2019-03-14 15:29:33 +00:00
|
|
|
ret = append(ret, k+":"+v)
|
|
|
|
}
|
|
|
|
return strings.Join(ret, ",")
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
2019-02-15 17:15:26 +00:00
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) Id() int { return ScreenIdTodo }
|
2019-02-28 13:44:03 +00:00
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) Initialize(bundle termboxScreen.Bundle) error {
|
2019-03-14 15:29:33 +00:00
|
|
|
screen.fieldLabels = make(map[int]string)
|
2023-09-07 19:39:45 +00:00
|
|
|
screen.fieldLabels[FieldTodoTodo] = "Todo"
|
|
|
|
screen.fieldLabels[FieldTodoPriority] = "Priority"
|
|
|
|
screen.fieldLabels[FieldTodoProjects] = "Projects"
|
|
|
|
screen.fieldLabels[FieldTodoContexts] = "Contexts"
|
|
|
|
screen.fieldLabels[FieldTodoTags] = "Tags"
|
2019-02-15 17:15:26 +00:00
|
|
|
var err error
|
2019-03-14 15:29:33 +00:00
|
|
|
width, height := termbox.Size()
|
|
|
|
screen.inputField = termboxUtil.CreateInputField(2, (height - 3), width, 1, DefaultFg, DefaultBg)
|
|
|
|
screen.message = NewMessage("", DefaultFg, DefaultBg, time.Second*2)
|
2019-02-21 16:47:08 +00:00
|
|
|
if bundle != nil {
|
2023-09-07 19:39:45 +00:00
|
|
|
screen.currentTodoId = bundle.GetInt(TodoBundleTodoIdKey, -1)
|
2019-02-21 16:47:08 +00:00
|
|
|
}
|
2023-09-07 19:39:45 +00:00
|
|
|
if screen.currentTodoId == -1 {
|
|
|
|
return errors.New("Todo Screen Initialization Failed")
|
2019-02-15 17:15:26 +00:00
|
|
|
}
|
2023-09-07 19:39:45 +00:00
|
|
|
if screen.displayTodo, err = app.TodoList.GetTodo(screen.currentTodoId); err != nil {
|
2019-02-15 17:15:26 +00:00
|
|
|
return err
|
|
|
|
}
|
2023-09-07 19:39:45 +00:00
|
|
|
screen.cursor = FieldTodoTodo
|
2019-02-15 17:15:26 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) ResizeScreen() { screen.Initialize(nil) }
|
2019-02-28 13:44:03 +00:00
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) HandleKeyEvent(event termbox.Event) int {
|
2019-03-14 15:29:33 +00:00
|
|
|
if screen.editing {
|
|
|
|
return screen.handleEditingKeyEvent(event)
|
|
|
|
}
|
|
|
|
if event.Key == termbox.KeyEnter {
|
|
|
|
screen.editing = true
|
2021-03-17 17:37:26 +00:00
|
|
|
//screen.inputField.SetTitle(screen.fieldLabels[screen.cursor] + ": ")
|
2019-03-14 15:29:33 +00:00
|
|
|
screen.inputField.SetValue(screen.GetFieldValue(screen.cursor))
|
2021-03-17 17:37:26 +00:00
|
|
|
//screen.inputField.SetActive(true)
|
2019-03-14 15:29:33 +00:00
|
|
|
return screen.Id()
|
|
|
|
|
|
|
|
} else if event.Key == termbox.KeyBackspace || event.Key == termbox.KeyBackspace2 || event.Ch == 'h' || event.Key == termbox.KeyArrowLeft {
|
|
|
|
bundle := termboxScreen.Bundle{}
|
|
|
|
bundle.SetValue(MainBundleListKey, MainBundleListCurrent)
|
|
|
|
app.uiManager.InitializeScreen(ScreenIdMain, bundle)
|
|
|
|
return ScreenIdMain
|
2019-02-15 17:15:26 +00:00
|
|
|
|
|
|
|
} else if event.Ch == 'j' || event.Key == termbox.KeyArrowDown {
|
|
|
|
screen.moveCursorDown()
|
|
|
|
|
|
|
|
} else if event.Ch == 'k' || event.Key == termbox.KeyArrowUp {
|
|
|
|
screen.moveCursorUp()
|
|
|
|
}
|
2019-03-14 15:29:33 +00:00
|
|
|
return screen.Id()
|
2019-02-15 17:15:26 +00:00
|
|
|
}
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) HandleNoneEvent(event termbox.Event) int { return screen.Id() }
|
2019-02-15 17:15:26 +00:00
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) DrawScreen() {
|
2019-02-15 17:15:26 +00:00
|
|
|
screen.drawHeader()
|
|
|
|
|
|
|
|
yPos := 1
|
2023-09-07 19:39:45 +00:00
|
|
|
if screen.cursor == FieldTodoTodo {
|
|
|
|
termboxUtil.DrawStringAtPoint(screen.displayTodo.Todo, 0, yPos, CursorBg, CursorFg)
|
2019-03-14 15:29:33 +00:00
|
|
|
} else {
|
2023-09-07 19:39:45 +00:00
|
|
|
termboxUtil.DrawStringAtPoint(screen.displayTodo.Todo, 0, yPos, DefaultFg, DefaultBg)
|
2019-03-14 15:29:33 +00:00
|
|
|
}
|
2019-02-15 17:15:26 +00:00
|
|
|
yPos++
|
2023-09-07 19:39:45 +00:00
|
|
|
if screen.cursor == FieldTodoPriority {
|
|
|
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Priority: %s", screen.displayTodo.Priority), 0, yPos, CursorBg, CursorFg)
|
2019-03-14 15:29:33 +00:00
|
|
|
} else {
|
2023-09-07 19:39:45 +00:00
|
|
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Priority: %s", screen.displayTodo.Priority), 0, yPos, DefaultFg, DefaultBg)
|
2019-03-14 15:29:33 +00:00
|
|
|
}
|
2019-02-15 17:15:26 +00:00
|
|
|
yPos++
|
2023-09-07 19:39:45 +00:00
|
|
|
if screen.cursor == FieldTodoProjects {
|
|
|
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Projects: %s", screen.displayTodo.Projects), 0, yPos, CursorBg, CursorFg)
|
2019-03-14 15:29:33 +00:00
|
|
|
} else {
|
2023-09-07 19:39:45 +00:00
|
|
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Projects: %s", screen.displayTodo.Projects), 0, yPos, DefaultFg, DefaultBg)
|
2019-03-14 15:29:33 +00:00
|
|
|
}
|
2019-02-15 17:15:26 +00:00
|
|
|
yPos++
|
2023-09-07 19:39:45 +00:00
|
|
|
if screen.cursor == FieldTodoContexts {
|
|
|
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Contexts: %s", screen.displayTodo.Contexts), 0, yPos, CursorBg, CursorFg)
|
2019-03-14 15:29:33 +00:00
|
|
|
} else {
|
2023-09-07 19:39:45 +00:00
|
|
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Contexts: %s", screen.displayTodo.Contexts), 0, yPos, DefaultFg, DefaultBg)
|
2019-03-14 15:29:33 +00:00
|
|
|
}
|
2019-02-15 17:15:26 +00:00
|
|
|
yPos++
|
2023-09-07 19:39:45 +00:00
|
|
|
if screen.cursor == FieldTodoTags {
|
2019-03-14 15:29:33 +00:00
|
|
|
termboxUtil.DrawStringAtPoint("Additional Tags: ", 0, yPos, CursorBg, CursorFg)
|
|
|
|
} else {
|
|
|
|
termboxUtil.DrawStringAtPoint("Additional Tags: ", 0, yPos, DefaultFg, DefaultBg)
|
|
|
|
}
|
2019-02-15 17:15:26 +00:00
|
|
|
yPos++
|
2023-09-07 19:39:45 +00:00
|
|
|
for k, v := range screen.displayTodo.AdditionalTags {
|
2019-02-15 17:15:26 +00:00
|
|
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("%s: %s", k, v), 0, yPos, DefaultFg, DefaultBg)
|
|
|
|
yPos++
|
|
|
|
}
|
|
|
|
|
2019-03-14 15:29:33 +00:00
|
|
|
if screen.editing {
|
|
|
|
w, h := termbox.Size()
|
|
|
|
termboxUtil.DrawBorder(0, h-4, w-1, h-2, CursorBg, CursorFg)
|
|
|
|
termboxUtil.FillWithChar(' ', 1, h-3, w-2, h-3, DefaultFg, DefaultBg)
|
|
|
|
screen.inputField.Draw()
|
|
|
|
}
|
|
|
|
|
2019-02-15 17:15:26 +00:00
|
|
|
screen.drawFooter()
|
|
|
|
}
|
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) handleEditingKeyEvent(event termbox.Event) int {
|
2019-03-14 15:29:33 +00:00
|
|
|
if event.Key == termbox.KeyEnter {
|
|
|
|
var needsSave bool
|
|
|
|
// Save the change
|
|
|
|
switch screen.cursor {
|
2023-09-07 19:39:45 +00:00
|
|
|
case FieldTodoTodo:
|
|
|
|
//screen.displayTodo.Todo = screen.inputField.GetValue()
|
|
|
|
if screen.inputField.GetValue() != screen.displayTodo.Todo {
|
|
|
|
screen.displayTodo.Todo = screen.inputField.GetValue()
|
2019-03-14 15:29:33 +00:00
|
|
|
needsSave = true
|
|
|
|
}
|
2023-09-07 19:39:45 +00:00
|
|
|
case FieldTodoPriority:
|
2019-03-14 15:29:33 +00:00
|
|
|
val := screen.inputField.GetValue()
|
|
|
|
if len(val) > 0 {
|
|
|
|
val = string(val[0])
|
|
|
|
}
|
2023-09-07 19:39:45 +00:00
|
|
|
if val != screen.displayTodo.Priority {
|
|
|
|
screen.displayTodo.Priority = val
|
2019-03-14 15:29:33 +00:00
|
|
|
needsSave = true
|
|
|
|
}
|
2023-09-07 19:39:45 +00:00
|
|
|
case FieldTodoProjects:
|
2019-03-14 15:29:33 +00:00
|
|
|
projects := splitFields(screen.inputField.GetValue())
|
2023-09-07 19:39:45 +00:00
|
|
|
if !isCombination(projects, screen.displayTodo.Projects) {
|
2019-03-14 15:29:33 +00:00
|
|
|
needsSave = true
|
2023-09-07 19:39:45 +00:00
|
|
|
screen.displayTodo.Projects = []string{}
|
2019-03-14 15:29:33 +00:00
|
|
|
for _, v := range projects {
|
2023-09-07 19:39:45 +00:00
|
|
|
screen.displayTodo.Projects = append(screen.displayTodo.Projects, v)
|
2019-03-14 15:29:33 +00:00
|
|
|
}
|
|
|
|
}
|
2023-09-07 19:39:45 +00:00
|
|
|
case FieldTodoContexts:
|
2019-03-14 15:29:33 +00:00
|
|
|
contexts := splitFields(screen.inputField.GetValue())
|
2023-09-07 19:39:45 +00:00
|
|
|
if !isCombination(contexts, screen.displayTodo.Contexts) {
|
2019-03-14 15:29:33 +00:00
|
|
|
needsSave = true
|
2023-09-07 19:39:45 +00:00
|
|
|
screen.displayTodo.Contexts = []string{}
|
2019-03-14 15:29:33 +00:00
|
|
|
for _, v := range contexts {
|
2023-09-07 19:39:45 +00:00
|
|
|
screen.displayTodo.Contexts = append(screen.displayTodo.Contexts, v)
|
2019-03-14 15:29:33 +00:00
|
|
|
}
|
|
|
|
}
|
2023-09-07 19:39:45 +00:00
|
|
|
case FieldTodoTags:
|
2019-03-14 15:29:33 +00:00
|
|
|
tagsSlice := splitFields(screen.inputField.GetValue())
|
|
|
|
if !sliceIsValidTags(tagsSlice) {
|
|
|
|
screen.message.Set("Tags should be in format <key>:<val>")
|
|
|
|
return screen.Id()
|
|
|
|
}
|
2023-09-07 19:39:45 +00:00
|
|
|
if !isCombination(tagsSlice, tagsToSlice(screen.displayTodo.AdditionalTags)) {
|
2019-03-14 15:29:33 +00:00
|
|
|
needsSave = true
|
2023-09-07 19:39:45 +00:00
|
|
|
screen.displayTodo.AdditionalTags = make(map[string]string)
|
2019-03-14 15:29:33 +00:00
|
|
|
for k, v := range sliceToTags(tagsSlice) {
|
2023-09-07 19:39:45 +00:00
|
|
|
screen.displayTodo.AdditionalTags[k] = v
|
2019-03-14 15:29:33 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if needsSave {
|
2023-09-07 19:39:45 +00:00
|
|
|
if err := app.saveTodo(screen.displayTodo); err != nil {
|
2019-03-14 15:29:33 +00:00
|
|
|
screen.message.SetError(err.Error())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
screen.editing = false
|
2021-03-17 17:37:26 +00:00
|
|
|
//screen.inputField.SetActive(false)
|
2019-03-14 15:29:33 +00:00
|
|
|
} else {
|
|
|
|
if screen.inputField.HandleEvent(event) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return screen.Id()
|
|
|
|
}
|
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) drawHeader() {
|
2019-02-15 17:15:26 +00:00
|
|
|
width, _ := termbox.Size()
|
2023-09-07 19:39:45 +00:00
|
|
|
headerString := screen.displayTodo.Todo
|
2019-02-15 17:15:26 +00:00
|
|
|
spaces := strings.Repeat(" ", ((width-len(headerString))/2)+1)
|
|
|
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("%s%s%s", spaces, headerString, spaces), 0, 0, TitleFg, TitleBg)
|
|
|
|
}
|
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) drawFooter() {
|
2019-02-15 17:15:26 +00:00
|
|
|
_, height := termbox.Size()
|
2019-03-14 15:29:33 +00:00
|
|
|
screen.message.DrawAt(0, height-1)
|
2019-02-15 17:15:26 +00:00
|
|
|
}
|
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) moveCursorDown() bool {
|
|
|
|
screen.cursor = (screen.cursor + 1) % FieldTodoError
|
2019-02-15 17:15:26 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) moveCursorUp() bool {
|
2019-03-14 15:29:33 +00:00
|
|
|
if screen.cursor > 0 {
|
|
|
|
screen.cursor--
|
|
|
|
} else {
|
2023-09-07 19:39:45 +00:00
|
|
|
screen.cursor = FieldTodoError - 1
|
2019-03-14 15:29:33 +00:00
|
|
|
}
|
2019-02-15 17:15:26 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-09-07 19:39:45 +00:00
|
|
|
func (screen *TodoScreen) editCurrentField() {
|
2019-02-15 17:15:26 +00:00
|
|
|
|
|
|
|
}
|