<!-- SPDX-FileCopyrightText: 2026 FocusFlow contributors -->
<!-- SPDX-License-Identifier: AGPL-3.0-only -->


# Task Pushing 01 Block 04 — Push Menu Destinations

**Status:** Complete.
**Goal:** Open a destination menu from the Push button and route each choice to a
callback.

---

## Block outcome

After this block, clicking `Push` opens a menu with the three requested choices.
The choices may call stubbed/controller callbacks until Block 05 wires real
commands.

## Implementation notes

1. The Push button opens a compact popup menu with exactly `Push to next`,
   `Push to tomorrow`, and `Push to backlog`.
2. Destination-specific callbacks are threaded from the home scaffold through
   `TimelineView` to `TaskTimelineCard`.
3. The card prevents duplicate destination submission while a push callback is
   still running.
4. Widget tests cover menu labels, destination callbacks, outside-click
   dismissal, and one-shot running behavior.

---

## Chunk 4.1 — Add destination menu UI

### Tasks

1. Add a small menu anchored to the Push button.
2. Include exactly these visible labels:
   - `Push to next`,
   - `Push to tomorrow`,
   - `Push to backlog`.
3. Keep menu styling consistent with the dark compact UI.
4. Use enough spacing for desktop pointer targets without making the card feel
   heavy.
5. Ensure the menu can open above/below the card depending on available space.

### Acceptance criteria

- Menu opens from the Push button.
- Menu contains all three requested labels.
- Menu does not obscure the button in a way that prevents closing/reopening.

---

## Chunk 4.2 — Add destination callback surface

### Tasks

1. Add callback signatures to the card/timeline path for:
   - push to next,
   - push to tomorrow,
   - push to backlog.
2. Pass task id and expected update metadata required for stale-write protection.
3. Keep callbacks nullable only for tests/previews that intentionally disable
   command wiring.
4. Do not pass raw domain `Task` objects into leaf widgets unless existing
   architecture already does.

### Acceptance criteria

- Each menu item calls the correct destination callback.
- Callback payload includes enough task identity/update metadata to run a safe
  command.
- Widgets do not know command-use-case class names.

---

## Chunk 4.3 — Handle menu dismissal and command-running state

### Tasks

1. Close the menu when a destination is selected.
2. Close the menu on outside click or Escape.
3. Decide whether command-running state disables menu re-entry globally or per
   card.
4. Prevent double-submission if the user rapidly clicks a destination twice.
5. Show existing command failure/success UI if available; do not add a new
   notification framework in this plan.

### Acceptance criteria

- Destination selection is one-shot until the command result returns.
- Cancel/dismiss performs no task mutation.
- Existing command state surfaces are reused.

---

## Chunk 4.4 — Add menu widget tests

### Required tests

1. Tap Push opens menu.
2. Menu has exactly the three destination labels.
3. Tapping each item invokes the matching callback.
4. Escape/outside click closes menu without callback.
5. Rapid double tap does not invoke duplicate commands if command-running state
   is available at this layer.

### Acceptance criteria

- Destination menu behavior is covered before backend wiring.
- Tests do not require a live scheduler engine.

---

## Block acceptance criteria

- Push menu appears and dismisses correctly.
- Each destination has a distinct callback path.
- No backend scheduling logic is introduced into widgets.

## Validation after block

```sh
cd apps/focus_flow_flutter
flutter test test/widgets/timeline
```
