mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
51
modules/todoist/display.go
Normal file
51
modules/todoist/display.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package todoist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/rivo/tview"
|
||||
"github.com/wtfutil/wtf/wtf"
|
||||
)
|
||||
|
||||
const checkWidth = 4
|
||||
|
||||
func (widget *Widget) display() {
|
||||
proj := widget.CurrentProject()
|
||||
|
||||
if proj == nil {
|
||||
return
|
||||
}
|
||||
|
||||
title := fmt.Sprintf("[green]%s[white]", proj.Project.Name)
|
||||
widget.View.SetTitle(widget.ContextualTitle(title))
|
||||
|
||||
str := wtf.SigilStr(len(widget.projects), widget.idx, widget.View) + "\n"
|
||||
|
||||
maxLen := proj.LongestLine()
|
||||
|
||||
for index, item := range proj.tasks {
|
||||
foreColor, backColor := "white", wtf.Config.UString("wtf.colors.background", "black")
|
||||
|
||||
if index == proj.index {
|
||||
foreColor = wtf.Config.UString("wtf.colors.highlight.fore", "black")
|
||||
backColor = wtf.Config.UString("wtf.colors.highlight.back", "orange")
|
||||
}
|
||||
|
||||
row := fmt.Sprintf(
|
||||
"[%s:%s]| | %s[white]",
|
||||
foreColor,
|
||||
backColor,
|
||||
tview.Escape(item.Content),
|
||||
)
|
||||
|
||||
_, _, w, _ := widget.View.GetInnerRect()
|
||||
if w > maxLen {
|
||||
maxLen = w
|
||||
}
|
||||
|
||||
str = str + row + wtf.PadRow((checkWidth+len(item.Content)), (checkWidth+maxLen+1)) + "\n"
|
||||
}
|
||||
|
||||
//widget.View.Clear()
|
||||
widget.View.SetText(str)
|
||||
}
|
||||
112
modules/todoist/project.go
Normal file
112
modules/todoist/project.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package todoist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/darkSasori/todoist"
|
||||
)
|
||||
|
||||
type Project struct {
|
||||
todoist.Project
|
||||
|
||||
index int
|
||||
tasks []todoist.Task
|
||||
}
|
||||
|
||||
func NewProject(id int) *Project {
|
||||
// Todoist seems to experience a lot of network issues on their side
|
||||
// If we can't connect, handle it with an empty project until we can
|
||||
project, err := todoist.GetProject(id)
|
||||
if err != nil {
|
||||
return &Project{}
|
||||
}
|
||||
|
||||
proj := &Project{
|
||||
Project: project,
|
||||
|
||||
index: -1,
|
||||
}
|
||||
|
||||
proj.loadTasks()
|
||||
|
||||
return proj
|
||||
}
|
||||
|
||||
func (proj *Project) isFirst() bool {
|
||||
return proj.index == 0
|
||||
}
|
||||
|
||||
func (proj *Project) isLast() bool {
|
||||
return proj.index >= len(proj.tasks)-1
|
||||
}
|
||||
|
||||
func (proj *Project) up() {
|
||||
proj.index = proj.index - 1
|
||||
|
||||
if proj.index < 0 {
|
||||
proj.index = len(proj.tasks) - 1
|
||||
}
|
||||
}
|
||||
|
||||
func (proj *Project) down() {
|
||||
if proj.index == -1 {
|
||||
proj.index = 0
|
||||
return
|
||||
}
|
||||
|
||||
proj.index = proj.index + 1
|
||||
if proj.index >= len(proj.tasks) {
|
||||
proj.index = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (proj *Project) loadTasks() {
|
||||
tasks, err := todoist.ListTask(todoist.QueryParam{"project_id": fmt.Sprintf("%d", proj.ID)})
|
||||
if err == nil {
|
||||
proj.tasks = tasks
|
||||
}
|
||||
}
|
||||
|
||||
func (proj *Project) LongestLine() int {
|
||||
maxLen := 0
|
||||
|
||||
for _, task := range proj.tasks {
|
||||
if len(task.Content) > maxLen {
|
||||
maxLen = len(task.Content)
|
||||
}
|
||||
}
|
||||
|
||||
return maxLen
|
||||
}
|
||||
|
||||
func (proj *Project) currentTask() *todoist.Task {
|
||||
if proj.index < 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &proj.tasks[proj.index]
|
||||
}
|
||||
|
||||
func (proj *Project) closeSelectedTask() {
|
||||
currTask := proj.currentTask()
|
||||
|
||||
if currTask != nil {
|
||||
if err := currTask.Close(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
proj.loadTasks()
|
||||
}
|
||||
}
|
||||
|
||||
func (proj *Project) deleteSelectedTask() {
|
||||
currTask := proj.currentTask()
|
||||
|
||||
if currTask != nil {
|
||||
if err := currTask.Delete(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
proj.loadTasks()
|
||||
}
|
||||
}
|
||||
201
modules/todoist/widget.go
Normal file
201
modules/todoist/widget.go
Normal file
@@ -0,0 +1,201 @@
|
||||
package todoist
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/darkSasori/todoist"
|
||||
"github.com/gdamore/tcell"
|
||||
"github.com/rivo/tview"
|
||||
"github.com/wtfutil/wtf/wtf"
|
||||
)
|
||||
|
||||
const HelpText = `
|
||||
Keyboard commands for Todoist:
|
||||
|
||||
/: Show/hide this help window
|
||||
c: Close the selected item
|
||||
d: Delete the selected item
|
||||
h: Previous Todoist list
|
||||
j: Select the next item in the list
|
||||
k: Select the previous item in the list
|
||||
l: Next Todoist list
|
||||
r: Refresh the todo list data
|
||||
|
||||
arrow down: Select the next item in the list
|
||||
arrow left: Previous Todoist list
|
||||
arrow right: Next Todoist list
|
||||
arrow up: Select the previous item in the list
|
||||
`
|
||||
|
||||
type Widget struct {
|
||||
wtf.HelpfulWidget
|
||||
wtf.TextWidget
|
||||
|
||||
projects []*Project
|
||||
idx int
|
||||
}
|
||||
|
||||
func NewWidget(app *tview.Application, pages *tview.Pages) *Widget {
|
||||
widget := Widget{
|
||||
HelpfulWidget: wtf.NewHelpfulWidget(app, pages, HelpText),
|
||||
TextWidget: wtf.NewTextWidget(app, "Todoist", "todoist", true),
|
||||
}
|
||||
|
||||
widget.loadAPICredentials()
|
||||
widget.projects = loadProjects()
|
||||
|
||||
widget.HelpfulWidget.SetView(widget.View)
|
||||
widget.View.SetInputCapture(widget.keyboardIntercept)
|
||||
|
||||
return &widget
|
||||
}
|
||||
|
||||
/* -------------------- Exported Functions -------------------- */
|
||||
|
||||
func (widget *Widget) CurrentProject() *Project {
|
||||
return widget.ProjectAt(widget.idx)
|
||||
}
|
||||
|
||||
func (widget *Widget) ProjectAt(idx int) *Project {
|
||||
if len(widget.projects) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
return widget.projects[idx]
|
||||
}
|
||||
|
||||
func (w *Widget) NextProject() {
|
||||
w.idx = w.idx + 1
|
||||
if w.idx == len(w.projects) {
|
||||
w.idx = 0
|
||||
}
|
||||
|
||||
w.display()
|
||||
}
|
||||
|
||||
func (w *Widget) PreviousProject() {
|
||||
w.idx = w.idx - 1
|
||||
if w.idx < 0 {
|
||||
w.idx = len(w.projects) - 1
|
||||
}
|
||||
|
||||
w.display()
|
||||
}
|
||||
|
||||
func (w *Widget) Refresh() {
|
||||
if w.Disabled() || w.CurrentProject() == nil {
|
||||
return
|
||||
}
|
||||
|
||||
w.display()
|
||||
}
|
||||
|
||||
/* -------------------- Keyboard Movement -------------------- */
|
||||
|
||||
// Down selects the next item in the list
|
||||
func (w *Widget) Down() {
|
||||
w.CurrentProject().down()
|
||||
w.display()
|
||||
}
|
||||
|
||||
// Up selects the previous item in the list
|
||||
func (w *Widget) Up() {
|
||||
w.CurrentProject().up()
|
||||
w.display()
|
||||
}
|
||||
|
||||
// Close closes the currently-selected task in the currently-selected project
|
||||
func (w *Widget) Close() {
|
||||
w.CurrentProject().closeSelectedTask()
|
||||
|
||||
if w.CurrentProject().isLast() {
|
||||
w.Up()
|
||||
return
|
||||
}
|
||||
|
||||
w.Down()
|
||||
}
|
||||
|
||||
// Delete deletes the currently-selected task in the currently-selected project
|
||||
func (w *Widget) Delete() {
|
||||
w.CurrentProject().deleteSelectedTask()
|
||||
|
||||
if w.CurrentProject().isLast() {
|
||||
w.Up()
|
||||
return
|
||||
}
|
||||
|
||||
w.Down()
|
||||
}
|
||||
|
||||
/* -------------------- Unexported Functions -------------------- */
|
||||
|
||||
func (w *Widget) keyboardIntercept(event *tcell.EventKey) *tcell.EventKey {
|
||||
if len(w.projects) == 0 {
|
||||
return event
|
||||
}
|
||||
|
||||
switch string(event.Rune()) {
|
||||
case "/":
|
||||
w.ShowHelp()
|
||||
return nil
|
||||
case "r":
|
||||
w.Refresh()
|
||||
return nil
|
||||
case "d":
|
||||
w.Delete()
|
||||
return nil
|
||||
case "c":
|
||||
w.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
switch w.vimBindings(event) {
|
||||
case tcell.KeyLeft:
|
||||
w.PreviousProject()
|
||||
return nil
|
||||
case tcell.KeyRight:
|
||||
w.NextProject()
|
||||
return nil
|
||||
case tcell.KeyUp:
|
||||
w.Up()
|
||||
return nil
|
||||
case tcell.KeyDown:
|
||||
w.Down()
|
||||
return nil
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
func (widget *Widget) loadAPICredentials() {
|
||||
todoist.Token = wtf.Config.UString(
|
||||
"wtf.mods.todoist.apiKey",
|
||||
os.Getenv("WTF_TODOIST_TOKEN"),
|
||||
)
|
||||
}
|
||||
|
||||
func loadProjects() []*Project {
|
||||
projects := []*Project{}
|
||||
|
||||
for _, id := range wtf.Config.UList("wtf.mods.todoist.projects") {
|
||||
proj := NewProject(id.(int))
|
||||
projects = append(projects, proj)
|
||||
}
|
||||
|
||||
return projects
|
||||
}
|
||||
|
||||
func (w *Widget) vimBindings(event *tcell.EventKey) tcell.Key {
|
||||
switch string(event.Rune()) {
|
||||
case "h":
|
||||
return tcell.KeyLeft
|
||||
case "l":
|
||||
return tcell.KeyRight
|
||||
case "k":
|
||||
return tcell.KeyUp
|
||||
case "j":
|
||||
return tcell.KeyDown
|
||||
}
|
||||
return event.Key()
|
||||
}
|
||||
Reference in New Issue
Block a user