This commit is contained in:
Brian Buller 2023-02-02 06:08:50 -06:00
parent e0affc82d4
commit 5ff74e851c
5 changed files with 183 additions and 118 deletions

View File

@ -43,6 +43,18 @@ func (p *Program) LoadTimerList() error {
return nil
}
func (p *Program) WriteLists() error {
err := p.WriteTimerList()
if dErr := p.WriteDoneList(); dErr != nil {
if err == nil {
return fmt.Errorf("Error writing Done list %w", dErr)
} else {
return fmt.Errorf("Error writing Both lists (Timer: %s; Done: %s) (%w)", err.Error(), dErr.Error(), err)
}
}
return nil
}
func (p *Program) WriteTimerList() error {
return p.TimerList.WriteToFilename(p.timerPath)
}

View File

@ -53,6 +53,15 @@ type listTimersScreen struct {
type ListTimersMsg ScreenMsg
func NewListTimersMsg(data interface{}, err error) ListTimersMsg {
return ListTimersMsg{
source: ListTimersId,
command: CmdArchiveTimer,
data: data,
err: err,
}
}
func NewListTimersScreen(u *Ui) *listTimersScreen {
s := listTimersScreen{
ui: u,
@ -115,6 +124,7 @@ func (s *listTimersScreen) Init() wandle.Cmd {
func (s *listTimersScreen) Update(msg wandle.Msg) wandle.Cmd {
switch msg := msg.(type) {
case ScreenMsg:
s.err = msg.err
case termbox.Event:
return s.handleTermboxEvent(msg)
}
@ -172,7 +182,17 @@ func (s *listTimersScreen) View(style wandle.Style) {
selectedStatus = fmt.Sprintf("%s (%d / %d selected)", selectedStatus, len(s.selected), s.fullFilterList.Size())
}
wandle.Print(1, h-2, style, selectedStatus)
help := "[T]oggle Display, [p]roject(+), [c]ontext(@), [t]ags(:), [A]rchive Selected, [Ctrl+A]: Select All/None, [Ctrl+I]: Invert Selection"
var archiveText string
if s.areSelectedInSameList() {
if s.areSelectedInDoneList() {
archiveText = "Un[A]rchive Selected, "
} else {
archiveText = "[A]rchive Selected, "
}
} else {
archiveText = "Not in Same List"
}
help := fmt.Sprintf("[T]oggle Display, [p]roject(+), [c]ontext(@), [t]ags(:), %s[Ctrl+A]: Select All/None, [Ctrl+I]: Invert Selection", archiveText)
wandle.Print(1, h-1, style, help)
s.scrollbar.View(style)
@ -188,7 +208,10 @@ func (s *listTimersScreen) View(style wandle.Style) {
if s.confirm.IsActive() {
s.confirm.View(style)
}
wandle.Print(1, h-2, style, s.msg)
wandle.Print(1, h-3, style, s.msg)
if s.err != nil {
wandle.Print(1, h-4, ErrStyle, s.err.Error())
}
}
func (s *listTimersScreen) ViewTimer(x, y int, style wandle.Style, tmr *timertxt.Timer) {
@ -204,7 +227,12 @@ func (s *listTimersScreen) handleTermboxEvent(msg termbox.Event) wandle.Cmd {
return s.confirm.Update(msg)
}
if s.choiceMenu.IsActive() {
return s.choiceMenu.Update(msg)
if msg.Type == termbox.EventKey && msg.Key == termbox.KeyEsc {
s.choiceMenu.SetActive(false)
return wandle.EmptyCmd
} else {
return s.choiceMenu.Update(msg)
}
}
if s.tagEditor.IsActive() {
return s.tagEditor.Update(msg)
@ -252,6 +280,8 @@ func (s *listTimersScreen) handleTermboxEvent(msg termbox.Event) wandle.Cmd {
return nil
} else if msg.Ch == 'G' {
s.cursor = s.fullFilterList.Size() - 1
} else if msg.Ch == 'g' {
s.cursor = 0
} else if msg.Ch == 't' {
// Edit tag(s)
return s.showEditTagsChoice()
@ -301,10 +331,10 @@ func (s *listTimersScreen) showArchiveSelected() wandle.Cmd {
return func() wandle.Msg {
if len(s.selected) > 0 {
s.confirm.SetTitle(fmt.Sprintf("Archive %d Timers?", len(s.selected)))
s.confirm.SetMessage("Are you sure you want to archive these timers?")
s.confirm.SetMessage("Are you sure you want to archive these timers? (y/n)")
} else {
s.confirm.SetTitle("Archive Timer?")
s.confirm.SetMessage("Are you sure you want to archive this timer?")
s.confirm.SetMessage("Are you sure you want to archive this timer? (y/n)")
}
s.confirm.SetOkCommand(func() wandle.Msg {
s.confirm.SetVisible(false)
@ -319,25 +349,35 @@ func (s *listTimersScreen) showArchiveSelected() wandle.Cmd {
}
}
func (s *listTimersScreen) doArchiveSelected() wandle.Cmd {
return func() wandle.Msg {
selected := len(s.selected)
if selected == 0 {
if s.cursor < s.fullFilterList.Size() {
var selTimer *timertxt.Timer
if selTimer, s.err = s.fullFilterList.GetTimer(s.cursor); s.err == nil {
}
}
} else {
for i := range s.selected {
if tmr, err := s.fullFilterList.GetTimer(i); err == nil {
archiveTimer := func(t *timertxt.Timer) error {
if remErr := s.timerList.RemoveTimer(*t); remErr != nil {
return remErr
}
s.doneList.AddTimer(t)
return nil
}
selected := len(s.selected)
if selected == 0 {
if s.cursor < s.fullFilterList.Size() {
var selTimer *timertxt.Timer
if selTimer, s.err = s.fullFilterList.GetTimer(s.cursor); s.err == nil {
if archErr := archiveTimer(selTimer); archErr != nil {
s.err = archErr
return wandle.EmptyCmd
}
}
}
} else {
for i := range s.selected {
if tmr, err := s.fullFilterList.GetTimer(i); err == nil {
if err := archiveTimer(tmr); err != nil {
s.err = err
return wandle.EmptyCmd
}
}
}
return nil
}
//return wandle.EmptyCmd
return wandle.EmptyCmd
}
func (s *listTimersScreen) showEditTagsChoice() wandle.Cmd {
@ -393,12 +433,19 @@ func (s *listTimersScreen) showEditTagsChoice() wandle.Cmd {
removeTag.SetCommand(func() wandle.Msg {
s.choiceMenu.ClearOptions()
s.choiceMenu.SetTitle("Choose Tag to Remove")
for k, v := range tags {
opt := widdles.NewMenuItem(fmt.Sprintf("%s: %s", k, v))
opt.SetCommand(func() wandle.Msg {
s.removeTagOnSelectedTimers(k)
return wandle.EmptyCmd
})
s.choiceMenu.AddOption(opt)
}
s.choiceMenu.SetActive(true)
return wandle.EmptyCmd
})
s.choiceMenu.AddOption(removeTag)
s.choiceMenu.SetActive(true)
//tags := s.fullList.GetTagKeys()
//_ = tags
return wandle.EmptyCmd
}
@ -425,127 +472,112 @@ func (s *listTimersScreen) gotoSettingsScreen() wandle.Msg {
}
}
func (s *listTimersScreen) getSelectedTimerTags() map[string][]string {
ret := make(map[string][]string)
selected := len(s.selected)
if selected == 0 {
if s.cursor < s.fullFilterList.Size() {
var selTimer *timertxt.Timer
if selTimer, s.err = s.fullFilterList.GetTimer(s.cursor); s.err == nil {
for k, v := range selTimer.AdditionalTags {
ret[k] = []string{v}
}
}
}
} else {
for i := range s.selected {
if tmr, err := s.fullFilterList.GetTimer(i); err == nil {
for k, v := range tmr.AdditionalTags {
if !util.StringSliceContains(ret[k], v) {
ret[k] = append(ret[k], v)
}
}
}
}
}
return ret
}
func (s *listTimersScreen) updateTagOnSelectedTimers(key, val string) {
selected := len(s.selected)
if selected == 0 {
if s.cursor < s.fullFilterList.Size() {
var selTimer *timertxt.Timer
if selTimer, s.err = s.fullFilterList.GetTimer(s.cursor); s.err == nil {
selTimer.AdditionalTags[key] = val
}
}
} else {
for i := range s.selected {
if tmr, err := s.fullFilterList.GetTimer(i); err == nil {
tmr.AdditionalTags[key] = val
}
}
}
// Writes the lists through the program, putting errors in s.err
func (s *listTimersScreen) writeLists() {
var errText string
if err := s.ui.program.WriteTimerList(); err != nil {
if err := s.ui.program.WriteLists(); err != nil {
errText = fmt.Sprintf("Errors Writing Lists (%v)", err)
}
if err := s.ui.program.WriteDoneList(); err != nil {
if len(errText) == 0 {
errText = fmt.Sprintf("Errors Writing Lists (%v)", err)
} else {
errText = fmt.Sprintf("%s (%v)", errText, err)
}
}
if len(errText) > 0 {
s.err = errors.New(errText)
}
}
func (s *listTimersScreen) getSelectedTimerProjects() []string {
var ret []string
func (s *listTimersScreen) getSelectedTimers() []*timertxt.Timer {
var ret []*timertxt.Timer
selected := len(s.selected)
if selected == 0 {
if s.cursor < s.fullFilterList.Size() {
var selTimer *timertxt.Timer
if selTimer, s.err = s.fullFilterList.GetTimer(s.cursor); s.err == nil {
for _, v := range selTimer.Projects {
ret = append(ret, v)
}
ret = append(ret, selTimer)
}
}
} else {
for i := range s.selected {
if tmr, err := s.fullFilterList.GetTimer(i); err == nil {
for _, v := range tmr.Projects {
if !util.StringSliceContains(ret, v) {
ret = append(ret, v)
}
}
ret = append(ret, tmr)
}
}
}
return ret
}
func (s *listTimersScreen) getSelectedTimerTags() map[string][]string {
ret := make(map[string][]string)
sel := s.getSelectedTimers()
for _, tmr := range sel {
for k, v := range tmr.AdditionalTags {
ret[k] = util.AppendStringIfDistinct(ret[k], v)
}
}
return ret
}
func (s *listTimersScreen) updateTagOnSelectedTimers(key, val string) {
sel := s.getSelectedTimers()
for _, tmr := range sel {
tmr.AdditionalTags[key] = val
}
s.writeLists()
}
func (s *listTimersScreen) removeTagOnSelectedTimers(key string) {
sel := s.getSelectedTimers()
for _, tmr := range sel {
if _, ok := tmr.AdditionalTags[key]; ok {
delete(tmr.AdditionalTags, key)
}
}
s.writeLists()
}
func (s *listTimersScreen) getSelectedTimerProjects() []string {
var ret []string
sel := s.getSelectedTimers()
for _, tmr := range sel {
for _, v := range tmr.Contexts {
ret = util.AppendStringIfDistinct(ret, v)
}
}
return ret
}
func (s *listTimersScreen) getSelectedTimerContexts() []string {
var ret []string
selected := len(s.selected)
if selected == 0 {
if s.cursor < s.fullFilterList.Size() {
var selTimer *timertxt.Timer
if selTimer, s.err = s.fullFilterList.GetTimer(s.cursor); s.err == nil {
for _, v := range selTimer.Contexts {
ret = append(ret, v)
}
}
}
} else {
for i := range s.selected {
if tmr, err := s.fullFilterList.GetTimer(i); err == nil {
for _, v := range tmr.Contexts {
if !util.StringSliceContains(ret, v) {
ret = append(ret, v)
}
}
}
sel := s.getSelectedTimers()
for _, tmr := range sel {
for _, v := range tmr.Contexts {
ret = util.AppendStringIfDistinct(ret, v)
}
}
return ret
}
func (s *listTimersScreen) getSelectedTimerDuration() time.Duration {
selected := len(s.selected)
if selected == 0 {
if s.cursor < s.fullFilterList.Size() {
var selTimer *timertxt.Timer
if selTimer, s.err = s.fullFilterList.GetTimer(s.cursor); s.err == nil {
return util.Round(selTimer.Duration())
}
}
}
sel := s.getSelectedTimers()
var ret time.Duration
for i := range s.selected {
if tmr, err := s.fullFilterList.GetTimer(i); err == nil {
ret = util.AddDurations(ret, util.Round(tmr.Duration()))
}
for _, tmr := range sel {
ret = util.AddDurations(ret, util.Round(tmr.Duration()))
}
return ret
}
// Returns true if all selected timers are done
func (s *listTimersScreen) areSelectedInDoneList() bool {
sel := s.getSelectedTimers()
for i := range sel {
if s.timerList.Contains(sel[i]) {
return false
}
}
return true
}
// Return true if all selected timers are from the same list (file)
func (s *listTimersScreen) areSelectedInSameList() bool {
sel := s.getSelectedTimers()
var inActive, inDone int
for i := range sel {
if s.timerList.Contains(sel[i]) {
inActive++
}
if s.doneList.Contains(sel[i]) {
inDone++
}
}
return inActive == 0 || inDone == 0
}

View File

@ -22,11 +22,26 @@ const (
CmdCanceled = ScreenMsgCommand(iota)
CmdSaved
// ListTimers Commands
CmdArchiveTimer
// Goto Screen Commands
CmdGotoSettings
CmdGotoTimerList
)
// Styles
var (
DefaultStyle = wandle.NewStyle(
termbox.RGBToAttribute(uint8(0), uint8(255), uint8(0)),
termbox.RGBToAttribute(uint8(0), uint8(0), uint8(0)),
)
ErrStyle = wandle.NewStyle(
termbox.RGBToAttribute(uint8(255), uint8(0), uint8(0)),
termbox.RGBToAttribute(uint8(0), uint8(0), uint8(0)),
)
)
func RunTUI(p *cli.Program) error {
ui := NewUi(p)
ui.debug = true
@ -71,10 +86,7 @@ func NewUi(p *cli.Program) *Ui {
ui.screens[sId] = s
ui.currScreen = sId
ui.wandle = wandle.NewProgram(s)
ui.wandle.Style(wandle.NewStyle(
termbox.RGBToAttribute(uint8(0), uint8(255), uint8(0)),
termbox.RGBToAttribute(uint8(0), uint8(0), uint8(0)),
))
ui.wandle.Style(DefaultStyle)
return ui
}

View File

@ -138,7 +138,10 @@ func (w *PromptForTagWiddle) Measure() {
}
func (w *PromptForTagWiddle) handleTermboxEvent(msg termbox.Event) wandle.Cmd {
if msg.Key == termbox.KeyEnter {
if msg.Key == termbox.KeyEsc {
w.Done()
return wandle.EmptyCmd
} else if msg.Key == termbox.KeyEnter {
if w.keyInput.IsEditable() {
w.keyInput.SetActive(false)
w.keyInput.SetEditable(false)

View File

@ -441,3 +441,9 @@ func StringSliceContains(sl []string, val string) bool {
}
return false
}
func AppendStringIfDistinct(sl []string, val string) []string {
if !StringSliceContains(sl, val) {
return append(sl, val)
}
return sl
}