docs: fabled app overhaul design spec
This commit is contained in:
@@ -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<String>` + 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
|
||||||
Reference in New Issue
Block a user