Files
geek-life/app/projects.go
2021-12-09 11:16:31 +06:00

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
}