# UI Plan 1 Block 04 — Compact Timeline Rail and Task Cards

**Status:** Complete on 2026-06-30.
**Goal:** Render the seeded Today timeline so it visually matches the compact mockup.

---

## Block outcome

After this block, the main screen without modal should closely match `mockups/clean/main_screen_compact.png`.

---

## Chunk 4.1 — Implement timeline geometry

### Tasks

Create `widgets/timeline/timeline_geometry.dart` with a small layout model:

```dart
class TimelineGeometry {
  final TimeOfDay visibleStart;
  final TimeOfDay visibleEnd;
  final double pixelsPerMinute;
  final double minCardHeight;
  double yForMinutesSinceMidnight(int minutes);
  double heightForDuration(int minutes);
}
```

The exact API can differ, but isolate these responsibilities:

- visible time range,
- time label generation,
- y-position from scheduled time,
- card height calculation,
- minimum tappable card height.

### Visual target

- Visible range: 4:00 PM through 8:45 PM.
- Grid rows: 15-minute increments.
- Hour labels/dots prominent.
- Quarter labels muted.
- Cards align to scheduled start rows.
- Use a minimum card height so 10–15 minute items remain readable/tappable, as in the mockup.

### Acceptance criteria

- Geometry can be tested without rendering widgets.
- Geometry is presentation-only and does not alter task schedule state.
- Cards can be positioned from model start/end times.

---

## Chunk 4.2 — Render timeline axis and grid

### Tasks

Create `widgets/timeline/timeline_axis.dart`:

1. Draw or compose the left time labels.
2. Draw the vertical rail and hour dots.
3. Draw horizontal grid lines across content width.
4. Keep grid colors low contrast.

### Implementation options

- Use `CustomPainter` for better performance and visual control.
- Or compose with `Stack`/`Positioned` if simpler and testable.

### Acceptance criteria

- Labels from 4:00 PM to 8:45 PM are visible.
- The rail and grid align with card positions.
- Axis does not know task semantics.

---

## Chunk 4.3 — Implement reward icon painter

### Tasks

Create `widgets/timeline/reward_icon.dart`.

Requirements:

1. Draw solid sparkle/star shapes.
2. Support at least the visual sizes used in:
   - card metadata badge,
   - modal reward tile.
3. Use task accent color or explicit color input.
4. Avoid generic line-art icon if it does not match the mockup.

### Acceptance criteria

- Reward icon is solid, not just outlined.
- Widget tests or painter tests verify it renders for all reward states used in the seed.
- It can be reused by cards and modal.

---

## Chunk 4.4 — Implement five-bar difficulty painter

### Tasks

Create `widgets/timeline/difficulty_bars.dart`.

Requirements:

1. Always reserve five rounded bars.
2. Fill count mapping:
   - not set → 0,
   - very easy → 1,
   - easy → 2,
   - medium → 3,
   - hard → 4,
   - very hard → 5.
3. Filled bars use task/accent color.
4. Unfilled bars use outline only.
5. Bars increase in height from left to right.
6. Medium effort must show exactly three filled bars.

### Acceptance criteria

- A unit/widget test verifies fill count mapping for every difficulty value.
- The modal's `Medium effort` tile uses the same painter as cards.
- There are no six-bar or four-bar variants.

---

## Chunk 4.5 — Implement timeline card component

### Tasks

Create `widgets/timeline/task_timeline_card.dart` that accepts `TimelineCardModel` or equivalent.

Card slots:

1. Left status ring/check.
2. Title.
3. Subtitle/time/duration metadata.
4. Right-side no-op quick action icons for visible cards.
5. Reward icon badge.
6. Difficulty icon badge.

### Visual variants

| Visual kind | Styling |
|---|---|
| flexible | Green border/glow, dark green glass fill, green status ring. |
| required/critical | Pink border/glow, dark pink glass fill, pink status ring. |
| inflexible/appointment | Blue border/glow, dark blue glass fill, blue status ring. |
| free slot | Purple border/glow, dark purple glass fill, dashed/purple status ring, italic `Intentional rest`. |
| completed surprise | Gray border/fill, muted text, check ring, strikethrough title. |

### Behavior

- Entire card gets an `onTap` callback supplied by parent.
- Quick action icons on the card are no-op. They may share the same callback that does nothing or use inert buttons.
- Completed cards may still be selectable, but the required acceptance path only needs planned task selection.

### Acceptance criteria

- Cards render all visual variants from seed data.
- `Clean coffee maker`, `Pay bill`, `Doctor appointment`, `Free Slot`, and completed rows are visible.
- No card action performs a domain command.

---

## Chunk 4.6 — Compose timeline view

### Tasks

Create `widgets/timeline/timeline_view.dart`:

1. Accept `TodayScreenData.cards`.
2. Use `TimelineGeometry` to position cards.
3. Render axis/grid behind cards.
4. Render cards in stable order.
5. Avoid overlap issues by using minimum heights and explicit stacking order.
6. Give task cards stable keys by task id.

### Layout guidance

- Left rail and labels are a fixed-width column.
- Cards begin to the right of the rail.
- Cards should span most of the main content width.
- Right badges/actions align near the card edge.
- Preserve card margins and dense vertical spacing from the mockup.

### Acceptance criteria

- Screen at 1586×992 resembles `main_screen_compact.png`.
- Timeline data still comes from seeded read model.
- The app remains responsive enough not to overflow badly at moderately smaller desktop widths.

---

## Chunk 4.7 — Polish against the clean mockup

### Tasks

1. Run the app locally at a desktop size close to 1586×992.
2. Compare against `mockups/clean/main_screen_compact.png`.
3. Tune:
   - sidebar width,
   - header spacing,
   - banner height,
   - card x/y spacing,
   - card radii,
   - card border opacity,
   - timeline grid contrast,
   - icon sizes,
   - text weights.
4. Keep changes tokenized when possible.

### Acceptance criteria

- Visual differences are intentional and minor.
- No white surfaces appear.
- Icons match reward/difficulty requirements.
- UI still passes tests after tuning.

BREAKPOINT: Stop here and review screenshot before implementing the modal if the visual structure substantially deviates from the mockup.

---

## Block acceptance criteria

- Main compact screen visually matches the clean non-modal mockup closely.
- Timeline rail/grid/cards render from backend-backed seed data.
- Reward icon uses solid sparkles.
- Difficulty icon always uses five bars.
- No task action is wired beyond card selection callback plumbing.

## Validation after block

```sh
cd apps/focus_flow_flutter
flutter analyze
flutter test
```

Add/update widget tests for card labels and difficulty fill counts.

---

## Completed implementation

1. Added timeline geometry, axis, grid, and compact card layout.
2. Rendered all six seeded timeline rows from `TodayScreenData`.
3. Added solid custom reward sparkle rendering.
4. Added five-bar difficulty rendering with fill-count mapping.
5. Added card visual variants for flexible, required, appointment, free slot,
   and completed surprise rows.

## Verification

1. `flutter analyze`: passed, no issues found.
2. `flutter test`: passed, including seeded labels and difficulty fill-count
   coverage.

Visual note: no separate screenshot artifact was checked in; widget tests render
the screen at the mockup-sized 1586x992 surface and assert the required
structure/labels without golden-file brittleness.
