Creating Projects, Tasks and editing Task details, done/resume working.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -13,3 +13,5 @@
|
|||||||
|
|
||||||
# Dependency directories (remove the comment below to include it)
|
# Dependency directories (remove the comment below to include it)
|
||||||
# vendor/
|
# vendor/
|
||||||
|
/geek-life
|
||||||
|
/geek-life.db
|
||||||
|
|||||||
121
app/cli.go
Normal file
121
app/cli.go
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/asdine/storm/v3"
|
||||||
|
"github.com/gdamore/tcell"
|
||||||
|
"github.com/rivo/tview"
|
||||||
|
|
||||||
|
"github.com/ajaxray/geek-life/model"
|
||||||
|
"github.com/ajaxray/geek-life/repository"
|
||||||
|
repo "github.com/ajaxray/geek-life/repository/storm"
|
||||||
|
"github.com/ajaxray/geek-life/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
app *tview.Application
|
||||||
|
newProject, newTask *tview.InputField
|
||||||
|
projectList, taskList *tview.List
|
||||||
|
projectPane, taskPane, detailPane *tview.Flex
|
||||||
|
layout, contents *tview.Flex
|
||||||
|
statusBar *tview.Pages
|
||||||
|
message *tview.TextView
|
||||||
|
shortcutsPage, messagePage string = "shortcuts", "message"
|
||||||
|
|
||||||
|
db *storm.DB
|
||||||
|
projectRepo repository.ProjectRepository
|
||||||
|
taskRepo repository.TaskRepository
|
||||||
|
|
||||||
|
projects []model.Project
|
||||||
|
currentProject model.Project
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
app = tview.NewApplication()
|
||||||
|
|
||||||
|
db = util.ConnectStorm()
|
||||||
|
defer db.Close()
|
||||||
|
|
||||||
|
projectRepo = repo.NewProjectRepository(db)
|
||||||
|
taskRepo = repo.NewTaskRepository(db)
|
||||||
|
|
||||||
|
titleText := tview.NewTextView().SetText("[lime::b]Geek-life [::-]- life management for geeks!").SetDynamicColors(true)
|
||||||
|
cloudStatus := tview.NewTextView().SetText("[::d]Cloud Sync: off").SetTextAlign(tview.AlignRight).SetDynamicColors(true)
|
||||||
|
|
||||||
|
titleBar := tview.NewFlex().
|
||||||
|
AddItem(titleText, 0, 2, false).
|
||||||
|
AddItem(cloudStatus, 0, 1, false)
|
||||||
|
|
||||||
|
prepareProjectPane()
|
||||||
|
prepareTaskPane()
|
||||||
|
prepareStatusBar()
|
||||||
|
prepareDetailPane()
|
||||||
|
|
||||||
|
contents = tview.NewFlex().
|
||||||
|
AddItem(projectPane, 25, 1, true).
|
||||||
|
AddItem(taskPane, 0, 2, false)
|
||||||
|
//AddItem(detailPane, 0, 3, true)
|
||||||
|
|
||||||
|
layout = tview.NewFlex().SetDirection(tview.FlexRow).
|
||||||
|
AddItem(titleBar, 2, 1, false).
|
||||||
|
AddItem(contents, 0, 2, true).
|
||||||
|
AddItem(statusBar, 1, 1, false)
|
||||||
|
|
||||||
|
setKeyboardShortcuts(projectPane, taskPane)
|
||||||
|
|
||||||
|
if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setKeyboardShortcuts(projectPane *tview.Flex, taskPane *tview.Flex) *tview.Application {
|
||||||
|
return app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
if ignoreKeyEvt() {
|
||||||
|
return event
|
||||||
|
}
|
||||||
|
switch event.Rune() {
|
||||||
|
case 'p':
|
||||||
|
app.SetFocus(projectPane)
|
||||||
|
case 't':
|
||||||
|
app.SetFocus(taskPane)
|
||||||
|
case 'n':
|
||||||
|
if projectPane.HasFocus() {
|
||||||
|
app.SetFocus(newProject)
|
||||||
|
} else if taskPane.HasFocus() {
|
||||||
|
app.SetFocus(newTask)
|
||||||
|
}
|
||||||
|
case 'e':
|
||||||
|
if detailPane.HasFocus() {
|
||||||
|
activateEditor()
|
||||||
|
} else {
|
||||||
|
// @TODO : Remove
|
||||||
|
showMessage(reflect.TypeOf(app.GetFocus()).String())
|
||||||
|
}
|
||||||
|
case 'f':
|
||||||
|
// @TODO : Remove
|
||||||
|
showMessage(reflect.TypeOf(app.GetFocus()).String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return event
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareStatusBar() {
|
||||||
|
statusBar = tview.NewPages()
|
||||||
|
|
||||||
|
message = tview.NewTextView().SetDynamicColors(true).SetText("Loading...")
|
||||||
|
statusBar.AddPage(messagePage, message, true, true)
|
||||||
|
|
||||||
|
statusBar.AddPage(shortcutsPage,
|
||||||
|
tview.NewGrid().
|
||||||
|
SetColumns(0, 0, 0, 0).
|
||||||
|
SetRows(0).
|
||||||
|
AddItem(tview.NewTextView().SetText("Shortcuts: Alt+.(dot)"), 0, 0, 1, 1, 0, 0, false).
|
||||||
|
AddItem(tview.NewTextView().SetText("New Project: n").SetTextAlign(tview.AlignCenter), 0, 1, 1, 1, 0, 0, false).
|
||||||
|
AddItem(tview.NewTextView().SetText("New Task: t").SetTextAlign(tview.AlignCenter), 0, 2, 1, 1, 0, 0, false).
|
||||||
|
AddItem(tview.NewTextView().SetText("Quit: Ctrl+C").SetTextAlign(tview.AlignRight), 0, 3, 1, 1, 0, 0, false),
|
||||||
|
true,
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
}
|
||||||
78
app/projects.go
Normal file
78
app/projects.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/asdine/storm/v3"
|
||||||
|
"github.com/gdamore/tcell"
|
||||||
|
"github.com/rivo/tview"
|
||||||
|
)
|
||||||
|
|
||||||
|
func prepareProjectPane() {
|
||||||
|
var err error
|
||||||
|
projects, err = projectRepo.GetAll()
|
||||||
|
if err != nil {
|
||||||
|
showMessage("Could not load Projects: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
projectList = tview.NewList().ShowSecondaryText(false)
|
||||||
|
|
||||||
|
for i := range projects {
|
||||||
|
addProjectToList(i, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
newProject = makeLightTextInput("+[New Project]").
|
||||||
|
SetDoneFunc(func(key tcell.Key) {
|
||||||
|
switch key {
|
||||||
|
case tcell.KeyEnter:
|
||||||
|
project, err := projectRepo.Create(newProject.GetText(), "")
|
||||||
|
if err != nil {
|
||||||
|
showMessage("[red::]Failed to create Project:" + err.Error())
|
||||||
|
} else {
|
||||||
|
showMessage(fmt.Sprintf("[green::]Project %s created. Press n to start adding new tasks.", newProject.GetText()))
|
||||||
|
projects = append(projects, project)
|
||||||
|
addProjectToList(len(projects)-1, true)
|
||||||
|
newProject.SetText("")
|
||||||
|
}
|
||||||
|
case tcell.KeyEsc:
|
||||||
|
app.SetFocus(projectPane)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
projectPane = tview.NewFlex().SetDirection(tview.FlexRow).
|
||||||
|
AddItem(projectList, 0, 1, true).
|
||||||
|
AddItem(newProject, 1, 0, false)
|
||||||
|
|
||||||
|
projectPane.SetBorder(true).SetTitle("[::u]P[::-]rojects")
|
||||||
|
}
|
||||||
|
|
||||||
|
func addProjectToList(i int, selectItem bool) {
|
||||||
|
// To avoid overriding of loop variables - https://www.calhoun.io/gotchas-and-common-mistakes-with-closures-in-go/
|
||||||
|
projectList.AddItem("- "+projects[i].Title, "", 0, func(idx int) func() {
|
||||||
|
return func() { loadProject(idx) }
|
||||||
|
}(i))
|
||||||
|
|
||||||
|
if selectItem {
|
||||||
|
projectList.SetCurrentItem(i)
|
||||||
|
loadProject(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadProject(idx int) {
|
||||||
|
currentProject = projects[idx]
|
||||||
|
taskList.Clear()
|
||||||
|
app.SetFocus(taskPane)
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if tasks, err = taskRepo.GetAllByProject(currentProject); err != nil && err != storm.ErrNotFound {
|
||||||
|
showMessage("[red::]Error: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, task := range tasks {
|
||||||
|
taskList.AddItem(makeTaskListingTitle(task), "", 0, func(taskidx int) func() {
|
||||||
|
return func() { loadTask(taskidx) }
|
||||||
|
}(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
contents.RemoveItem(detailPane)
|
||||||
|
}
|
||||||
183
app/task_detail.go
Normal file
183
app/task_detail.go
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell"
|
||||||
|
"github.com/pgavlin/femto"
|
||||||
|
"github.com/pgavlin/femto/runtime"
|
||||||
|
"github.com/rivo/tview"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
taskName *tview.TextView
|
||||||
|
taskDate *tview.InputField
|
||||||
|
taskDetailView *femto.View
|
||||||
|
taskStatusToggle *tview.Button
|
||||||
|
colorscheme femto.Colorscheme
|
||||||
|
)
|
||||||
|
|
||||||
|
const dateLayoutISO = "2006-01-02"
|
||||||
|
|
||||||
|
func prepareDetailPane() {
|
||||||
|
taskName = tview.NewTextView().SetDynamicColors(true)
|
||||||
|
hr := makeHorizontalLine(tview.BoxDrawingsLightHorizontal)
|
||||||
|
|
||||||
|
prepareDetailsEditor()
|
||||||
|
|
||||||
|
taskStatusToggle = makeButton("Complete", func() {}).SetLabelColor(tcell.ColorLightGray)
|
||||||
|
|
||||||
|
hint := tview.NewTextView().SetTextColor(tcell.ColorYellow).
|
||||||
|
SetText("press Enter to save changes, Esc to ignore")
|
||||||
|
|
||||||
|
detailPane = tview.NewFlex().SetDirection(tview.FlexRow).
|
||||||
|
AddItem(taskName, 2, 1, true).
|
||||||
|
AddItem(hr, 1, 1, false).
|
||||||
|
AddItem(nil, 1, 1, false).
|
||||||
|
AddItem(makeDateRow(), 1, 1, true).
|
||||||
|
AddItem(taskDetailView, 15, 4, false).
|
||||||
|
AddItem(tview.NewTextView(), 1, 1, false).
|
||||||
|
AddItem(hint, 1, 1, false).
|
||||||
|
AddItem(nil, 0, 1, false).
|
||||||
|
AddItem(taskStatusToggle, 3, 1, false)
|
||||||
|
|
||||||
|
detailPane.SetBorder(true).SetTitle("Detail")
|
||||||
|
|
||||||
|
// taskName is the default focus attracting child of detailPane
|
||||||
|
taskName.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
|
||||||
|
switch event.Key() {
|
||||||
|
case tcell.KeyEsc:
|
||||||
|
app.SetFocus(taskPane)
|
||||||
|
case tcell.KeyDown:
|
||||||
|
taskDetailView.ScrollDown(1)
|
||||||
|
case tcell.KeyUp:
|
||||||
|
taskDetailView.ScrollUp(1)
|
||||||
|
case tcell.KeyRune:
|
||||||
|
// switch event.Rune() {
|
||||||
|
// case 'n':
|
||||||
|
// app.SetFocus(projectPane)
|
||||||
|
// case 'e':
|
||||||
|
// if detailPane.HasFocus() {
|
||||||
|
// activateEditor()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
return event
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeDateRow() *tview.Flex {
|
||||||
|
taskDate = makeLightTextInput("yyyy-mm-dd").
|
||||||
|
SetLabel("Due Date: ").
|
||||||
|
SetLabelColor(tcell.ColorGray).
|
||||||
|
SetFieldWidth(12)
|
||||||
|
|
||||||
|
todaySelector := func() {
|
||||||
|
taskDate.SetText(time.Now().Format(dateLayoutISO))
|
||||||
|
}
|
||||||
|
|
||||||
|
nextDaySelector := func() {
|
||||||
|
currentText := taskDate.GetText()
|
||||||
|
if date, err := time.Parse(dateLayoutISO, currentText); err == nil {
|
||||||
|
taskDate.SetText(date.AddDate(0, 0, 1).Format(dateLayoutISO))
|
||||||
|
} else {
|
||||||
|
taskDate.SetText(time.Now().AddDate(0, 0, 1).Format(dateLayoutISO))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prevDaySelector := func() {
|
||||||
|
currentText := taskDate.GetText()
|
||||||
|
if date, err := time.Parse(dateLayoutISO, currentText); err == nil {
|
||||||
|
taskDate.SetText(date.AddDate(0, 0, -1).Format(dateLayoutISO))
|
||||||
|
} else {
|
||||||
|
taskDate.SetText(time.Now().AddDate(0, 0, -1).Format(dateLayoutISO))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tview.NewFlex().
|
||||||
|
AddItem(taskDate, 25, 2, true).
|
||||||
|
AddItem(nil, 1, 0, false).
|
||||||
|
AddItem(makeButton("today", todaySelector), 8, 1, false).
|
||||||
|
AddItem(nil, 1, 0, false).
|
||||||
|
AddItem(makeButton("+1", nextDaySelector), 4, 1, false).
|
||||||
|
AddItem(nil, 1, 0, false).
|
||||||
|
AddItem(makeButton("-1", prevDaySelector), 4, 1, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setStatusToggle(idx int) {
|
||||||
|
action := func(i int, label string, color tcell.Color, status bool) {
|
||||||
|
taskStatusToggle.SetLabel(label).SetBackgroundColor(color)
|
||||||
|
taskStatusToggle.SetSelectedFunc(func() {
|
||||||
|
if taskRepo.UpdateField(currentTask, "Completed", status) == nil {
|
||||||
|
currentTask.Completed = status
|
||||||
|
loadTask(i)
|
||||||
|
taskList.SetItemText(i, makeTaskListingTitle(*currentTask), "")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if currentTask.Completed {
|
||||||
|
action(idx, "Resume", tcell.ColorMaroon, false)
|
||||||
|
} else {
|
||||||
|
action(idx, "Complete", tcell.ColorDarkGreen, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepareDetailsEditor() {
|
||||||
|
taskDetailView = femto.NewView(makeBufferFromString(""))
|
||||||
|
taskDetailView.SetRuntimeFiles(runtime.Files)
|
||||||
|
|
||||||
|
// var colorscheme femto.Colorscheme
|
||||||
|
if monokai := runtime.Files.FindFile(femto.RTColorscheme, "monokai"); monokai != nil {
|
||||||
|
if data, err := monokai.Data(); err == nil {
|
||||||
|
colorscheme = femto.ParseColorscheme(string(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taskDetailView.SetColorscheme(colorscheme)
|
||||||
|
taskDetailView.SetBorder(true)
|
||||||
|
taskDetailView.SetBorderColor(tcell.ColorLightSlateGray)
|
||||||
|
|
||||||
|
taskDetailView.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
||||||
|
switch event.Key() {
|
||||||
|
case tcell.KeyEsc:
|
||||||
|
currentTask.Details = taskDetailView.Buf.String()
|
||||||
|
err := taskRepo.Update(currentTask)
|
||||||
|
if err == nil {
|
||||||
|
showMessage("[lime]Saved task detail")
|
||||||
|
} else {
|
||||||
|
showMessage("[red]Could not save: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
deactivateEditor()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return event
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeBufferFromString(content string) *femto.Buffer {
|
||||||
|
buff := femto.NewBufferFromString(content, "")
|
||||||
|
// taskDetail.Settings["ruler"] = false
|
||||||
|
buff.Settings["filetype"] = "markdown"
|
||||||
|
buff.Settings["keepautoindent"] = true
|
||||||
|
buff.Settings["statusline"] = false
|
||||||
|
buff.Settings["softwrap"] = true
|
||||||
|
buff.Settings["scrollbar"] = true
|
||||||
|
|
||||||
|
return buff
|
||||||
|
}
|
||||||
|
|
||||||
|
func activateEditor() {
|
||||||
|
taskDetailView.Readonly = false
|
||||||
|
taskDetailView.SetBorderColor(tcell.ColorDarkOrange)
|
||||||
|
app.SetFocus(taskDetailView)
|
||||||
|
}
|
||||||
|
|
||||||
|
func deactivateEditor() {
|
||||||
|
taskDetailView.Readonly = true
|
||||||
|
taskDetailView.SetBorderColor(tcell.ColorLightSlateGray)
|
||||||
|
app.SetFocus(detailPane)
|
||||||
|
}
|
||||||
84
app/tasks.go
Normal file
84
app/tasks.go
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell"
|
||||||
|
"github.com/rivo/tview"
|
||||||
|
|
||||||
|
"github.com/ajaxray/geek-life/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
tasks []model.Task
|
||||||
|
currentTask *model.Task
|
||||||
|
)
|
||||||
|
|
||||||
|
func prepareTaskPane() {
|
||||||
|
taskList = tview.NewList().ShowSecondaryText(false)
|
||||||
|
taskList.SetDoneFunc(func() {
|
||||||
|
app.SetFocus(projectPane)
|
||||||
|
})
|
||||||
|
|
||||||
|
newTask = makeLightTextInput("+[New Task]").
|
||||||
|
SetDoneFunc(func(key tcell.Key) {
|
||||||
|
switch key {
|
||||||
|
case tcell.KeyEnter:
|
||||||
|
task, err := taskRepo.Create(currentProject, newTask.GetText(), "", "", time.Now().Unix())
|
||||||
|
if err != nil {
|
||||||
|
showMessage("[red::]Could not create Task:" + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
taskList.AddItem(task.Title, "", 0, nil)
|
||||||
|
newTask.SetText("")
|
||||||
|
case tcell.KeyEsc:
|
||||||
|
app.SetFocus(taskPane)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
taskPane = tview.NewFlex().SetDirection(tview.FlexRow).
|
||||||
|
AddItem(taskList, 0, 1, true).
|
||||||
|
AddItem(newTask, 1, 0, false)
|
||||||
|
|
||||||
|
taskPane.SetBorder(true).SetTitle("[::u]T[::-]asks")
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadTask(idx int) {
|
||||||
|
contents.RemoveItem(detailPane)
|
||||||
|
currentTask = &tasks[idx]
|
||||||
|
|
||||||
|
taskName.SetText(fmt.Sprintf("[%s::b]# %s", getTaskTitleColor(*currentTask), currentTask.Title))
|
||||||
|
taskDetailView.Buf = makeBufferFromString(currentTask.Details)
|
||||||
|
taskDetailView.SetColorscheme(colorscheme)
|
||||||
|
taskDetailView.Start()
|
||||||
|
|
||||||
|
taskDate.SetText("")
|
||||||
|
if currentTask.DueDate != 0 {
|
||||||
|
taskDate.SetText(time.Unix(currentTask.DueDate, 0).Format(dateLayoutISO))
|
||||||
|
}
|
||||||
|
|
||||||
|
contents.AddItem(detailPane, 0, 3, false)
|
||||||
|
setStatusToggle(idx)
|
||||||
|
deactivateEditor()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTaskTitleColor(task model.Task) string {
|
||||||
|
colorName := "whitesmoke"
|
||||||
|
if task.Completed {
|
||||||
|
colorName = "lime"
|
||||||
|
} else if task.DueDate != 0 && task.DueDate < time.Now().Unix() {
|
||||||
|
colorName = "red"
|
||||||
|
}
|
||||||
|
|
||||||
|
return colorName
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeTaskListingTitle(task model.Task) string {
|
||||||
|
checkbox := "[ []"
|
||||||
|
if task.Completed {
|
||||||
|
checkbox = "[x[]"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("[%s]%s %s", getTaskTitleColor(task), checkbox, task.Title)
|
||||||
|
}
|
||||||
243
app/tui.go
243
app/tui.go
@@ -1,243 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/asdine/storm/v3"
|
|
||||||
"github.com/gdamore/tcell"
|
|
||||||
"github.com/rivo/tview"
|
|
||||||
|
|
||||||
"github.com/ajaxray/geek-life/model"
|
|
||||||
"github.com/ajaxray/geek-life/repository"
|
|
||||||
repo "github.com/ajaxray/geek-life/repository/storm"
|
|
||||||
"github.com/ajaxray/geek-life/util"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
app *tview.Application
|
|
||||||
newProject, newTask *tview.InputField
|
|
||||||
projectList, taskList *tview.List
|
|
||||||
projectPane, taskPane *tview.Flex
|
|
||||||
statusBar *tview.Pages
|
|
||||||
message *tview.TextView
|
|
||||||
shortcutsPage, messagePage string = "shortcuts", "message"
|
|
||||||
|
|
||||||
db *storm.DB
|
|
||||||
projectRepo repository.ProjectRepository
|
|
||||||
taskRepo repository.TaskRepository
|
|
||||||
|
|
||||||
projects []model.Project
|
|
||||||
currentProject model.Project
|
|
||||||
|
|
||||||
tasks []model.Task
|
|
||||||
currentTask model.Task
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
app = tview.NewApplication()
|
|
||||||
|
|
||||||
db = util.ConnectStorm()
|
|
||||||
defer db.Close()
|
|
||||||
|
|
||||||
projectRepo = repo.NewProjectRepository(db)
|
|
||||||
taskRepo = repo.NewTaskRepository(db)
|
|
||||||
|
|
||||||
titleText := tview.NewTextView().SetText("[lime::b]Geek-life [::-]- life management for geeks!").SetDynamicColors(true)
|
|
||||||
cloudStatus := tview.NewTextView().SetText("[::d]Cloud Sync: off").SetTextAlign(tview.AlignRight).SetDynamicColors(true)
|
|
||||||
|
|
||||||
prepareStatusBar()
|
|
||||||
|
|
||||||
titleBar := tview.NewFlex().
|
|
||||||
AddItem(titleText, 0, 2, false).
|
|
||||||
AddItem(cloudStatus, 0, 1, false)
|
|
||||||
|
|
||||||
projectPane = makeProjectPane()
|
|
||||||
taskPane = makeTaskPane()
|
|
||||||
|
|
||||||
layout := tview.NewFlex().SetDirection(tview.FlexRow).
|
|
||||||
AddItem(titleBar, 2, 1, false).
|
|
||||||
AddItem(tview.NewFlex().
|
|
||||||
AddItem(projectPane, 25, 1, true).
|
|
||||||
AddItem(taskPane, 0, 2, false).
|
|
||||||
AddItem(tview.NewBox().SetBorder(true).SetTitle("Details"), 0, 3, false),
|
|
||||||
0, 2, true).
|
|
||||||
AddItem(statusBar, 1, 1, false)
|
|
||||||
|
|
||||||
setKeyboardShortcuts(projectPane, taskPane)
|
|
||||||
|
|
||||||
if err := app.SetRoot(layout, true).EnableMouse(true).Run(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeProjectPane() *tview.Flex {
|
|
||||||
var err error
|
|
||||||
projects, err = projectRepo.GetAll()
|
|
||||||
util.FatalIfError(err, "Could not load Projects")
|
|
||||||
|
|
||||||
projectList = tview.NewList()
|
|
||||||
|
|
||||||
for i := range projects {
|
|
||||||
addProjectToList(i, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
newProject = makeLightTextInput("+[New Project]").
|
|
||||||
SetDoneFunc(func(key tcell.Key) {
|
|
||||||
switch key {
|
|
||||||
case tcell.KeyEnter:
|
|
||||||
project, err := projectRepo.Create(newProject.GetText(), "")
|
|
||||||
if err != nil {
|
|
||||||
showMessage("[red::]Failed to create Project:" + err.Error())
|
|
||||||
} else {
|
|
||||||
showMessage(fmt.Sprintf("[green::]Project %s created. Press n to start adding new tasks.", newProject.GetText()))
|
|
||||||
projects = append(projects, project)
|
|
||||||
addProjectToList(len(projects)-1, true)
|
|
||||||
newProject.SetText("")
|
|
||||||
}
|
|
||||||
case tcell.KeyEsc:
|
|
||||||
app.SetFocus(projectPane)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
projectBar := tview.NewFlex().SetDirection(tview.FlexRow).
|
|
||||||
AddItem(projectList, 0, 1, true).
|
|
||||||
AddItem(newProject, 1, 0, false)
|
|
||||||
|
|
||||||
projectBar.SetBorder(true).SetTitle("Projects (p)")
|
|
||||||
|
|
||||||
return projectBar
|
|
||||||
}
|
|
||||||
|
|
||||||
func addProjectToList(i int, selectItem bool) {
|
|
||||||
// To avoid overriding of loop variables - https://www.calhoun.io/gotchas-and-common-mistakes-with-closures-in-go/
|
|
||||||
projectList.AddItem(projects[i].Title, "", 0, func(idx int) func() {
|
|
||||||
return func() { loadProject(idx) }
|
|
||||||
}(i))
|
|
||||||
|
|
||||||
if selectItem {
|
|
||||||
projectList.SetCurrentItem(i)
|
|
||||||
loadProject(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeTaskPane() *tview.Flex {
|
|
||||||
taskList = tview.NewList().ShowSecondaryText(false)
|
|
||||||
taskList.SetDoneFunc(func() {
|
|
||||||
app.SetFocus(projectPane)
|
|
||||||
})
|
|
||||||
|
|
||||||
newTask = makeLightTextInput("+[New Task]").
|
|
||||||
SetDoneFunc(func(key tcell.Key) {
|
|
||||||
switch key {
|
|
||||||
case tcell.KeyEnter:
|
|
||||||
task, err := taskRepo.Create(currentProject, newTask.GetText(), "", "", time.Now().Unix())
|
|
||||||
if err != nil {
|
|
||||||
showMessage("[red::]Could not create Task:" + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
taskList.AddItem(task.Title, "", 0, nil)
|
|
||||||
newTask.SetText("")
|
|
||||||
case tcell.KeyEsc:
|
|
||||||
app.SetFocus(taskPane)
|
|
||||||
}
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
taskPane := tview.NewFlex().SetDirection(tview.FlexRow).
|
|
||||||
AddItem(taskList, 0, 1, true).
|
|
||||||
AddItem(newTask, 1, 0, false)
|
|
||||||
|
|
||||||
taskPane.SetBorder(true).SetTitle("Tasks (t)")
|
|
||||||
|
|
||||||
return taskPane
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadProject(idx int) {
|
|
||||||
currentProject = projects[idx]
|
|
||||||
taskList.Clear()
|
|
||||||
app.SetFocus(taskPane)
|
|
||||||
var err error
|
|
||||||
|
|
||||||
if tasks, err = taskRepo.GetAllByProject(currentProject); err != nil && err != storm.ErrNotFound {
|
|
||||||
showMessage("[red::]Error: " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
for i, task := range tasks {
|
|
||||||
taskList.AddItem(task.Title, "", 0, func(taskidx int) func() {
|
|
||||||
return func() { loadTask(taskidx) }
|
|
||||||
}(i))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadTask(idx int) {
|
|
||||||
currentTask = tasks[idx]
|
|
||||||
// taskList.Clear()
|
|
||||||
// app.SetFocus(taskPane)
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeLightTextInput(placeholder string) *tview.InputField {
|
|
||||||
return tview.NewInputField().
|
|
||||||
SetPlaceholder(placeholder).
|
|
||||||
SetPlaceholderTextColor(tcell.ColorLightSlateGray).
|
|
||||||
SetFieldTextColor(tcell.ColorBlack).
|
|
||||||
SetFieldBackgroundColor(tcell.ColorGray)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ignoreKeyEvt() bool {
|
|
||||||
return reflect.TypeOf(app.GetFocus()).String() == "*tview.InputField"
|
|
||||||
}
|
|
||||||
|
|
||||||
func setKeyboardShortcuts(projectPane *tview.Flex, taskPane *tview.Flex) *tview.Application {
|
|
||||||
return app.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
|
|
||||||
if ignoreKeyEvt() {
|
|
||||||
return event
|
|
||||||
}
|
|
||||||
switch event.Rune() {
|
|
||||||
case 'p':
|
|
||||||
app.SetFocus(projectPane)
|
|
||||||
case 't':
|
|
||||||
app.SetFocus(taskPane)
|
|
||||||
case 'n':
|
|
||||||
if projectPane.HasFocus() {
|
|
||||||
app.SetFocus(newProject)
|
|
||||||
} else if taskPane.HasFocus() {
|
|
||||||
app.SetFocus(newTask)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return event
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func showMessage(text string) {
|
|
||||||
message.SetText(text)
|
|
||||||
statusBar.SwitchToPage(messagePage)
|
|
||||||
|
|
||||||
go func() {
|
|
||||||
app.QueueUpdateDraw(func() {
|
|
||||||
time.Sleep(time.Second * 5)
|
|
||||||
statusBar.SwitchToPage(shortcutsPage)
|
|
||||||
})
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func prepareStatusBar() {
|
|
||||||
statusBar = tview.NewPages()
|
|
||||||
|
|
||||||
message = tview.NewTextView().SetDynamicColors(true).SetText("Loading...")
|
|
||||||
statusBar.AddPage(messagePage, message, true, true)
|
|
||||||
|
|
||||||
statusBar.AddPage(shortcutsPage,
|
|
||||||
tview.NewGrid().
|
|
||||||
SetColumns(0, 0, 0, 0).
|
|
||||||
SetRows(0).
|
|
||||||
AddItem(tview.NewTextView().SetText("Shortcuts: Alt+.(dot)"), 0, 0, 1, 1, 0, 0, false).
|
|
||||||
AddItem(tview.NewTextView().SetText("New Project: n").SetTextAlign(tview.AlignCenter), 0, 1, 1, 1, 0, 0, false).
|
|
||||||
AddItem(tview.NewTextView().SetText("New Task: t").SetTextAlign(tview.AlignCenter), 0, 2, 1, 1, 0, 0, false).
|
|
||||||
AddItem(tview.NewTextView().SetText("Quit: Ctrl+C").SetTextAlign(tview.AlignRight), 0, 3, 1, 1, 0, 0, false),
|
|
||||||
true,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
62
app/util.go
Normal file
62
app/util.go
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gdamore/tcell"
|
||||||
|
"github.com/rivo/tview"
|
||||||
|
|
||||||
|
"github.com/ajaxray/geek-life/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeHorizontalLine(lineChar rune) *tview.TextView {
|
||||||
|
hr := tview.NewTextView()
|
||||||
|
hr.SetDrawFunc(func(screen tcell.Screen, x int, y int, width int, height int) (int, int, int, int) {
|
||||||
|
// Draw a horizontal line across the middle of the box.
|
||||||
|
style := tcell.StyleDefault.Foreground(tcell.ColorWhite).Background(tcell.ColorBlack)
|
||||||
|
centerY := y + height/2
|
||||||
|
for cx := x; cx < x+width; cx++ {
|
||||||
|
screen.SetContent(cx, centerY, lineChar, nil, style)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Space for other content.
|
||||||
|
return x + 1, centerY + 1, width - 2, height - (centerY + 1 - y)
|
||||||
|
})
|
||||||
|
|
||||||
|
return hr
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeLightTextInput(placeholder string) *tview.InputField {
|
||||||
|
return tview.NewInputField().
|
||||||
|
SetPlaceholder(placeholder).
|
||||||
|
SetPlaceholderTextColor(tcell.ColorLightSlateGray).
|
||||||
|
SetFieldTextColor(tcell.ColorBlack).
|
||||||
|
SetFieldBackgroundColor(tcell.ColorGray)
|
||||||
|
}
|
||||||
|
|
||||||
|
func showMessage(text string) {
|
||||||
|
message.SetText(text)
|
||||||
|
statusBar.SwitchToPage(messagePage)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
app.QueueUpdateDraw(func() {
|
||||||
|
time.Sleep(time.Second * 5)
|
||||||
|
statusBar.SwitchToPage(shortcutsPage)
|
||||||
|
})
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeButton(label string, handler func()) *tview.Button {
|
||||||
|
btn := tview.NewButton(label).SetSelectedFunc(handler).
|
||||||
|
SetLabelColor(tcell.ColorWhite)
|
||||||
|
|
||||||
|
btn.SetBackgroundColor(tcell.ColorCornflowerBlue)
|
||||||
|
|
||||||
|
return btn
|
||||||
|
}
|
||||||
|
|
||||||
|
func ignoreKeyEvt() bool {
|
||||||
|
textInputs := []string{"*tview.InputField", "*femto.View"}
|
||||||
|
return util.InArray(reflect.TypeOf(app.GetFocus()).String(), textInputs)
|
||||||
|
}
|
||||||
1
go.mod
1
go.mod
@@ -6,6 +6,7 @@ require (
|
|||||||
github.com/asdine/storm/v3 v3.2.0
|
github.com/asdine/storm/v3 v3.2.0
|
||||||
github.com/gdamore/tcell v1.3.0
|
github.com/gdamore/tcell v1.3.0
|
||||||
github.com/golang/protobuf v1.3.3 // indirect
|
github.com/golang/protobuf v1.3.3 // indirect
|
||||||
|
github.com/pgavlin/femto v0.0.0-20191028012355-31a9964a50b5
|
||||||
github.com/rivo/tview v0.0.0-20200507165325-823f280c5426
|
github.com/rivo/tview v0.0.0-20200507165325-823f280c5426
|
||||||
github.com/stretchr/testify v1.4.0 // indirect
|
github.com/stretchr/testify v1.4.0 // indirect
|
||||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 // indirect
|
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 // indirect
|
||||||
|
|||||||
12
go.sum
12
go.sum
@@ -5,6 +5,8 @@ github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863 h1:BRrxwOZBolJN4gIwv
|
|||||||
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
|
github.com/Sereal/Sereal v0.0.0-20190618215532-0b8ac451a863/go.mod h1:D0JMgToj/WdxCgd30Kc1UcA9E+WdZoJqeVOuYW7iTBM=
|
||||||
github.com/asdine/storm/v3 v3.2.0 h1:qFpwwlOyIDVVrAgJliML9fEccRO3PJrJe+KpWK199ho=
|
github.com/asdine/storm/v3 v3.2.0 h1:qFpwwlOyIDVVrAgJliML9fEccRO3PJrJe+KpWK199ho=
|
||||||
github.com/asdine/storm/v3 v3.2.0/go.mod h1:LEpXwGt4pIqrE/XcTvCnZHT5MgZCV6Ub9q7yQzOFWr0=
|
github.com/asdine/storm/v3 v3.2.0/go.mod h1:LEpXwGt4pIqrE/XcTvCnZHT5MgZCV6Ub9q7yQzOFWr0=
|
||||||
|
github.com/atotto/clipboard v0.1.2 h1:YZCtFu5Ie8qX2VmVTBnrqLSiU9XOWwqNRmdT3gIQzbY=
|
||||||
|
github.com/atotto/clipboard v0.1.2/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@@ -27,20 +29,28 @@ github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1
|
|||||||
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
github.com/lucasb-eyer/go-colorful v1.0.3 h1:QIbQXiugsb+q10B+MI+7DI1oQLdmnep86tWFlaaUAac=
|
||||||
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||||
|
github.com/mattn/go-runewidth v0.0.5/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
|
github.com/mattn/go-runewidth v0.0.8 h1:3tS41NlGYSmhhe/8fhGRzc+z3AYCw1Fe1WAyLuujKs0=
|
||||||
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.8/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
|
github.com/pgavlin/femto v0.0.0-20191028012355-31a9964a50b5 h1:jDmnr/0bMWhOta4Rk9F0RAeSpdr71SLvI34Ooav/CYM=
|
||||||
|
github.com/pgavlin/femto v0.0.0-20191028012355-31a9964a50b5/go.mod h1:vBSdyXS0eulREXU3VHVmy2BnHekZx8HTO8oEMIe/I+M=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/rivo/tview v0.0.0-20191018125527-685bf6da76c2/go.mod h1:/rBeY22VG2QprWnEqG57IBC8biVu3i0DOIjRLc9I8H0=
|
||||||
github.com/rivo/tview v0.0.0-20200507165325-823f280c5426 h1:oUJaa48KPBmtgqppKbVqP4QHRa/cdONfQoXcNWRe7wE=
|
github.com/rivo/tview v0.0.0-20200507165325-823f280c5426 h1:oUJaa48KPBmtgqppKbVqP4QHRa/cdONfQoXcNWRe7wE=
|
||||||
github.com/rivo/tview v0.0.0-20200507165325-823f280c5426/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84=
|
github.com/rivo/tview v0.0.0-20200507165325-823f280c5426/go.mod h1:6lkG1x+13OShEf0EaOCaTQYyB7d5nSbb181KtjlS+84=
|
||||||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
||||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||||
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI=
|
||||||
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
|
||||||
|
github.com/zyedidia/micro v1.4.1 h1:OuszISyaEPK/8xxkklkh7dp2ragvKDEnr4RyHfJcQdo=
|
||||||
|
github.com/zyedidia/micro v1.4.1/go.mod h1:/wcvhlXPvvvb6v176yUQE4gNzr+Erwz4pWfx7PU/cuE=
|
||||||
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg=
|
||||||
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
@@ -49,6 +59,7 @@ golang.org/x/net v0.0.0-20191105084925-a882066a44e0 h1:QPlSTtPE2k6PZPasQUbzuK3p9
|
|||||||
golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
golang.org/x/net v0.0.0-20191105084925-a882066a44e0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191018095205-727590c5006e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo=
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 h1:sfkvUWPNGwSV+8/fNqctR5lS2AqCSqYwXdrjCxp/dXo=
|
||||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -64,5 +75,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|||||||
@@ -9,5 +9,6 @@ type ProjectRepository interface {
|
|||||||
GetByUUID(UUID string) (model.Project, error)
|
GetByUUID(UUID string) (model.Project, error)
|
||||||
Create(title, UUID string) (model.Project, error)
|
Create(title, UUID string) (model.Project, error)
|
||||||
Update(p *model.Project) error
|
Update(p *model.Project) error
|
||||||
|
UpdateField(p *model.Project, field string, value interface{}) error
|
||||||
Delete(p *model.Project) error
|
Delete(p *model.Project) error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,10 @@ func (repo *projectRepository) Delete(project *model.Project) error {
|
|||||||
return repo.DB.DeleteStruct(project)
|
return repo.DB.DeleteStruct(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (repo *projectRepository) UpdateField(task *model.Project, field string, value interface{}) error {
|
||||||
|
return repo.DB.UpdateField(task, field, value)
|
||||||
|
}
|
||||||
|
|
||||||
func (repo *projectRepository) getOneByField(fieldName string, val interface{}) (model.Project, error) {
|
func (repo *projectRepository) getOneByField(fieldName string, val interface{}) (model.Project, error) {
|
||||||
var project model.Project
|
var project model.Project
|
||||||
err := repo.DB.One(fieldName, val, &project)
|
err := repo.DB.One(fieldName, val, &project)
|
||||||
|
|||||||
@@ -18,11 +18,11 @@ func NewTaskRepository(db *storm.DB) repository.TaskRepository {
|
|||||||
return &taskRepository{db}
|
return &taskRepository{db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taskRepository) GetAll() ([]model.Task, error) {
|
func (t *taskRepository) GetAll() ([]model.Task, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taskRepository) GetAllByProject(project model.Project) ([]model.Task, error) {
|
func (t *taskRepository) GetAllByProject(project model.Project) ([]model.Task, error) {
|
||||||
var tasks []model.Task
|
var tasks []model.Task
|
||||||
//err = db.Find("ProjetID", project.ID, &tasks, storm.Limit(10), storm.Skip(10), storm.Reverse())
|
//err = db.Find("ProjetID", project.ID, &tasks, storm.Limit(10), storm.Skip(10), storm.Reverse())
|
||||||
err := t.DB.Find("ProjectID", project.ID, &tasks)
|
err := t.DB.Find("ProjectID", project.ID, &tasks)
|
||||||
@@ -30,19 +30,19 @@ func (t taskRepository) GetAllByProject(project model.Project) ([]model.Task, er
|
|||||||
return tasks, err
|
return tasks, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taskRepository) GetAllByDate(from, to time.Time) ([]model.Task, error) {
|
func (t *taskRepository) GetAllByDate(from, to time.Time) ([]model.Task, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taskRepository) GetByID(ID string) (model.Task, error) {
|
func (t *taskRepository) GetByID(ID string) (model.Task, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taskRepository) GetByUUID(UUID string) (model.Task, error) {
|
func (t *taskRepository) GetByUUID(UUID string) (model.Task, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taskRepository) Create(project model.Project, title, details, UUID string, dueDate int64) (model.Task, error) {
|
func (t *taskRepository) Create(project model.Project, title, details, UUID string, dueDate int64) (model.Task, error) {
|
||||||
task := model.Task{
|
task := model.Task{
|
||||||
ProjectID: project.ID,
|
ProjectID: project.ID,
|
||||||
Title: title,
|
Title: title,
|
||||||
@@ -55,10 +55,14 @@ func (t taskRepository) Create(project model.Project, title, details, UUID strin
|
|||||||
return task, err
|
return task, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taskRepository) Update(p *model.Task) error {
|
func (t *taskRepository) Update(task *model.Task) error {
|
||||||
panic("implement me")
|
return t.DB.Update(task)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t taskRepository) Delete(p *model.Task) error {
|
func (t *taskRepository) UpdateField(task *model.Task, field string, value interface{}) error {
|
||||||
|
return t.DB.UpdateField(task, field, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *taskRepository) Delete(task *model.Task) error {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ type TaskRepository interface {
|
|||||||
GetByID(ID string) (model.Task, error)
|
GetByID(ID string) (model.Task, error)
|
||||||
GetByUUID(UUID string) (model.Task, error)
|
GetByUUID(UUID string) (model.Task, error)
|
||||||
Create(project model.Project, title, details, UUID string, dueDate int64) (model.Task, error)
|
Create(project model.Project, title, details, UUID string, dueDate int64) (model.Task, error)
|
||||||
Update(p *model.Task) error
|
Update(t *model.Task) error
|
||||||
Delete(p *model.Task) error
|
UpdateField(t *model.Task, field string, value interface{}) error
|
||||||
|
Delete(t *model.Task) error
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user