taskDetailPane modified as a Component (type)

This commit is contained in:
Anis Ahmad
2020-06-12 18:20:40 +06:00
parent 19666900a2
commit 46cc0bfd18
3 changed files with 112 additions and 94 deletions

View File

@@ -13,12 +13,12 @@ import (
var ( var (
app *tview.Application app *tview.Application
projectDetailPane *tview.Flex projectDetailPane *tview.Flex
taskDetailPane *tview.Flex
layout, contents *tview.Flex layout, contents *tview.Flex
statusBar *StatusBar statusBar *StatusBar
projectPane *ProjectPane projectPane *ProjectPane
taskPane *TaskPane taskPane *TaskPane
taskDetailPane *TaskDetailPane
db *storm.DB db *storm.DB
projectRepo repository.ProjectRepository projectRepo repository.ProjectRepository
@@ -43,10 +43,9 @@ func main() {
statusBar = makeStatusBar(app) statusBar = makeStatusBar(app)
projectPane = NewProjectPane(projectRepo) projectPane = NewProjectPane(projectRepo)
// prepareTaskPane()
taskPane = NewTaskPane(projectRepo, taskRepo) taskPane = NewTaskPane(projectRepo, taskRepo)
prepareProjectDetail() prepareProjectDetail()
prepareDetailPane() taskDetailPane = NewTaskDetailPane(taskRepo)
contents = tview.NewFlex(). contents = tview.NewFlex().
AddItem(projectPane, 25, 1, true). AddItem(projectPane, 25, 1, true).
@@ -77,7 +76,7 @@ func setKeyboardShortcuts() *tview.Application {
case taskPane.HasFocus(): case taskPane.HasFocus():
event = taskPane.handleShortcuts(event) event = taskPane.handleShortcuts(event)
case taskDetailPane.HasFocus(): case taskDetailPane.HasFocus():
event = handleDetailPaneShortcuts(event) event = taskDetailPane.handleShortcuts(event)
} }
// Global shortcuts // Global shortcuts

View File

@@ -8,90 +8,103 @@ import (
"github.com/pgavlin/femto" "github.com/pgavlin/femto"
"github.com/pgavlin/femto/runtime" "github.com/pgavlin/femto/runtime"
"github.com/rivo/tview" "github.com/rivo/tview"
"github.com/ajaxray/geek-life/model"
"github.com/ajaxray/geek-life/repository"
) )
var ( type TaskDetailPane struct {
*tview.Flex
taskName, taskDateDisplay *tview.TextView taskName, taskDateDisplay *tview.TextView
editorHint *tview.TextView editorHint *tview.TextView
taskDate *tview.InputField taskDate *tview.InputField
taskDetailView *femto.View
taskStatusToggle *tview.Button taskStatusToggle *tview.Button
colorscheme femto.Colorscheme taskDetailView *femto.View
blankCell = tview.NewTextView() colorScheme femto.Colorscheme
) taskRepo repository.TaskRepository
task *model.Task
}
const dateLayoutISO = "2006-01-02" const dateLayoutISO = "2006-01-02"
const dateLayoutHuman = "02 Jan, Monday" const dateLayoutHuman = "02 Jan, Monday"
func prepareDetailPane() { var blankCell = tview.NewTextView()
taskName = tview.NewTextView().SetDynamicColors(true)
prepareDetailsEditor() func NewTaskDetailPane(taskRepo repository.TaskRepository) *TaskDetailPane {
pane := TaskDetailPane{
Flex: tview.NewFlex().SetDirection(tview.FlexRow),
taskName: tview.NewTextView().SetDynamicColors(true),
taskDateDisplay: tview.NewTextView().SetDynamicColors(true),
taskStatusToggle: makeButton("Complete", nil).SetLabelColor(tcell.ColorLightGray),
taskRepo: taskRepo,
}
taskStatusToggle = makeButton("Complete", toggleActiveTaskStatus).SetLabelColor(tcell.ColorLightGray) pane.prepareDetailsEditor()
toggleHint := tview.NewTextView().SetTextColor(tcell.ColorDimGray).SetText("<space> to toggle") toggleHint := tview.NewTextView().SetTextColor(tcell.ColorDimGray).SetText("<space> to toggle")
pane.taskStatusToggle.SetSelectedFunc(pane.toggleTaskStatus)
pane.editorHint = tview.NewTextView().SetText(" e to edit, ↓↑ to scroll").SetTextColor(tcell.ColorDimGray)
// Prepare static (no external interaction) elements
editorLabel := tview.NewFlex(). editorLabel := tview.NewFlex().
AddItem(tview.NewTextView().SetText("Task Not[::u]e[::-]:").SetDynamicColors(true), 0, 1, false). AddItem(tview.NewTextView().SetText("Task Not[::u]e[::-]:").SetDynamicColors(true), 0, 1, false).
AddItem(makeButton("edit", func() { activateEditor() }), 6, 0, false) AddItem(makeButton("edit", func() { pane.activateEditor() }), 6, 0, false)
editorHint = tview.NewTextView().
SetText(" e to edit, ↓↑ to scroll").
SetTextColor(tcell.ColorDimGray)
editorHelp := tview.NewFlex(). editorHelp := tview.NewFlex().
AddItem(editorHint, 0, 1, false). AddItem(pane.editorHint, 0, 1, false).
AddItem(tview.NewTextView().SetTextAlign(tview.AlignRight). AddItem(tview.NewTextView().SetTextAlign(tview.AlignRight).
SetText("syntax:markdown theme:monakai"). SetText("syntax:markdown theme:monakai").
SetTextColor(tcell.ColorDimGray), 0, 1, false) SetTextColor(tcell.ColorDimGray), 0, 1, false)
taskDetailPane = tview.NewFlex().SetDirection(tview.FlexRow). pane.
AddItem(taskName, 2, 1, true). AddItem(pane.taskName, 2, 1, true).
AddItem(makeHorizontalLine(tcell.RuneS3, tcell.ColorGray), 1, 1, false). AddItem(makeHorizontalLine(tcell.RuneS3, tcell.ColorGray), 1, 1, false).
AddItem(blankCell, 1, 1, false). AddItem(blankCell, 1, 1, false).
AddItem(makeDateRow(), 1, 1, true). AddItem(pane.makeDateRow(), 1, 1, true).
AddItem(blankCell, 1, 1, false). AddItem(blankCell, 1, 1, false).
AddItem(editorLabel, 1, 1, false). AddItem(editorLabel, 1, 1, false).
AddItem(taskDetailView, 15, 4, false). AddItem(pane.taskDetailView, 15, 4, false).
AddItem(editorHelp, 1, 1, false). AddItem(editorHelp, 1, 1, false).
AddItem(blankCell, 0, 1, false). AddItem(blankCell, 0, 1, false).
AddItem(toggleHint, 1, 1, false). AddItem(toggleHint, 1, 1, false).
AddItem(taskStatusToggle, 3, 1, false) AddItem(pane.taskStatusToggle, 3, 1, false)
taskDetailPane.SetBorder(true).SetTitle("Task Detail") pane.SetBorder(true).SetTitle("Task Detail")
return &pane
} }
func makeDateRow() *tview.Flex { func (td *TaskDetailPane) makeDateRow() *tview.Flex {
taskDateDisplay = tview.NewTextView().SetDynamicColors(true)
taskDate = makeLightTextInput("yyyy-mm-dd"). td.taskDate = makeLightTextInput("yyyy-mm-dd").
SetLabel("Set:"). SetLabel("Set:").
SetLabelColor(tcell.ColorGray). SetLabelColor(tcell.ColorGray).
SetFieldWidth(12). SetFieldWidth(12).
SetDoneFunc(func(key tcell.Key) { SetDoneFunc(func(key tcell.Key) {
switch key { switch key {
case tcell.KeyEnter: case tcell.KeyEnter:
setTaskDate(parseDateInputOrCurrent(taskDate.GetText()).Unix(), true) td.setTaskDate(parseDateInputOrCurrent(td.taskDate.GetText()).Unix(), true)
case tcell.KeyEsc: case tcell.KeyEsc:
setTaskDate(taskPane.activeTask.DueDate, false) td.setTaskDate(td.task.DueDate, false)
} }
app.SetFocus(taskDetailPane) app.SetFocus(td)
}) })
todaySelector := func() { todaySelector := func() {
setTaskDate(time.Now().Unix(), true) td.setTaskDate(time.Now().Unix(), true)
} }
nextDaySelector := func() { nextDaySelector := func() {
setTaskDate(parseDateInputOrCurrent(taskDate.GetText()).AddDate(0, 0, 1).Unix(), true) td.setTaskDate(parseDateInputOrCurrent(td.taskDate.GetText()).AddDate(0, 0, 1).Unix(), true)
} }
prevDaySelector := func() { prevDaySelector := func() {
setTaskDate(parseDateInputOrCurrent(taskDate.GetText()).AddDate(0, 0, -1).Unix(), true) td.setTaskDate(parseDateInputOrCurrent(td.taskDate.GetText()).AddDate(0, 0, -1).Unix(), true)
} }
return tview.NewFlex(). return tview.NewFlex().
AddItem(taskDateDisplay, 0, 2, true). AddItem(td.taskDateDisplay, 0, 2, true).
AddItem(taskDate, 14, 0, true). AddItem(td.taskDate, 14, 0, true).
AddItem(blankCell, 1, 0, false). AddItem(blankCell, 1, 0, false).
AddItem(makeButton("today", todaySelector), 8, 1, false). AddItem(makeButton("today", todaySelector), 8, 1, false).
AddItem(blankCell, 1, 0, false). AddItem(blankCell, 1, 0, false).
@@ -100,28 +113,28 @@ func makeDateRow() *tview.Flex {
AddItem(makeButton("-1", prevDaySelector), 4, 1, false) AddItem(makeButton("-1", prevDaySelector), 4, 1, false)
} }
func setStatusToggle() { func (td *TaskDetailPane) updateToggleDisplay() {
if taskPane.activeTask.Completed { if td.task.Completed {
taskStatusToggle.SetLabel("Resume").SetBackgroundColor(tcell.ColorMaroon) td.taskStatusToggle.SetLabel("Resume").SetBackgroundColor(tcell.ColorMaroon)
} else { } else {
taskStatusToggle.SetLabel("Complete").SetBackgroundColor(tcell.ColorDarkGreen) td.taskStatusToggle.SetLabel("Complete").SetBackgroundColor(tcell.ColorDarkGreen)
} }
} }
func toggleActiveTaskStatus() { func (td *TaskDetailPane) toggleTaskStatus() {
status := !taskPane.activeTask.Completed status := !td.task.Completed
if taskRepo.UpdateField(taskPane.activeTask, "Completed", status) == nil { if taskRepo.UpdateField(td.task, "Completed", status) == nil {
taskPane.activeTask.Completed = status td.task.Completed = status
taskPane.ActivateTask(taskPane.list.GetCurrentItem()) td.SetTask(td.task)
taskPane.list.SetItemText(taskPane.list.GetCurrentItem(), makeTaskListingTitle(*taskPane.activeTask), "") taskPane.list.SetItemText(taskPane.list.GetCurrentItem(), makeTaskListingTitle(*td.task), "")
} }
} }
// Display Task date in detail pane, and update date if asked to // Display Task date in detail pane, and update date if asked to
func setTaskDate(unixDate int64, update bool) { func (td *TaskDetailPane) setTaskDate(unixDate int64, update bool) {
if update { if update {
taskPane.activeTask.DueDate = unixDate td.task.DueDate = unixDate
if err := taskRepo.UpdateField(taskPane.activeTask, "DueDate", unixDate); err != nil { if err := td.taskRepo.UpdateField(td.task, "DueDate", unixDate); err != nil {
statusBar.showForSeconds("Could not update due date: "+err.Error(), 5) statusBar.showForSeconds("Could not update due date: "+err.Error(), 5)
return return
} }
@@ -135,40 +148,42 @@ func setTaskDate(unixDate int64, update bool) {
if due.Before(time.Now()) { if due.Before(time.Now()) {
color = "red" color = "red"
} }
taskDateDisplay.SetText(fmt.Sprintf("[::u]D[::-]ue: [%s]%s", color, humanDate)) td.taskDateDisplay.SetText(fmt.Sprintf("[::u]D[::-]ue: [%s]%s", color, humanDate))
taskDate.SetText(due.Format(dateLayoutISO)) td.taskDate.SetText(due.Format(dateLayoutISO))
} else { } else {
taskDate.SetText("") td.taskDate.SetText("")
taskDateDisplay.SetText("[::u]D[::-]ue: [::d]Not Set") td.taskDateDisplay.SetText("[::u]D[::-]ue: [::d]Not Set")
} }
} }
func prepareDetailsEditor() { func (td *TaskDetailPane) prepareDetailsEditor() {
taskDetailView = femto.NewView(makeBufferFromString(""))
taskDetailView.SetRuntimeFiles(runtime.Files)
// var colorscheme femto.Colorscheme td.taskDetailView = femto.NewView(makeBufferFromString(""))
td.taskDetailView.SetRuntimeFiles(runtime.Files)
// var colorScheme femto.Colorscheme
if monokai := runtime.Files.FindFile(femto.RTColorscheme, "monokai"); monokai != nil { if monokai := runtime.Files.FindFile(femto.RTColorscheme, "monokai"); monokai != nil {
if data, err := monokai.Data(); err == nil { if data, err := monokai.Data(); err == nil {
colorscheme = femto.ParseColorscheme(string(data)) td.colorScheme = femto.ParseColorscheme(string(data))
} }
} }
taskDetailView.SetColorscheme(colorscheme)
taskDetailView.SetBorder(true)
taskDetailView.SetBorderColor(tcell.ColorLightSlateGray)
taskDetailView.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey { td.taskDetailView.SetColorscheme(td.colorScheme)
td.taskDetailView.SetBorder(true)
td.taskDetailView.SetBorderColor(tcell.ColorLightSlateGray)
td.taskDetailView.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() { switch event.Key() {
case tcell.KeyEsc: case tcell.KeyEsc:
taskPane.activeTask.Details = taskDetailView.Buf.String() td.task.Details = td.taskDetailView.Buf.String()
err := taskRepo.Update(taskPane.activeTask) err := taskRepo.Update(td.task)
if err == nil { if err == nil {
statusBar.showForSeconds("[lime]Saved task detail", 5) statusBar.showForSeconds("[lime]Saved task detail", 5)
} else { } else {
statusBar.showForSeconds("[red]Could not save: "+err.Error(), 5) statusBar.showForSeconds("[red]Could not save: "+err.Error(), 5)
} }
deactivateEditor() td.deactivateEditor()
return nil return nil
} }
@@ -188,38 +203,50 @@ func makeBufferFromString(content string) *femto.Buffer {
return buff return buff
} }
func activateEditor() { func (td *TaskDetailPane) activateEditor() {
taskDetailView.Readonly = false td.taskDetailView.Readonly = false
taskDetailView.SetBorderColor(tcell.ColorDarkOrange) td.taskDetailView.SetBorderColor(tcell.ColorDarkOrange)
editorHint.SetText(" Esc to save changes") td.editorHint.SetText(" Esc to save changes")
app.SetFocus(taskDetailView) app.SetFocus(td.taskDetailView)
} }
func deactivateEditor() { func (td *TaskDetailPane) deactivateEditor() {
taskDetailView.Readonly = true td.taskDetailView.Readonly = true
taskDetailView.SetBorderColor(tcell.ColorLightSlateGray) td.taskDetailView.SetBorderColor(tcell.ColorLightSlateGray)
editorHint.SetText(" e to edit, ↓↑ to scroll") td.editorHint.SetText(" e to edit, ↓↑ to scroll")
app.SetFocus(taskDetailPane) app.SetFocus(td)
} }
func handleDetailPaneShortcuts(event *tcell.EventKey) *tcell.EventKey { func (td *TaskDetailPane) handleShortcuts(event *tcell.EventKey) *tcell.EventKey {
switch event.Key() { switch event.Key() {
case tcell.KeyEsc: case tcell.KeyEsc:
app.SetFocus(taskPane) app.SetFocus(taskPane)
case tcell.KeyDown: case tcell.KeyDown:
taskDetailView.ScrollDown(1) td.taskDetailView.ScrollDown(1)
case tcell.KeyUp: case tcell.KeyUp:
taskDetailView.ScrollUp(1) td.taskDetailView.ScrollUp(1)
case tcell.KeyRune: case tcell.KeyRune:
switch event.Rune() { switch event.Rune() {
case 'e': case 'e':
activateEditor() td.activateEditor()
case 'd': case 'd':
app.SetFocus(taskDate) app.SetFocus(td.taskDate)
case ' ': case ' ':
toggleActiveTaskStatus() td.toggleTaskStatus()
} }
} }
return event return event
} }
func (td *TaskDetailPane) SetTask(task *model.Task) {
td.task = task
td.taskName.SetText(fmt.Sprintf("[%s::b]# %s", getTaskTitleColor(*td.task), td.task.Title))
td.taskDetailView.Buf = makeBufferFromString(td.task.Details)
td.taskDetailView.SetColorscheme(td.colorScheme)
td.taskDetailView.Start()
td.setTaskDate(td.task.DueDate, false)
td.updateToggleDisplay()
td.deactivateEditor()
}

View File

@@ -1,8 +1,6 @@
package main package main
import ( import (
"fmt"
"github.com/asdine/storm/v3" "github.com/asdine/storm/v3"
"github.com/gdamore/tcell" "github.com/gdamore/tcell"
"github.com/rivo/tview" "github.com/rivo/tview"
@@ -110,14 +108,8 @@ func (pane *TaskPane) LoadProjectTasks(project model.Project) {
func (pane *TaskPane) ActivateTask(idx int) { func (pane *TaskPane) ActivateTask(idx int) {
removeThirdCol() removeThirdCol()
pane.activeTask = &pane.tasks[idx] pane.activeTask = &pane.tasks[idx]
taskDetailPane.SetTask(pane.activeTask)
taskName.SetText(fmt.Sprintf("[%s::b]# %s", getTaskTitleColor(*pane.activeTask), pane.activeTask.Title))
taskDetailView.Buf = makeBufferFromString(pane.activeTask.Details)
taskDetailView.SetColorscheme(colorscheme)
taskDetailView.Start()
setTaskDate(pane.activeTask.DueDate, false)
setStatusToggle()
contents.AddItem(taskDetailPane, 0, 3, false) contents.AddItem(taskDetailPane, 0, 3, false)
deactivateEditor()
} }