summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-03 23:16:49 +0200
committerPaul Buetow <paul@buetow.org>2026-03-03 23:16:49 +0200
commit09ee73b50f8500373ee9acb789f863982da6ca13 (patch)
treeae009f7c4efe9ac7bf6bccbfa61d6f5a28ef3eec
parentb64e20fe58da8d9afecda06c2d701096b267cca0 (diff)
Task 352: clean up legacy live package and stale binaries
-rw-r--r--.gitignore4
-rw-r--r--internal/cli/timer.go8
-rw-r--r--internal/live/live.go181
-rw-r--r--internal/tui/timer.go2
-rw-r--r--internal/tui/timer_test.go12
5 files changed, 18 insertions, 189 deletions
diff --git a/.gitignore b/.gitignore
index 8202e98..2007bca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
-timr
+/timr
+/main
+/cmd/timr/timr
diff --git a/internal/cli/timer.go b/internal/cli/timer.go
index 86c958f..6c344e5 100644
--- a/internal/cli/timer.go
+++ b/internal/cli/timer.go
@@ -9,8 +9,8 @@ import (
"time"
"codeberg.org/snonux/timr/internal/ascii"
- "codeberg.org/snonux/timr/internal/live"
timrTimer "codeberg.org/snonux/timr/internal/timer"
+ tuiapp "codeberg.org/snonux/timr/internal/tui"
"codeberg.org/snonux/timr/internal/worktime"
tea "github.com/charmbracelet/bubbletea"
"github.com/spf13/cobra"
@@ -198,7 +198,11 @@ func newTimerLiveCmd() *cobra.Command {
selectedFont = ascii.AllFonts[rand.IntN(len(ascii.AllFonts))]
}
- program := tea.NewProgram(live.NewModel(selectedFont))
+ model, err := tuiapp.NewTimerModel(selectedFont, CurrentConfig())
+ if err != nil {
+ return err
+ }
+ program := tea.NewProgram(model)
return program.Start()
},
}
diff --git a/internal/live/live.go b/internal/live/live.go
deleted file mode 100644
index 9590622..0000000
--- a/internal/live/live.go
+++ /dev/null
@@ -1,181 +0,0 @@
-package live
-
-import (
- "fmt"
- "time"
-
- "github.com/charmbracelet/bubbletea"
- "github.com/charmbracelet/lipgloss"
- "github.com/common-nighthawk/go-figure"
- "codeberg.org/snonux/timr/internal/ascii"
- timrTimer "codeberg.org/snonux/timr/internal/timer"
-)
-
-type tickMsg time.Time
-
-func tick() tea.Cmd {
- return tea.Tick(time.Second, func(t time.Time) tea.Msg {
- return tickMsg(t)
- })
-}
-
-// Model is the Bubble Tea model for the live timer view.
-type Model struct {
- state timrTimer.State
- quitting bool
- helpStyle lipgloss.Style
- timerStyle lipgloss.Style
- statusStyle lipgloss.Style
- width int
- height int
- font string // Font selection: "doom" for figlet, or ASCII font names
- fontIndex int // Current index in the AllFonts slice for cycling
-}
-
-// NewModel creates a new Model with the specified font.
-// The font parameter can be "doom" for the original figlet font,
-// or one of the ASCII font names: "mono12", "rebel", "ansi", "ansiShadow".
-func NewModel(font string) Model {
- state, err := timrTimer.LoadState()
- if err != nil {
- panic(err) // Or handle more gracefully
- }
-
- // Find the current font index in AllFonts for cycling support
- fontIndex := 0
- for i, f := range ascii.AllFonts {
- if f == font {
- fontIndex = i
- break
- }
- }
-
- return Model{
- state: state,
- helpStyle: lipgloss.NewStyle().Faint(true),
- timerStyle: lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("#00BFFF")),
- statusStyle: lipgloss.NewStyle().Italic(true),
- font: font,
- fontIndex: fontIndex,
- }
-}
-
-// Init is the first function that will be called.
-func (m Model) Init() tea.Cmd {
- if m.state.Running {
- return tick()
- }
- return nil
-}
-
-// Update is called when a message is received.
-func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
- switch msg := msg.(type) {
- case tea.WindowSizeMsg:
- m.width = msg.Width
- m.height = msg.Height
- return m, nil
- case tickMsg:
- if !m.state.Running {
- return m, nil
- }
- return m, tick()
-
- case tea.KeyMsg:
- switch msg.String() {
- case "q", "ctrl+c":
- m.quitting = true
- if err := m.state.Save(); err != nil {
- // handle error
- }
- return m, tea.Quit
-
- case "s":
- if m.state.Running {
- // Stop the timer
- m.state.ElapsedTime += time.Since(m.state.StartTime)
- m.state.Running = false
- return m, nil // Stop ticking
- } else {
- // Start the timer
- m.state.Running = true
- m.state.StartTime = time.Now()
- return m, tick() // Start ticking
- }
-
- case "r":
- // Reset the timer
- m.state = timrTimer.State{}
- if _, err := timrTimer.ResetTimer(); err != nil {
- // handle error
- }
- return m, nil // Stop ticking
-
- case "f":
- // Cycle to the next font
- m.fontIndex = (m.fontIndex + 1) % len(ascii.AllFonts)
- m.font = ascii.AllFonts[m.fontIndex]
- return m, nil
- }
- }
-
- return m, nil
-}
-
-// View renders the model's state to the terminal.
-// Supports both figlet-style fonts (doom) and large ASCII art fonts (mono12, rebel, ansi, ansiShadow).
-func (m Model) View() string {
- if m.quitting {
- return ""
- }
-
- var currentSession time.Duration
- if m.state.Running {
- currentSession = time.Since(m.state.StartTime)
- }
-
- totalElapsed := (m.state.ElapsedTime + currentSession).Round(time.Second)
-
- status := "Paused"
- if m.state.Running {
- status = "Running"
- }
-
- // Render timer based on selected font
- var timerStr string
- if m.font == "doom" {
- // Use original figlet font
- figure := figure.NewFigure(totalElapsed.String(), "doom", true)
- timerStr = m.timerStyle.Render(figure.String())
- } else {
- // Use large ASCII art fonts
- font := ascii.GetFont(m.font)
- // Format time as HH:MM:SS for better ASCII display
- hours := int(totalElapsed.Hours())
- minutes := int(totalElapsed.Minutes()) % 60
- seconds := int(totalElapsed.Seconds()) % 60
- timeStr := fmt.Sprintf("%02d:%02d:%02d", hours, minutes, seconds)
- asciiTime := ascii.RenderNumber(timeStr, font)
- timerStr = m.timerStyle.Render(asciiTime)
- }
-
- statusStr := m.statusStyle.Render(status)
- fontInfo := m.helpStyle.Render(fmt.Sprintf("Font: %s", m.font))
- helpStr := m.helpStyle.Render("q: quit, s: start/stop, r: reset, f: change font")
-
- // Centering
- return lipgloss.Place(
- m.width,
- m.height,
- lipgloss.Center,
- lipgloss.Center,
- lipgloss.JoinVertical(
- lipgloss.Center,
- timerStr,
- statusStr,
- "", // spacer
- fontInfo,
- helpStr,
- ),
- )
-}
diff --git a/internal/tui/timer.go b/internal/tui/timer.go
index 4a3ce02..4ed3c5f 100644
--- a/internal/tui/timer.go
+++ b/internal/tui/timer.go
@@ -93,7 +93,7 @@ func (m TimerModel) Init() tea.Cmd {
}
// Update handles timer screen updates.
-func (m TimerModel) Update(msg tea.Msg) (TimerModel, tea.Cmd) {
+func (m TimerModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.width = msg.Width
diff --git a/internal/tui/timer_test.go b/internal/tui/timer_test.go
index 5c6ac51..4c420ce 100644
--- a/internal/tui/timer_test.go
+++ b/internal/tui/timer_test.go
@@ -27,12 +27,14 @@ func TestTimerModelToggleWorkLogin(t *testing.T) {
t.Fatal("work integration should be enabled")
}
- model, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'l'}})
+ modelAny, _ := model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'l'}})
+ model = modelAny.(TimerModel)
if !model.workLoggedIn {
t.Fatal("work should be logged in after first l")
}
- model, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'l'}})
+ modelAny, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'l'}})
+ model = modelAny.(TimerModel)
if model.workLoggedIn {
t.Fatal("work should be logged out after second l")
}
@@ -55,7 +57,8 @@ func TestTimerModelFontCycling(t *testing.T) {
}
originalFont := model.font
- model, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'f'}})
+ modelAny, _ := model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'f'}})
+ model = modelAny.(TimerModel)
if model.font == originalFont {
t.Fatalf("font did not change after f: %q", model.font)
}
@@ -72,7 +75,8 @@ func TestTimerModelWorkToggleWhenDisabled(t *testing.T) {
t.Fatalf("NewTimerModel() error = %v", err)
}
- model, _ = model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'l'}})
+ modelAny, _ := model.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune{'l'}})
+ model = modelAny.(TimerModel)
if model.workStatus != "work integration disabled" {
t.Fatalf("workStatus = %q, want work integration disabled", model.workStatus)
}