UI Mode Work & Archiving
This commit is contained in:
parent
f4af61386e
commit
69e1c959f6
28
bundle.go
Normal file
28
bundle.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type Bundle map[string]interface{}
|
||||||
|
|
||||||
|
func (b Bundle) setValue(key string, val interface{}) {
|
||||||
|
b[key] = val
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Bundle) getBool(key string, def bool) bool {
|
||||||
|
if v, ok := b[key].(bool); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Bundle) getString(key, def string) string {
|
||||||
|
if v, ok := b[key].(string); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b Bundle) getInt(key string, def int) int {
|
||||||
|
if v, ok := b[key].(int); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return def
|
||||||
|
}
|
67
screen.go
Normal file
67
screen.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
termbox "github.com/nsf/termbox-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Screen interface {
|
||||||
|
handleKeyEvent(termbox.Event) int
|
||||||
|
initialize(Bundle) error
|
||||||
|
drawScreen()
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ScreenMain = iota
|
||||||
|
ScreenAbout
|
||||||
|
ScreenExit
|
||||||
|
|
||||||
|
DefaultBg = termbox.ColorBlack
|
||||||
|
DefaultFg = termbox.ColorWhite
|
||||||
|
TitleFg = termbox.ColorWhite
|
||||||
|
TitleBg = termbox.ColorBlue
|
||||||
|
CursorFg = termbox.ColorBlack
|
||||||
|
CursorBg = termbox.ColorGreen
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *AppState) BuildScreens() {
|
||||||
|
mainScreen := MainScreen{}
|
||||||
|
aboutScreen := AboutScreen{}
|
||||||
|
a.screens = append(a.screens, &mainScreen)
|
||||||
|
a.screens = append(a.screens, &aboutScreen)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppState) drawBackground(bg termbox.Attribute) {
|
||||||
|
termbox.Clear(0, bg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppState) layoutAndDrawScreen(s Screen) {
|
||||||
|
a.drawBackground(DefaultBg)
|
||||||
|
s.drawScreen()
|
||||||
|
termbox.Flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
func readUserInput(e chan termbox.Event) {
|
||||||
|
for {
|
||||||
|
e <- termbox.PollEvent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func refreshList(e chan termbox.Event) {
|
||||||
|
/*
|
||||||
|
for {
|
||||||
|
time.Sleep(5 * time.Minute)
|
||||||
|
app.LoadTasklist()
|
||||||
|
app.LoadDoneList()
|
||||||
|
e <- termbox.Event{Type: termbox.EventNone}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ViewPort helps keep track of what's being displayed on the screen
|
||||||
|
*/
|
||||||
|
type ViewPort struct {
|
||||||
|
bytesPerRow int
|
||||||
|
numberOfRows int
|
||||||
|
firstRow int
|
||||||
|
}
|
93
screen_about.go
Normal file
93
screen_about.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/br0xen/termbox-util"
|
||||||
|
termbox "github.com/nsf/termbox-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AboutScreen holds all that's going on
|
||||||
|
type AboutScreen struct {
|
||||||
|
viewPort ViewPort
|
||||||
|
message string
|
||||||
|
messageTimeout time.Duration
|
||||||
|
messageTime time.Time
|
||||||
|
|
||||||
|
titleTemplate []string
|
||||||
|
commandsCol1 []Command
|
||||||
|
commandsCol2 []Command
|
||||||
|
}
|
||||||
|
|
||||||
|
type Command struct {
|
||||||
|
key string
|
||||||
|
description string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *AboutScreen) initialize(bundle Bundle) error {
|
||||||
|
screen.titleTemplate = []string{
|
||||||
|
" .__ ",
|
||||||
|
" ____ |__| _____ ____ ",
|
||||||
|
" / ___\\| |/ \\_/ __ \\ ",
|
||||||
|
" / /_/ > | Y Y \\ ___/ ",
|
||||||
|
" \\___ /|__|__|_| /\\___ >",
|
||||||
|
"/_____/ \\/ \\/ ",
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.commandsCol1 = []Command{
|
||||||
|
Command{"j,↓", "down"},
|
||||||
|
Command{"k,↑", "up"},
|
||||||
|
Command{"l,→", "open task"},
|
||||||
|
Command{"------", "---------"},
|
||||||
|
Command{"g", "goto top"},
|
||||||
|
Command{"G", "goto bottom"},
|
||||||
|
Command{"ctrl+f", "jump down"},
|
||||||
|
Command{"ctrl+b", "jump up"},
|
||||||
|
}
|
||||||
|
screen.commandsCol2 = []Command{
|
||||||
|
Command{"D", "archive timer to done.txt"},
|
||||||
|
Command{"------", "---------"},
|
||||||
|
Command{"?", "this screen"},
|
||||||
|
Command{"q", "quit program"},
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *AboutScreen) handleKeyEvent(event termbox.Event) int {
|
||||||
|
return ScreenMain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *AboutScreen) drawScreen() {
|
||||||
|
width, height := termbox.Size()
|
||||||
|
xPos := (width - len(screen.titleTemplate[0])) / 2
|
||||||
|
yPos := 1
|
||||||
|
for _, line := range screen.titleTemplate {
|
||||||
|
termboxUtil.DrawStringAtPoint(line, xPos, yPos, DefaultFg, DefaultBg)
|
||||||
|
yPos++
|
||||||
|
}
|
||||||
|
|
||||||
|
numCols := 2
|
||||||
|
if width < 80 {
|
||||||
|
numCols = 1
|
||||||
|
}
|
||||||
|
col1XPos := (width - (width * 3 / 4))
|
||||||
|
col2XPos := (width - (width * 2 / 4))
|
||||||
|
if numCols == 1 {
|
||||||
|
col2XPos = col1XPos
|
||||||
|
}
|
||||||
|
screen.drawCommandsAtPoint(screen.commandsCol1, col1XPos, yPos)
|
||||||
|
screen.drawCommandsAtPoint(screen.commandsCol2, col2XPos, yPos)
|
||||||
|
exitTxt := "Press any key to return to tasks"
|
||||||
|
termboxUtil.DrawStringAtPoint(exitTxt, (width-len(exitTxt))/2, height-1, TitleFg, TitleBg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *AboutScreen) drawCommandsAtPoint(commands []Command, x, y int) {
|
||||||
|
xPos, yPos := x, y
|
||||||
|
for _, cmd := range commands {
|
||||||
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("%6s", cmd.key), xPos, yPos, DefaultFg, DefaultBg)
|
||||||
|
termboxUtil.DrawStringAtPoint(cmd.description, xPos+8, yPos, DefaultFg, DefaultBg)
|
||||||
|
yPos++
|
||||||
|
}
|
||||||
|
}
|
327
screen_main.go
Normal file
327
screen_main.go
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
timertxt "git.bullercodeworks.com/brian/go-timertxt"
|
||||||
|
"github.com/br0xen/termbox-util"
|
||||||
|
termbox "github.com/nsf/termbox-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
MainBundleListKey = "mainscreen.list"
|
||||||
|
MainBundleFilterKey = "mainscreen.filter"
|
||||||
|
|
||||||
|
MainBundleListRecent = "mainscreen.list.recent"
|
||||||
|
MainBundleListArchive = "mainscreen.list.archive"
|
||||||
|
|
||||||
|
MainBackspaceNothing = iota
|
||||||
|
MainBackspaceMain
|
||||||
|
MainBackspaceFilter
|
||||||
|
|
||||||
|
InputIDFilter = "filter"
|
||||||
|
InputIDAddTimer = "add timer"
|
||||||
|
InputIDUnArchiveTask = "move timer to active list? (y/n)"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MainScreen struct {
|
||||||
|
viewPort ViewPort
|
||||||
|
message string
|
||||||
|
messageTimeout time.Duration
|
||||||
|
messageTime time.Time
|
||||||
|
mode int
|
||||||
|
|
||||||
|
cursor map[string]int
|
||||||
|
inputField *termboxUtil.InputField
|
||||||
|
|
||||||
|
currentList string
|
||||||
|
currentFilter string
|
||||||
|
backspaceDoes int
|
||||||
|
displayList *timertxt.TimerList
|
||||||
|
activeList *timertxt.TimerList
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) initialize(bundle Bundle) error {
|
||||||
|
width, height := termbox.Size()
|
||||||
|
screen.inputField = termboxUtil.CreateInputField(0, (height - 3), width, 1, DefaultFg, DefaultBg)
|
||||||
|
|
||||||
|
screen.cursor = make(map[string]int)
|
||||||
|
if bundle != nil {
|
||||||
|
if err := screen.reloadList(bundle); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
screen.inputField.SetID("")
|
||||||
|
screen.inputField.SetBordered(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) reloadList(bundle Bundle) error {
|
||||||
|
screen.displayList = timertxt.NewTimerList()
|
||||||
|
screen.currentList = bundle.getString(MainBundleListKey, MainBundleListRecent)
|
||||||
|
switch screen.currentList {
|
||||||
|
case MainBundleListRecent:
|
||||||
|
screen.setActiveList(app.TimerList)
|
||||||
|
if screen.currentFilter = bundle.getString(MainBundleFilterKey, ""); screen.currentFilter != "" {
|
||||||
|
filteredList := app.filterList(screen.activeList, screen.currentFilter)
|
||||||
|
for _, av := range *screen.activeList {
|
||||||
|
for _, fv := range *filteredList {
|
||||||
|
if av.String() == fv.String() {
|
||||||
|
screen.displayList.AddTimer(&av)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, av := range *screen.activeList {
|
||||||
|
screen.displayList.AddTimer(&av)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case MainBundleListArchive:
|
||||||
|
//screen.setActiveList(
|
||||||
|
}
|
||||||
|
if screen.cursor[screen.currentList] > len(*screen.displayList)-1 {
|
||||||
|
screen.cursor[screen.currentList] = len(*screen.displayList) - 1
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) reloadCurrentView() {
|
||||||
|
bundle := Bundle{}
|
||||||
|
bundle.setValue(MainBundleListKey, screen.currentList)
|
||||||
|
bundle.setValue(MainBundleFilterKey, screen.currentFilter)
|
||||||
|
screen.reloadList(bundle)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) handleKeyEvent(event termbox.Event) int {
|
||||||
|
if screen.inputField.GetID() != "" {
|
||||||
|
return screen.handleInputKeyEvent(event)
|
||||||
|
}
|
||||||
|
if event.Ch == '?' {
|
||||||
|
// Go to About Screen
|
||||||
|
b := Bundle{}
|
||||||
|
if err := app.screens[ScreenAbout].initialize(b); err != nil {
|
||||||
|
screen.setMessage(err.Error())
|
||||||
|
}
|
||||||
|
return ScreenAbout
|
||||||
|
|
||||||
|
} else if event.Ch == 'g' {
|
||||||
|
screen.cursor[screen.currentList] = 0
|
||||||
|
|
||||||
|
} else if event.Ch == 'G' {
|
||||||
|
screen.cursor[screen.currentList] = len(*screen.displayList) - 1
|
||||||
|
|
||||||
|
} else if event.Key == termbox.KeyCtrlF {
|
||||||
|
// Jump forward half a screen
|
||||||
|
_, h := termbox.Size()
|
||||||
|
screen.cursor[screen.currentList] += (h / 2)
|
||||||
|
if screen.cursor[screen.currentList] >= len(*screen.displayList) {
|
||||||
|
screen.cursor[screen.currentList] = len(*screen.displayList) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if event.Key == termbox.KeyCtrlB {
|
||||||
|
// Jump back half a screen
|
||||||
|
_, h := termbox.Size()
|
||||||
|
screen.cursor[screen.currentList] -= (h / 2)
|
||||||
|
if screen.cursor[screen.currentList] < 0 {
|
||||||
|
screen.cursor[screen.currentList] = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if event.Ch == 'j' || event.Key == termbox.KeyArrowDown {
|
||||||
|
screen.moveCursorDown()
|
||||||
|
|
||||||
|
} else if event.Ch == 'k' || event.Key == termbox.KeyArrowUp {
|
||||||
|
screen.moveCursorUp()
|
||||||
|
|
||||||
|
} else if event.Ch == '/' {
|
||||||
|
screen.startFilter()
|
||||||
|
|
||||||
|
} else if event.Ch == 'L' {
|
||||||
|
return screen.toggleViewList()
|
||||||
|
|
||||||
|
} else if event.Ch == 'q' {
|
||||||
|
return ScreenExit
|
||||||
|
|
||||||
|
}
|
||||||
|
return ScreenMain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) handleInputKeyEvent(event termbox.Event) int {
|
||||||
|
switch screen.inputField.GetID() {
|
||||||
|
case InputIDFilter:
|
||||||
|
if event.Key == termbox.KeyEnter {
|
||||||
|
// Apply the filter
|
||||||
|
filter := screen.inputField.GetValue()
|
||||||
|
screen.inputField.SetID("")
|
||||||
|
screen.inputField.SetValue("")
|
||||||
|
screen.backspaceDoes = MainBackspaceFilter
|
||||||
|
screen.reloadList(screen.buildBundle(screen.currentList, filter))
|
||||||
|
return ScreenMain
|
||||||
|
}
|
||||||
|
case InputIDAddTimer:
|
||||||
|
if event.Key == termbox.KeyEnter {
|
||||||
|
// Create the new item
|
||||||
|
err := app.addTimer(screen.inputField.GetValue())
|
||||||
|
if err != nil {
|
||||||
|
screen.setMessage(err.Error())
|
||||||
|
}
|
||||||
|
screen.inputField.SetID("")
|
||||||
|
screen.inputField.SetValue("")
|
||||||
|
screen.reloadList(screen.buildBundle(screen.currentList, screen.currentFilter))
|
||||||
|
return ScreenMain
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if event.Key == termbox.KeyBackspace || event.Key == termbox.KeyBackspace2 {
|
||||||
|
if screen.inputField.GetValue() == "" {
|
||||||
|
screen.reloadList(screen.buildBundle(screen.currentList, screen.inputField.GetValue()))
|
||||||
|
screen.inputField.SetID("")
|
||||||
|
screen.inputField.SetValue("")
|
||||||
|
return ScreenMain
|
||||||
|
}
|
||||||
|
} else if event.Key == termbox.KeyEsc {
|
||||||
|
screen.reloadList(screen.buildBundle(screen.currentList, screen.currentFilter))
|
||||||
|
screen.inputField.SetID("")
|
||||||
|
screen.inputField.SetValue("")
|
||||||
|
return ScreenMain
|
||||||
|
}
|
||||||
|
screen.inputField.HandleEvent(event)
|
||||||
|
return ScreenMain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) drawScreen() {
|
||||||
|
_, height := termbox.Size()
|
||||||
|
screen.viewPort.numberOfRows = height - 1
|
||||||
|
if screen.inputField.GetID() != "" {
|
||||||
|
screen.viewPort.numberOfRows--
|
||||||
|
}
|
||||||
|
screen.viewPort.firstRow = 1
|
||||||
|
displayOffset := 0
|
||||||
|
maxCursor := screen.viewPort.numberOfRows * 2 / 3
|
||||||
|
if screen.cursor[screen.currentList] > maxCursor {
|
||||||
|
displayOffset = screen.cursor[screen.currentList] - maxCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
if screen.message == "" {
|
||||||
|
screen.setMessageWithTimeout("Press '?' for help", -1)
|
||||||
|
}
|
||||||
|
screen.drawHeader()
|
||||||
|
topId := 0
|
||||||
|
for _, v := range *screen.displayList {
|
||||||
|
if v.Id > topId {
|
||||||
|
topId = v.Id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
padCnt := fmt.Sprintf("%d", topId)
|
||||||
|
for k, v := range *screen.displayList {
|
||||||
|
pad := strings.Repeat(" ", len(padCnt)-len(fmt.Sprintf("%d", v.Id)))
|
||||||
|
useFg, useBg := DefaultFg, DefaultBg
|
||||||
|
if k == screen.cursor[screen.currentList] {
|
||||||
|
useFg, useBg = CursorFg, CursorBg
|
||||||
|
}
|
||||||
|
lineY := k + 1 - displayOffset
|
||||||
|
if lineY > 0 && lineY < screen.viewPort.numberOfRows {
|
||||||
|
termboxUtil.DrawStringAtPoint(pad+app.getTimerString(v), 0, lineY, useFg, useBg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
screen.drawFooter()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) drawHeader() {
|
||||||
|
width, _ := termbox.Size()
|
||||||
|
headerString := screen.currentFilter
|
||||||
|
if headerString == "" {
|
||||||
|
if screen.currentList == MainBundleListRecent {
|
||||||
|
headerString = "Timers"
|
||||||
|
} else if screen.currentList == MainBundleListArchive {
|
||||||
|
headerString = "Timer Archive"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spaces := strings.Repeat(" ", ((width-len(headerString))/2)+1)
|
||||||
|
termboxUtil.DrawStringAtPoint(fmt.Sprintf("%s%s%s", spaces, headerString, spaces), 0, 0, TitleFg, TitleBg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) drawFooter() {
|
||||||
|
if screen.messageTimeout > 0 && time.Since(screen.messageTime) > screen.messageTimeout {
|
||||||
|
screen.clearMessage()
|
||||||
|
}
|
||||||
|
width, height := termbox.Size()
|
||||||
|
if screen.inputField.GetID() != "" {
|
||||||
|
screen.inputField.SetX(len(screen.inputField.GetID()) + 2)
|
||||||
|
pad := width - len(screen.inputField.GetID()+":")
|
||||||
|
field := screen.inputField.GetID() + ":" + strings.Repeat(" ", pad)
|
||||||
|
termboxUtil.DrawStringAtPoint(field, 0, height-2, DefaultFg, DefaultBg)
|
||||||
|
screen.inputField.Draw()
|
||||||
|
}
|
||||||
|
// And the 'message'
|
||||||
|
termboxUtil.DrawStringAtPoint(screen.message, 0, height-1, DefaultFg, DefaultBg)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) toggleViewList() int {
|
||||||
|
bundle := Bundle{}
|
||||||
|
if screen.currentList == MainBundleListRecent {
|
||||||
|
bundle.setValue(MainBundleListKey, MainBundleListArchive)
|
||||||
|
screen.backspaceDoes = MainBackspaceMain
|
||||||
|
} else {
|
||||||
|
bundle.setValue(MainBundleListKey, MainBundleListRecent)
|
||||||
|
}
|
||||||
|
bundle.setValue(MainBundleFilterKey, screen.currentFilter)
|
||||||
|
screen.reloadList(bundle)
|
||||||
|
return ScreenMain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) moveCursorDown() bool {
|
||||||
|
screen.cursor[screen.currentList]++
|
||||||
|
if screen.cursor[screen.currentList] >= len(*screen.displayList) {
|
||||||
|
screen.cursor[screen.currentList] = len(*screen.displayList) - 1
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) moveCursorUp() bool {
|
||||||
|
screen.cursor[screen.currentList]--
|
||||||
|
if screen.cursor[screen.currentList] < 0 {
|
||||||
|
screen.cursor[screen.currentList] = 0
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) startFilter() int {
|
||||||
|
screen.inputField.SetID(InputIDFilter)
|
||||||
|
return ScreenMain
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) setMessage(msg string) {
|
||||||
|
screen.message = msg
|
||||||
|
screen.messageTime = time.Now()
|
||||||
|
screen.messageTimeout = time.Second * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
/* setMessageWithTimeout lets you specify the timeout for the message
|
||||||
|
* setting it to -1 means it won't timeout
|
||||||
|
*/
|
||||||
|
func (screen *MainScreen) setMessageWithTimeout(msg string, timeout time.Duration) {
|
||||||
|
screen.message = msg
|
||||||
|
screen.messageTime = time.Now()
|
||||||
|
screen.messageTimeout = timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) clearMessage() {
|
||||||
|
screen.message = fmt.Sprintf("%d Total Tasks", len(*screen.activeList))
|
||||||
|
screen.messageTimeout = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) buildBundle(list, filter string) Bundle {
|
||||||
|
bundle := Bundle{}
|
||||||
|
bundle.setValue(MainBundleListKey, list)
|
||||||
|
bundle.setValue(MainBundleFilterKey, filter)
|
||||||
|
return bundle
|
||||||
|
}
|
||||||
|
|
||||||
|
func (screen *MainScreen) setActiveList(list *timertxt.TimerList) {
|
||||||
|
screen.activeList = list
|
||||||
|
}
|
212
timer_ops.go
Normal file
212
timer_ops.go
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
timertxt "git.bullercodeworks.com/brian/go-timertxt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (a *AppState) opStatus(args []string) int {
|
||||||
|
if len(*a.TimerList.GetActiveTimers()) == 0 {
|
||||||
|
fmt.Println("No timers running")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
var currDur time.Duration
|
||||||
|
for _, v := range *a.TimerList {
|
||||||
|
if v.ActiveToday() {
|
||||||
|
currDur += v.Duration()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d := currDur.Round(GetRoundToDuration())
|
||||||
|
fmt.Printf("%s ( %.2f hrs )\n", time.Now().Format(time.Stamp), DurationToDecimal(d))
|
||||||
|
for _, v := range *a.TimerList.GetActiveTimers() {
|
||||||
|
fmt.Println(timerToFriendlyString(&v))
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List timers for a given time span
|
||||||
|
* By default, only list Today
|
||||||
|
*/
|
||||||
|
func (a *AppState) opListTimers(args []string) int {
|
||||||
|
var start, end time.Time
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if len(args) > 0 {
|
||||||
|
if args[0] == "--a" {
|
||||||
|
start = time.Time{}
|
||||||
|
end = time.Now()
|
||||||
|
args = args[1:]
|
||||||
|
} else {
|
||||||
|
if start, err = parseFuzzyTime(args[0]); err != nil {
|
||||||
|
y, m, d := time.Now().Date()
|
||||||
|
start = time.Date(y, m, d, 0, 0, 0, 0, time.Now().Location())
|
||||||
|
} else {
|
||||||
|
args = args[1:]
|
||||||
|
}
|
||||||
|
if end, err = parseFuzzyTime(args[0]); err != nil {
|
||||||
|
y, m, d := time.Now().Date()
|
||||||
|
end = time.Date(y, m, d, 23, 59, 59, 0, time.Now().Location())
|
||||||
|
} else {
|
||||||
|
args = args[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
list := a.TimerList.GetTimersInRange(start, end)
|
||||||
|
dayTotals := make(map[string]time.Duration)
|
||||||
|
for _, v := range *list {
|
||||||
|
dur := v.FinishDate.Sub(v.StartDate)
|
||||||
|
if v.FinishDate.IsZero() {
|
||||||
|
dur = time.Now().Sub(v.StartDate)
|
||||||
|
}
|
||||||
|
dayTotals[v.StartDate.Format("2006/01/02")] += dur
|
||||||
|
}
|
||||||
|
var oldDayStr, dayStr string
|
||||||
|
for _, v := range *list {
|
||||||
|
oldDayStr = dayStr
|
||||||
|
dayStr = v.StartDate.Format("2006/01/02")
|
||||||
|
if dayStr != oldDayStr {
|
||||||
|
wrkDur := dayTotals[dayStr].Round(GetRoundToDuration())
|
||||||
|
fmtStr := dayStr + " ( %.2f )\n"
|
||||||
|
fmt.Printf(fmtStr, DurationToDecimal(wrkDur))
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println(" " + timerToFriendlyString(&v))
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppState) opStartTimer(args []string) int {
|
||||||
|
var contexts, projects []string
|
||||||
|
t := timertxt.NewTimer()
|
||||||
|
contexts, args = getContextsFromSlice(args)
|
||||||
|
projects, args = getProjectsFromSlice(args)
|
||||||
|
if len(args) > 0 {
|
||||||
|
if start, err := parseFuzzyTime(args[0]); err == nil {
|
||||||
|
t.StartDate = start
|
||||||
|
args = args[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, v := range contexts {
|
||||||
|
t.Contexts = append(t.Contexts, strings.TrimPrefix(v, "@"))
|
||||||
|
}
|
||||||
|
for _, v := range projects {
|
||||||
|
t.Projects = append(t.Projects, strings.TrimPrefix(v, "+"))
|
||||||
|
}
|
||||||
|
|
||||||
|
a.TimerList.AddTimer(t)
|
||||||
|
if err := a.WriteList(); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppState) opStopTimer(args []string) int {
|
||||||
|
var err error
|
||||||
|
var wrk time.Time
|
||||||
|
end := time.Now()
|
||||||
|
id := -1
|
||||||
|
|
||||||
|
if len(args) > 0 {
|
||||||
|
if wrk, err = parseFuzzyTime(args[0]); err != nil {
|
||||||
|
id, err = strconv.Atoi(args[0])
|
||||||
|
} else {
|
||||||
|
end = wrk
|
||||||
|
args = args[1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("Stopping at : " + end.Format(time.RFC3339))
|
||||||
|
var timerIds []int
|
||||||
|
if id == -1 {
|
||||||
|
for _, v := range *a.TimerList.GetActiveTimers() {
|
||||||
|
timerIds = append(timerIds, v.Id)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
timerIds = append(timerIds, id)
|
||||||
|
}
|
||||||
|
for _, v := range timerIds {
|
||||||
|
var stopped *timertxt.Timer
|
||||||
|
if stopped, err = a.TimerList.GetTimer(v); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
if err = a.SetTimerFinished(v, end); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fmt.Println("Stopped Timer:", timerToFriendlyString(stopped))
|
||||||
|
}
|
||||||
|
if err = a.WriteList(); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppState) opSwitchTimer(args []string) int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppState) opArchiveTimer(args []string) int {
|
||||||
|
if len(args) > 0 {
|
||||||
|
for _, v := range args {
|
||||||
|
var id int
|
||||||
|
var timer *timertxt.Timer
|
||||||
|
var err error
|
||||||
|
if id, err = strconv.Atoi(v); err != nil {
|
||||||
|
fmt.Printf("Invalid id given: %s\n", v)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if timer, err = a.TimerList.GetTimer(id); err != nil {
|
||||||
|
fmt.Printf("Error getting timer %d\n", id)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if err = a.archiveTimer(id); err != nil {
|
||||||
|
fmt.Printf("Error archiving timer %d\n", id)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
fmt.Println(a.getDoneTimerString(*timer))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for _, v := range *a.TimerList {
|
||||||
|
if v.Finished {
|
||||||
|
if err := a.archiveTimer(v.Id); err != nil {
|
||||||
|
fmt.Printf("Error archiving task %d\n", v.Id)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
fmt.Println(a.getDoneTimerString(v))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppState) opState(args []string) int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppState) opFuzzyParse(args []string) int {
|
||||||
|
if len(args) > 0 {
|
||||||
|
if start, err := parseFuzzyTime(args[0]); err == nil {
|
||||||
|
fmt.Println(start.Format(time.RFC3339))
|
||||||
|
} else {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *AppState) opPrintUsage(args []string) int {
|
||||||
|
for _, v := range a.ValidOperations {
|
||||||
|
for _, vv := range v {
|
||||||
|
fmt.Println(" " + vv)
|
||||||
|
fmt.Println("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
56
ui_loop.go
Normal file
56
ui_loop.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
termbox "github.com/nsf/termbox-go"
|
||||||
|
)
|
||||||
|
|
||||||
|
func uiLoop() int {
|
||||||
|
err := termbox.Init()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
termbox.SetOutputMode(termbox.Output256)
|
||||||
|
app.BuildScreens()
|
||||||
|
displayScreen := app.screens[ScreenMain]
|
||||||
|
bundle := Bundle{}
|
||||||
|
bundle.setValue(MainBundleListKey, MainBundleListRecent)
|
||||||
|
displayScreen.initialize(bundle)
|
||||||
|
app.layoutAndDrawScreen(displayScreen)
|
||||||
|
eventChan := make(chan termbox.Event)
|
||||||
|
go readUserInput(eventChan)
|
||||||
|
for {
|
||||||
|
event := <-eventChan
|
||||||
|
if event.Type == termbox.EventKey {
|
||||||
|
if event.Key == termbox.KeyCtrlC {
|
||||||
|
break
|
||||||
|
} else if event.Key == termbox.KeyCtrlZ {
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
process, _ := os.FindProcess(os.Getpid())
|
||||||
|
termbox.Close()
|
||||||
|
process.Signal(syscall.SIGSTOP)
|
||||||
|
termbox.Init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newScreenIndex := displayScreen.handleKeyEvent(event)
|
||||||
|
if newScreenIndex < len(app.screens) {
|
||||||
|
displayScreen = app.screens[newScreenIndex]
|
||||||
|
app.layoutAndDrawScreen(displayScreen)
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if event.Type == termbox.EventResize {
|
||||||
|
displayScreen.initialize(nil)
|
||||||
|
app.layoutAndDrawScreen(displayScreen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
termbox.Close()
|
||||||
|
// Any wrap up should be done here...
|
||||||
|
return 0
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user