History Section
Displays filtered records with date range and tag filtering.
Structure
- 408-date-range-picker - Preset buttons + From/To pickers
- 409-tag-filter - Tag toggle buttons in FlowLayout
- Total time display
- Share button (opens 410-share-export-sheet)
- Month rows (HistoryMonthRow) - Period > Day > Record hierarchy
Month rows (HistoryMonthRow)
HistorySection emits one List row per month (HistoryMonthRow). Because the
enclosing List reuses cells natively, only on-screen months are built — the
nested SwiftUI Grids below are not lazy, but each is bounded to a single
month. Columns still align across months because every label column has a
fixed width (HistoryColumnSizes).
Level 1: Month Row
- One List row per year-month
- Period label column: vertical text (rotated 90 degrees)
- Contains Level 2 (Days Grid) for the month
Level 2: Days Grid
- Rows grouped by day within each month
- Day label column: large monospaced day number (01-31)
- Contains Level 3 (Records Grid) for each day
Level 3: Records Grid
- Individual record rows with columns:
- Duration (compact format, monospaced, right-aligned)
- Time range (start - end, monospaced)
- Tag (color indicator + name) - always shown
- Comment shown on separate row when present (spans all columns)
Smart Column Hiding (HistoryVisibility)
Columns are intelligently hidden based on filtered data:
- Period column: Hidden if all records are in current month of current year
- Year in period label: Shown only if multiple years or non-current year
- Day column: Hidden if all records are on the same day
The tag column is always shown so records stay identifiable regardless of the active filter.
This reduces visual noise when filtering to specific time periods.
Sticky Labels
Period and day labels use sticky positioning:
- Labels stay visible at top of viewport when scrolling through long lists
- Offset is clamped to keep label within its cell bounds
- Threshold: labels start sticking when cell Y goes below 100pt
Interactions
- Tap row: Expand inline 406-record-editor (spans record columns)
- Context menu: Delete option
- Long press (iOS): Same as context menu
Filtering
Records filtered by:
- Date range (inclusive)
- Selected tags (if any)
- Untagged toggle
Running timers are excluded from history.
Export
Share button opens 410-share-export-sheet with:
- Current date range
- Current tag filters
- All filtered records
Uses snapshot pattern to prevent sheet re-render issues.
Related
- 408-date-range-picker - Date selection
- 409-tag-filter - Tag filtering
- 410-share-export-sheet - Export formats
- 406-record-editor - Inline editing
- 402-ios - Parent view