171 lines
4.6 KiB
Go
171 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"unicode"
|
|
|
|
"github.com/gdamore/tcell/v2"
|
|
"github.com/rivo/tview"
|
|
|
|
"github.com/ajaxray/geek-life/model"
|
|
"github.com/ajaxray/geek-life/repository"
|
|
)
|
|
|
|
// ProjectPane Displays projects and dynamic lists
|
|
type ProjectPane struct {
|
|
*tview.Flex
|
|
projects []model.Project
|
|
list *tview.List
|
|
newProject *tview.InputField
|
|
repo repository.ProjectRepository
|
|
activeProject *model.Project
|
|
projectListStarting int // The index in list where project names starts
|
|
}
|
|
|
|
// NewProjectPane initializes
|
|
func NewProjectPane(repo repository.ProjectRepository) *ProjectPane {
|
|
pane := ProjectPane{
|
|
Flex: tview.NewFlex().SetDirection(tview.FlexRow),
|
|
list: tview.NewList().ShowSecondaryText(false),
|
|
newProject: makeLightTextInput("+[New Project]"),
|
|
repo: repo,
|
|
}
|
|
|
|
pane.newProject.SetDoneFunc(func(key tcell.Key) {
|
|
switch key {
|
|
case tcell.KeyEnter:
|
|
pane.addNewProject()
|
|
case tcell.KeyEsc:
|
|
app.SetFocus(projectPane)
|
|
}
|
|
})
|
|
|
|
pane.AddItem(pane.list, 0, 1, true).
|
|
AddItem(pane.newProject, 1, 0, false)
|
|
|
|
pane.SetBorder(true).SetTitle("[::u]P[::-]rojects")
|
|
pane.loadListItems(false)
|
|
|
|
return &pane
|
|
}
|
|
|
|
func (pane *ProjectPane) addNewProject() {
|
|
name := pane.newProject.GetText()
|
|
if len(name) < 3 {
|
|
statusBar.showForSeconds("[red::]Project name should be at least 3 character", 5)
|
|
return
|
|
}
|
|
|
|
project, err := pane.repo.Create(name, "")
|
|
if err != nil {
|
|
statusBar.showForSeconds("[red::]Failed to create Project:"+err.Error(), 5)
|
|
} else {
|
|
statusBar.showForSeconds(fmt.Sprintf("[yellow::]Project %s created. Press n to start adding new tasks.", name), 10)
|
|
pane.projects = append(pane.projects, project)
|
|
pane.addProjectToList(len(pane.projects)-1, true)
|
|
pane.newProject.SetText("")
|
|
}
|
|
}
|
|
|
|
func (pane *ProjectPane) addDynamicLists() {
|
|
pane.addSection("Dynamic Lists")
|
|
pane.list.AddItem("- Today", "", 0, func() { taskPane.LoadDynamicList("today") })
|
|
pane.list.AddItem("- Tomorrow", "", 0, func() { taskPane.LoadDynamicList("tomorrow") })
|
|
pane.list.AddItem("- Upcoming", "", 0, func() { taskPane.LoadDynamicList("upcoming") })
|
|
pane.list.AddItem("- Unscheduled", "", 0, func() { taskPane.LoadDynamicList("unscheduled") })
|
|
}
|
|
|
|
func (pane *ProjectPane) addProjectList() {
|
|
pane.addSection("Projects")
|
|
pane.projectListStarting = pane.list.GetItemCount()
|
|
|
|
var err error
|
|
pane.projects, err = pane.repo.GetAll()
|
|
if err != nil {
|
|
statusBar.showForSeconds("Could not load Projects: "+err.Error(), 5)
|
|
return
|
|
}
|
|
|
|
for i := range pane.projects {
|
|
pane.addProjectToList(i, false)
|
|
}
|
|
|
|
pane.list.SetCurrentItem(2) // Keep "Today" selected on start
|
|
}
|
|
|
|
func (pane *ProjectPane) addProjectToList(i int, selectItem bool) {
|
|
// To avoid overriding of loop variables - https://www.calhoun.io/gotchas-and-common-mistakes-with-closures-in-go/
|
|
pane.list.AddItem("- "+pane.projects[i].Title, "", 0, func(idx int) func() {
|
|
return func() { pane.activateProject(idx) }
|
|
}(i))
|
|
|
|
if selectItem {
|
|
pane.list.SetCurrentItem(-1)
|
|
pane.activateProject(i)
|
|
}
|
|
}
|
|
|
|
func (pane *ProjectPane) addSection(name string) {
|
|
pane.list.AddItem("[::d]"+name, "", 0, nil)
|
|
pane.list.AddItem("[::d]"+strings.Repeat(string(tcell.RuneHLine), 25), "", 0, nil)
|
|
}
|
|
|
|
func (pane *ProjectPane) handleShortcuts(event *tcell.EventKey) *tcell.EventKey {
|
|
switch unicode.ToLower(event.Rune()) {
|
|
case 'j':
|
|
pane.list.SetCurrentItem(pane.list.GetCurrentItem() + 1)
|
|
return nil
|
|
case 'k':
|
|
pane.list.SetCurrentItem(pane.list.GetCurrentItem() - 1)
|
|
return nil
|
|
case 'n':
|
|
app.SetFocus(pane.newProject)
|
|
return nil
|
|
}
|
|
|
|
return event
|
|
}
|
|
|
|
func (pane *ProjectPane) activateProject(idx int) {
|
|
pane.activeProject = &pane.projects[idx]
|
|
taskPane.LoadProjectTasks(*pane.activeProject)
|
|
|
|
removeThirdCol()
|
|
projectDetailPane.SetProject(pane.activeProject)
|
|
contents.AddItem(projectDetailPane, 25, 0, false)
|
|
app.SetFocus(taskPane)
|
|
}
|
|
|
|
// RemoveActivateProject deletes the currently active project
|
|
func (pane *ProjectPane) RemoveActivateProject() {
|
|
if pane.activeProject != nil && pane.repo.Delete(pane.activeProject) == nil {
|
|
|
|
for i := range taskPane.tasks {
|
|
_ = taskRepo.Delete(&taskPane.tasks[i])
|
|
}
|
|
taskPane.ClearList()
|
|
|
|
statusBar.showForSeconds("[lime]Removed Project: "+pane.activeProject.Title, 5)
|
|
removeThirdCol()
|
|
|
|
pane.loadListItems(true)
|
|
}
|
|
}
|
|
|
|
func (pane *ProjectPane) loadListItems(focus bool) {
|
|
pane.list.Clear()
|
|
pane.addDynamicLists()
|
|
pane.list.AddItem("", "", 0, nil)
|
|
pane.addProjectList()
|
|
|
|
if focus {
|
|
app.SetFocus(pane)
|
|
}
|
|
}
|
|
|
|
// GetActiveProject provides pointer to currently active project
|
|
func (pane *ProjectPane) GetActiveProject() *model.Project {
|
|
return pane.activeProject
|
|
}
|