diff options
author | T <t@tjp.lol> | 2025-08-05 11:37:02 -0600 |
---|---|---|
committer | T <t@tjp.lol> | 2025-08-05 11:37:08 -0600 |
commit | 665bd389a0a1c8adadcaa1122e846cc81f5ead31 (patch) | |
tree | f34f9ec77891308c600c680683f60951599429c3 /internal/tui/types.go | |
parent | dc895cec9d8a84af89ce2501db234dff33c757e2 (diff) |
WIP TUI
Diffstat (limited to 'internal/tui/types.go')
-rw-r--r-- | internal/tui/types.go | 165 |
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 +} |