gask/screen_task.go

258 lines
7.6 KiB
Go

package main
import (
"errors"
"fmt"
"strings"
"time"
todotxt "github.com/br0xen/go-todotxt"
"github.com/br0xen/termbox-screen"
"github.com/br0xen/termbox-util"
termbox "github.com/nsf/termbox-go"
)
const (
FieldTaskTodo = iota
FieldTaskPriority
FieldTaskProjects
FieldTaskContexts
FieldTaskTags
FieldTaskError
TaskBundleTaskIdKey = "taskscreen.taskid"
)
type TaskScreen struct {
message *Message
cursor int
currentTaskId int
displayTask *todotxt.Task
fieldLabels map[int]string
editing bool
inputField *termboxUtil.InputField
}
func (screen *TaskScreen) GetFieldValue(fld int) string {
switch fld {
case FieldTaskTodo:
return screen.displayTask.Todo
case FieldTaskPriority:
return screen.displayTask.Priority
case FieldTaskProjects:
return strings.Join(screen.displayTask.Projects, ",")
case FieldTaskContexts:
return strings.Join(screen.displayTask.Contexts, ",")
case FieldTaskTags:
var ret []string
for k, v := range screen.displayTask.AdditionalTags {
ret = append(ret, k+":"+v)
}
return strings.Join(ret, ",")
}
return ""
}
func (screen *TaskScreen) Id() int { return ScreenIdTask }
func (screen *TaskScreen) Initialize(bundle termboxScreen.Bundle) error {
screen.fieldLabels = make(map[int]string)
screen.fieldLabels[FieldTaskTodo] = "Todo"
screen.fieldLabels[FieldTaskPriority] = "Priority"
screen.fieldLabels[FieldTaskProjects] = "Projects"
screen.fieldLabels[FieldTaskContexts] = "Contexts"
screen.fieldLabels[FieldTaskTags] = "Tags"
var err error
width, height := termbox.Size()
screen.inputField = termboxUtil.CreateInputField(2, (height - 3), width, 1, DefaultFg, DefaultBg)
screen.message = NewMessage("", DefaultFg, DefaultBg, time.Second*2)
if bundle != nil {
screen.currentTaskId = bundle.GetInt(TaskBundleTaskIdKey, -1)
}
if screen.currentTaskId == -1 {
return errors.New("Task Screen Initialization Failed")
}
if screen.displayTask, err = app.TaskList.GetTask(screen.currentTaskId); err != nil {
return err
}
screen.cursor = FieldTaskTodo
return nil
}
func (screen *TaskScreen) ResizeScreen() { screen.Initialize(nil) }
func (screen *TaskScreen) HandleKeyEvent(event termbox.Event) int {
if screen.editing {
return screen.handleEditingKeyEvent(event)
}
if event.Key == termbox.KeyEnter {
screen.editing = true
screen.inputField.SetTitle(screen.fieldLabels[screen.cursor] + ": ")
screen.inputField.SetValue(screen.GetFieldValue(screen.cursor))
screen.inputField.SetActive(true)
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
} else if event.Ch == 'j' || event.Key == termbox.KeyArrowDown {
screen.moveCursorDown()
} else if event.Ch == 'k' || event.Key == termbox.KeyArrowUp {
screen.moveCursorUp()
}
return screen.Id()
}
func (screen *TaskScreen) HandleNoneEvent(event termbox.Event) int { return screen.Id() }
func (screen *TaskScreen) DrawScreen() {
screen.drawHeader()
yPos := 1
if screen.cursor == FieldTaskTodo {
termboxUtil.DrawStringAtPoint(screen.displayTask.Todo, 0, yPos, CursorBg, CursorFg)
} else {
termboxUtil.DrawStringAtPoint(screen.displayTask.Todo, 0, yPos, DefaultFg, DefaultBg)
}
yPos++
if screen.cursor == FieldTaskPriority {
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Priority: %s", screen.displayTask.Priority), 0, yPos, CursorBg, CursorFg)
} else {
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Priority: %s", screen.displayTask.Priority), 0, yPos, DefaultFg, DefaultBg)
}
yPos++
if screen.cursor == FieldTaskProjects {
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Projects: %s", screen.displayTask.Projects), 0, yPos, CursorBg, CursorFg)
} else {
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Projects: %s", screen.displayTask.Projects), 0, yPos, DefaultFg, DefaultBg)
}
yPos++
if screen.cursor == FieldTaskContexts {
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Contexts: %s", screen.displayTask.Contexts), 0, yPos, CursorBg, CursorFg)
} else {
termboxUtil.DrawStringAtPoint(fmt.Sprintf("Contexts: %s", screen.displayTask.Contexts), 0, yPos, DefaultFg, DefaultBg)
}
yPos++
if screen.cursor == FieldTaskTags {
termboxUtil.DrawStringAtPoint("Additional Tags: ", 0, yPos, CursorBg, CursorFg)
} else {
termboxUtil.DrawStringAtPoint("Additional Tags: ", 0, yPos, DefaultFg, DefaultBg)
}
yPos++
for k, v := range screen.displayTask.AdditionalTags {
termboxUtil.DrawStringAtPoint(fmt.Sprintf("%s: %s", k, v), 0, yPos, DefaultFg, DefaultBg)
yPos++
}
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()
}
screen.drawFooter()
}
func (screen *TaskScreen) handleEditingKeyEvent(event termbox.Event) int {
if event.Key == termbox.KeyEnter {
var needsSave bool
// Save the change
switch screen.cursor {
case FieldTaskTodo:
//screen.displayTask.Todo = screen.inputField.GetValue()
if screen.inputField.GetValue() != screen.displayTask.Todo {
screen.displayTask.Todo = screen.inputField.GetValue()
needsSave = true
}
case FieldTaskPriority:
val := screen.inputField.GetValue()
if len(val) > 0 {
val = string(val[0])
}
if val != screen.displayTask.Priority {
screen.displayTask.Priority = val
needsSave = true
}
case FieldTaskProjects:
projects := splitFields(screen.inputField.GetValue())
if !isCombination(projects, screen.displayTask.Projects) {
needsSave = true
screen.displayTask.Projects = []string{}
for _, v := range projects {
screen.displayTask.Projects = append(screen.displayTask.Projects, v)
}
}
case FieldTaskContexts:
contexts := splitFields(screen.inputField.GetValue())
if !isCombination(contexts, screen.displayTask.Contexts) {
needsSave = true
screen.displayTask.Contexts = []string{}
for _, v := range contexts {
screen.displayTask.Contexts = append(screen.displayTask.Contexts, v)
}
}
case FieldTaskTags:
tagsSlice := splitFields(screen.inputField.GetValue())
if !sliceIsValidTags(tagsSlice) {
screen.message.Set("Tags should be in format <key>:<val>")
return screen.Id()
}
if !isCombination(tagsSlice, tagsToSlice(screen.displayTask.AdditionalTags)) {
needsSave = true
screen.displayTask.AdditionalTags = make(map[string]string)
for k, v := range sliceToTags(tagsSlice) {
screen.displayTask.AdditionalTags[k] = v
}
}
}
if needsSave {
if err := app.saveTask(screen.displayTask); err != nil {
screen.message.SetError(err.Error())
}
}
screen.editing = false
screen.inputField.SetActive(false)
} else {
if screen.inputField.HandleEvent(event) {
}
}
return screen.Id()
}
func (screen *TaskScreen) drawHeader() {
width, _ := termbox.Size()
headerString := screen.displayTask.Todo
spaces := strings.Repeat(" ", ((width-len(headerString))/2)+1)
termboxUtil.DrawStringAtPoint(fmt.Sprintf("%s%s%s", spaces, headerString, spaces), 0, 0, TitleFg, TitleBg)
}
func (screen *TaskScreen) drawFooter() {
_, height := termbox.Size()
screen.message.DrawAt(0, height-1)
}
func (screen *TaskScreen) moveCursorDown() bool {
screen.cursor = (screen.cursor + 1) % FieldTaskError
return true
}
func (screen *TaskScreen) moveCursorUp() bool {
if screen.cursor > 0 {
screen.cursor--
} else {
screen.cursor = FieldTaskError - 1
}
return true
}
func (screen *TaskScreen) editCurrentField() {
}