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