From 3bd9c64477f9412818b5e668bb045e45dd9ffe05 Mon Sep 17 00:00:00 2001 From: bvandeusen Date: Wed, 11 Mar 2026 22:18:59 -0400 Subject: [PATCH] docs: fabled app overhaul design spec --- .../2026-03-11-fabled-app-overhaul-design.md | 253 ++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-11-fabled-app-overhaul-design.md diff --git a/docs/superpowers/specs/2026-03-11-fabled-app-overhaul-design.md b/docs/superpowers/specs/2026-03-11-fabled-app-overhaul-design.md new file mode 100644 index 0000000..1f72b80 --- /dev/null +++ b/docs/superpowers/specs/2026-03-11-fabled-app-overhaul-design.md @@ -0,0 +1,253 @@ +# Fabled App Overhaul — Design Spec + +**Date:** 2026-03-11 +**Project:** `/home/bvandeusen/Nextcloud/Projects/fabled_app` + +## Goal + +Reposition the Flutter Android app from a general-purpose mirror of the web app into a focused mobile companion: the Daily Briefing is the primary experience, Quick Capture is the secondary utility, and Notes/Tasks/Projects are a browsable library — secondary to both. + +--- + +## Navigation & Shell + +Three-tab shell replacing the current four-tab (Notes · Tasks · Projects · Chat) structure. + +| Tab | Icon | Screen | Route | +|-----|------|--------|-------| +| Briefing | `Icons.wb_sunny_outlined` / `Icons.wb_sunny` | `BriefingScreen` | `/briefing` | +| Library | `Icons.library_books_outlined` / `Icons.library_books` | `LibraryScreen` | `/library` | +| Chat | `Icons.chat_bubble_outline` / `Icons.chat_bubble` | `ConversationsListScreen` (inline) | `/conversations` | + +The `_QuickCaptureBar` remains pinned above the shell on all three tabs. The settings icon stays in the capture bar row. + +**Briefing is the initial route** — the app opens directly to the briefing tab on every launch. + +**Wide layout (≥ 600dp):** `NavigationRail` on the left (as today), same 3 destinations. + +### Dead Code Removed + +**Screens deleted:** +- `lib/screens/notes/notes_list_screen.dart` +- `lib/screens/tasks/tasks_list_screen.dart` +- `lib/screens/projects/project_list_screen.dart` +- `lib/screens/chat/conversations_list_screen.dart` +- `lib/screens/quick_capture/quick_capture_screen.dart` + +**Screens kept:** +- `lib/screens/notes/note_detail_screen.dart` +- `lib/screens/notes/note_edit_screen.dart` +- `lib/screens/tasks/task_edit_screen.dart` +- `lib/screens/chat/chat_screen.dart` +- All auth, settings, setup, splash screens + +--- + +## Theme + +Custom `ColorScheme` matching the main web app's "Illuminated Transcript" palette, in `lib/core/theme.dart`. System light/dark preference respected. + +### Dark theme +| Token | Value | +|-------|-------| +| `background` | `#111113` | +| `surface` | `#18181c` | +| `primary` | `#6366f1` | +| `onSurface` | `#e8e8f0` | +| `onSurfaceVariant` (muted) | `#8888a8` | + +### Light theme +| Token | Value | +|-------|-------| +| `background` | `#f4f4f8` | +| `surface` | `#ffffff` | +| `primary` | `#4f46e5` | +| `onSurface` | `#18181c` | +| `onSurfaceVariant` (muted) | `#6b6b88` | + +### Typography +- Add `google_fonts` to `pubspec.yaml` +- `headlineMedium`, `titleLarge`, `titleMedium` → `GoogleFonts.fraunces()` +- Body styles → system default (unchanged) + +### Buttons & Cards +- Primary action buttons: `BoxDecoration` with `LinearGradient(135°, #6366f1, #4f46e5)`; applied to send buttons in capture bar and briefing reply bar +- Cards: `borderRadius: 14`, subtle elevation shadow, no explicit border + +--- + +## BriefingScreen + +**File:** `lib/screens/briefing/briefing_screen.dart` + +The app's primary screen. Opens on launch. + +### Layout + +``` +AppBar: + title: "Briefing" (Fraunces) + subtitle: today's date ("Wednesday, March 11") + actions: [↻ refresh button] + +Body (scrollable column): + ┌─ DigestCard ──────────────────────┐ + │ ☀ Good morning — Mar 11 │ + │ [first assistant message, │ + │ truncated to 5 lines] │ + │ [Show more ↓] │ + └───────────────────────────────────┘ + + ─── Conversation ─── + + [scrollable message list] + [streaming bubble while generating] + +Bottom pinned: + [ Reply to your briefing… ] [➤] +``` + +### Digest Card +- Extracted widget: `lib/widgets/briefing_digest_card.dart` +- Shows the content of the first `assistant` message from today's conversation +- Truncated to 5 lines by default; `[Show more]` expands with `AnimatedSize` +- If no briefing exists yet: "No briefing yet today" placeholder + "Generate now" button + +### Conversation +- Message bubbles reuse the same widget used in `ChatScreen`; extracted to `lib/widgets/chat_message_bubble.dart` (shared between both screens) +- User messages: right-aligned, primary colour container +- Assistant messages: left-aligned, surface container with left accent border (indigo, 2dp) +- Streaming: a streaming bubble appears at the bottom of the list while SSE is active + +### Reply Bar +- Always visible (pinned to bottom, above system nav bar) +- Send button: indigo gradient, disabled when input is empty or streaming +- Submitting a reply uses the existing SSE chat endpoint with today's briefing `conversation_id` + +### Overflow Menu (`···`) +- "View past briefings" → pushes `BriefingHistoryScreen` (simple date list, read-only — no reply bar) + +### Refresh Button +- Calls `POST /api/briefing/trigger` with `{"slot": "compilation"}` +- Shows `CircularProgressIndicator` in the AppBar while in-flight +- Reloads conversation on completion + +### New Files +- `lib/screens/briefing/briefing_screen.dart` +- `lib/screens/briefing/briefing_history_screen.dart` +- `lib/widgets/briefing_digest_card.dart` +- `lib/widgets/chat_message_bubble.dart` (extracted from ChatScreen) +- `lib/data/api/briefing_api.dart` — `getToday()`, `getMessages(id)`, `triggerSlot(slot)` +- `lib/data/models/briefing_conversation.dart` — `id`, `briefingDate`, `title`, `messages` +- `lib/providers/briefing_provider.dart` — `briefingTodayProvider` (AsyncNotifier) + +--- + +## LibraryScreen + +**File:** `lib/screens/library/library_screen.dart` + +Unified browsing screen for notes, tasks, and projects. + +### Layout + +``` +AppBar: + title: "Library" + actions: [🔍 search icon → expands inline search bar] + +Filter pills (scrollable horizontal row): + [All] [Notes] [Tasks] [Projects] + +Content: + Unified list sorted by updated_at desc + Each item: LibraryItemCard + +FAB: + [+] → bottom sheet: "New note" | "New task" +``` + +### Filter Pills +| Pill | Content | Extra controls | +|------|---------|----------------| +| All | Notes + tasks interleaved | — | +| Notes | Notes only | — | +| Tasks | Tasks only | Secondary status row: Todo · In Progress · Done · All | +| Projects | Project cards | — | + +### Item Cards (`lib/widgets/library_item_card.dart`) +- **Note:** title (Fraunces medium), 1-line body snippet, tag chips, relative timestamp +- **Task:** status checkbox (tappable → cycles `todo → in_progress → done` via `PATCH /api/tasks/:id/status`), title, due date, priority dot (high = red, medium = amber) +- **Project:** left colour strip matching project colour, title, active task count, milestone progress bar + +### Search +- Tapping 🔍 slides an `AnimatedContainer` search bar into the AppBar +- Searches title + body across notes and tasks via `GET /api/notes?q=` (respects active filter pill) +- Dismisses with Escape / back gesture + +### FAB +- Bottom sheet with two large tap targets: "New note" → `NoteEditScreen`, "New task" → `TaskEditScreen` + +### New Files +- `lib/screens/library/library_screen.dart` +- `lib/widgets/library_item_card.dart` + +--- + +## Quick Capture Queue + +The `_QuickCaptureBar` in `app.dart` is updated to support multiple in-flight captures queued sequentially. + +### Behaviour +- Input **never disables** while the worker is active (only disables on offline — existing behaviour) +- Submitting appends text to the work queue; the worker drains it one item at a time +- Each completion fires a snackbar (`"Note created: …"`) +- Queue depth > 0: prefix icon shows a badge `⋯ N` +- Worker active: a 2dp `LinearProgressIndicator` in indigo animates below the capture bar + +### Implementation +- New `lib/providers/capture_work_queue_provider.dart` — `CaptureWorkQueueNotifier` (in-memory `List` + async drain loop) +- Separate from the existing `captureQueueProvider` (which handles offline persistence); the two queues are distinct: + - **Work queue:** in-memory, drains sequentially while online + - **Offline queue:** persisted to SharedPreferences, drained on reconnect +- Network errors during work queue drain fall through to offline queue (existing logic) + +--- + +## Files Created / Modified Summary + +**New:** +- `lib/core/theme.dart` +- `lib/screens/briefing/briefing_screen.dart` +- `lib/screens/briefing/briefing_history_screen.dart` +- `lib/screens/library/library_screen.dart` +- `lib/widgets/briefing_digest_card.dart` +- `lib/widgets/chat_message_bubble.dart` +- `lib/widgets/library_item_card.dart` +- `lib/data/api/briefing_api.dart` +- `lib/data/models/briefing_conversation.dart` +- `lib/providers/briefing_provider.dart` +- `lib/providers/capture_work_queue_provider.dart` + +**Modified:** +- `lib/app.dart` — new 3-tab shell, new routes, updated `_QuickCaptureBar` +- `lib/main.dart` — import `theme.dart` +- `lib/screens/chat/chat_screen.dart` — extract bubble widget +- `pubspec.yaml` — add `google_fonts` + +**Deleted:** +- `lib/screens/notes/notes_list_screen.dart` +- `lib/screens/tasks/tasks_list_screen.dart` +- `lib/screens/projects/project_list_screen.dart` +- `lib/screens/chat/conversations_list_screen.dart` +- `lib/screens/quick_capture/quick_capture_screen.dart` + +--- + +## Out of Scope + +- iOS support — Android only, as today +- Workspace view — web-only feature +- Graph view — web-only feature +- Note editing from Library (tap → NoteDetailScreen → edit button, as today) +- Push notification handling in-app — handled by the OS notification tray