summaryrefslogtreecommitdiff
path: root/internal/tui/types.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/tui/types.go')
-rw-r--r--internal/tui/types.go165
1 files changed, 165 insertions, 0 deletions
diff --git a/internal/tui/types.go b/internal/tui/types.go
new file mode 100644
index 0000000..2fcf55c
--- /dev/null
+++ b/internal/tui/types.go
@@ -0,0 +1,165 @@
+package tui
+
+import (
+ "context"
+ "time"
+
+ "punchcard/internal/queries"
+)
+
+// BoxType represents the different boxes that can be selected
+type BoxType int
+
+const (
+ TimerBox BoxType = iota
+ ClientsProjectsBox
+ HistoryBox
+)
+
+func (b BoxType) String() string {
+ switch b {
+ case TimerBox:
+ return "Timer"
+ case ClientsProjectsBox:
+ return "Clients & Projects"
+ case HistoryBox:
+ return "History"
+ default:
+ return "Unknown"
+ }
+}
+
+// AppModel is the main model for the TUI application
+type AppModel struct {
+ ctx context.Context
+ queries *queries.Queries
+ selectedBox BoxType
+ timerBoxModel TimerBoxModel
+ clientsProjectsModel ClientsProjectsModel
+ historyBoxModel HistoryBoxModel
+ width int
+ height int
+ // Cached data to avoid DB queries in View()
+ stats TimeStats
+ runningTimerStart *time.Time // UTC timestamp when timer started, nil if not active
+
+ // Modal state
+ showModal bool
+ modalType ModalType
+ textInputModel TextInputModel
+}
+
+// ModalType represents different types of modals
+type ModalType int
+
+const (
+ ModalDescribeTimer ModalType = iota
+)
+
+// TextInputModel represents a text input modal
+type TextInputModel struct {
+ prompt string
+ value string
+ placeholder string
+ cursorPos int
+}
+
+// TimerInfo holds information about the current timer state
+type TimerInfo struct {
+ IsActive bool
+ Duration time.Duration
+ StartTime time.Time
+ ClientName string
+ ProjectName string
+ Description string
+ BillableRate *float64
+}
+
+// TimeStats holds time statistics for display
+type TimeStats struct {
+ TodayTotal time.Duration
+ WeekTotal time.Duration
+}
+
+// TickMsg is sent every second to update the timer
+type TickMsg time.Time
+
+// KeyBinding represents the available key bindings for a view
+type KeyBinding struct {
+ Key string
+ Description string
+}
+
+// HistoryViewLevel represents the level of detail in history view
+type HistoryViewLevel int
+
+const (
+ HistoryLevelSummary HistoryViewLevel = iota // Level 1: Date/project summaries
+ HistoryLevelDetails // Level 2: Individual entries
+)
+
+// Box models for the three main components
+type TimerBoxModel struct {
+ timerInfo TimerInfo
+}
+
+type ClientsProjectsModel struct {
+ clients []queries.Client
+ projects []queries.ListAllProjectsRow
+ selectedIndex int // Index of selected row (client or project)
+ selectedIsClient bool // True if selected row is a client, false if project
+}
+
+type HistoryBoxModel struct {
+ entries []queries.TimeEntry
+ clients []queries.Client // For looking up client names
+ projects []queries.ListAllProjectsRow // For looking up project names
+ viewLevel HistoryViewLevel
+ selectedIndex int // Index of selected row
+ // Cached running timer data to avoid recalculating in View()
+ runningTimerStart *time.Time // UTC timestamp when timer started, nil if not active
+
+ // Summary view data (level 1)
+ summaryItems []HistorySummaryItem
+
+ // Details view data (level 2)
+ detailsEntries []queries.TimeEntry
+ selectedSummaryItem *HistorySummaryItem // Which summary item we drilled down from
+}
+
+// HistorySummaryItem represents a date + client/project combination with total duration
+type HistorySummaryItem struct {
+ Date time.Time
+ ClientID int64
+ ClientName string
+ ProjectID *int64 // nil if no project
+ ProjectName *string // nil if no project
+ TotalDuration time.Duration
+ EntryCount int
+}
+
+// HistoryDisplayItem represents an item in the history view (either date header or summary/detail item)
+type HistoryDisplayItem struct {
+ Type HistoryDisplayItemType
+ DateHeader *string // Set if Type is DateHeader
+ Summary *HistorySummaryItem // Set if Type is Summary
+ Entry *queries.TimeEntry // Set if Type is Entry
+ IsSelectable bool
+}
+
+type HistoryDisplayItemType int
+
+const (
+ HistoryItemDateHeader HistoryDisplayItemType = iota
+ HistoryItemSummary
+ HistoryItemEntry
+)
+
+// ProjectsDisplayItem represents an item in the projects display order (either client or project)
+type ProjectsDisplayItem struct {
+ IsClient bool
+ ClientIndex int // Index in m.clients
+ ProjectIndex int // Index in m.projects, only used when IsClient=false
+ Client *queries.Client
+ Project *queries.ListAllProjectsRow
+}