9.1 KiB
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.dartlib/screens/tasks/tasks_list_screen.dartlib/screens/projects/project_list_screen.dartlib/screens/chat/conversations_list_screen.dartlib/screens/quick_capture/quick_capture_screen.dart
Screens kept:
lib/screens/notes/note_detail_screen.dartlib/screens/notes/note_edit_screen.dartlib/screens/tasks/task_edit_screen.dartlib/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_fontstopubspec.yaml headlineMedium,titleLarge,titleMedium→GoogleFonts.fraunces()- Body styles → system default (unchanged)
Buttons & Cards
- Primary action buttons:
BoxDecorationwithLinearGradient(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
assistantmessage from today's conversation - Truncated to 5 lines by default;
[Show more]expands withAnimatedSize - If no briefing exists yet: "No briefing yet today" placeholder + "Generate now" button
Conversation
- Message bubbles reuse the same widget used in
ChatScreen; extracted tolib/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/triggerwith{"slot": "compilation"} - Shows
CircularProgressIndicatorin the AppBar while in-flight - Reloads conversation on completion
New Files
lib/screens/briefing/briefing_screen.dartlib/screens/briefing/briefing_history_screen.dartlib/widgets/briefing_digest_card.dartlib/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,messageslib/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 → doneviaPATCH /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
AnimatedContainersearch 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.dartlib/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
LinearProgressIndicatorin indigo animates below the capture bar
Implementation
- New
lib/providers/capture_work_queue_provider.dart—CaptureWorkQueueNotifier(in-memoryList<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.dartlib/screens/briefing/briefing_screen.dartlib/screens/briefing/briefing_history_screen.dartlib/screens/library/library_screen.dartlib/widgets/briefing_digest_card.dartlib/widgets/chat_message_bubble.dartlib/widgets/library_item_card.dartlib/data/api/briefing_api.dartlib/data/models/briefing_conversation.dartlib/providers/briefing_provider.dartlib/providers/capture_work_queue_provider.dart
Modified:
lib/app.dart— new 3-tab shell, new routes, updated_QuickCaptureBarlib/main.dart— importtheme.dartlib/screens/chat/chat_screen.dart— extract bubble widgetpubspec.yaml— addgoogle_fonts
Deleted:
lib/screens/notes/notes_list_screen.dartlib/screens/tasks/tasks_list_screen.dartlib/screens/projects/project_list_screen.dartlib/screens/chat/conversations_list_screen.dartlib/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