Shell: move Projects/News/Calendar into ShellRoute so the NavigationRail persists across all screens. Show all 6 nav destinations on tablet instead of 3+More overflow. Phone bottom nav unchanged. Chat: master-detail layout on tablet — conversations list (320px) with inline chat panel. Tapping a conversation updates state instead of pushing a new route. Knowledge: responsive grid (2 cols portrait, 3 cols landscape) with card layout showing icon, title, body preview, and tags. Fix snippet data — read json['snippet'] which the API actually sends. Bump snippet length from 120 to 200 chars. Tasks now show description as snippet. News: responsive grid with the same breakpoints. Larger snippet (5 lines) in grid mode via snippetMaxLines parameter. Briefing: centered reading column (maxWidth 700) on wide screens, matching the web UI layout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fabled — Android App
Native Android client for FabledAssistant, a self-hosted AI second-brain and productivity assistant.
Features
- Daily Briefing — the primary screen; opens on launch. Shows your AI-compiled morning digest (tasks, calendar, weather, RSS) with a full conversation you can reply to inline. Refresh manually or browse past briefings from the overflow menu.
- Quick Capture — always-visible input bar above all tabs. Type a note or task and submit; multiple captures queue sequentially so the input is never blocked. Falls back to offline persistence when the server is unreachable.
- Knowledge — unified browsable feed of notes, people, places, lists, and tasks across six filter tabs. Tag filters, inline search (debounced), and two-tier pagination (ID list → batch hydration). Tasks load from
/api/tasksdirectly and are fully integrated with the knowledge feed. - Chat — streaming AI conversations with real-time SSE display, including live tool-use status notifications (e.g. "Calling create_note…"). Tap + to start a new conversation or open an existing one.
- Calendar — month strip + daily agenda view backed by the server's internal event store. Full event CRUD with a modal form: title, all-day toggle, start/end date+time pickers, repeat (None/Daily/Weekly/Monthly/Yearly), description, location, and colour chips. Custom RRULE strings are preserved read-only.
- News — RSS article feed with per-feed filtering and reactions. Tap "Discuss" to open any article in a new chat conversation.
- Projects — browse and edit projects; tap a project to see its milestone-grouped task list.
- Voice I/O — tap the microphone in the capture bar or chat to dictate. Server-side STT transcribes audio; TTS reads assistant replies aloud in voice mode.
- Note & task editing — full Markdown editor for notes, task editor with due date, priority, project, and milestone assignment.
- OAuth / SSO — authenticates via your server's OIDC provider; local username/password login also supported if enabled server-side.
- Session persistence — stays logged in across restarts via a persistent cookie jar.
- Auto-refresh — data refreshes automatically when the app returns to the foreground (throttled to once per 5 minutes) and when switching between shell tabs.
- Auto-update — checks your Forgejo releases on launch and prompts to download and install new APKs in-app.
Requirements
- A running FabledAssistant server (self-hosted)
- Android 5.0+ (API 21)
Getting Started
Prerequisites
- Flutter 3.x SDK
- Android Studio (for Android SDK and emulator)
- JDK 17
Setup
flutter pub get
flutter run
On first launch, enter your FabledAssistant server URL (e.g. https://fabled.example.com) and sign in.
Architecture
lib/
├── main.dart # Entry point; resolves async deps before runApp
├── app.dart # GoRouter + auth guards + 3-tab shell + auto-refresh
├── core/
│ ├── constants.dart # Route name constants
│ ├── exceptions.dart # AppException hierarchy
│ └── theme.dart # Custom slate-indigo ColorScheme + Fraunces typography
├── data/
│ ├── api/ # Dio HTTP layer (one class per resource)
│ │ ├── chat_api.dart # SSE streaming; typed ChatStreamEvent (text/status)
│ │ ├── events_api.dart # Calendar event CRUD
│ │ ├── knowledge_api.dart # Two-tier paginated knowledge feed
│ │ ├── news_api.dart # RSS feed + reactions
│ │ └── voice_api.dart # STT + TTS endpoints
│ ├── models/ # Plain Dart models with fromJson/toJson
│ │ ├── calendar_event.dart # CalendarEvent + dateOnly() helper
│ │ ├── knowledge_item.dart # KnowledgeItem (notes/tasks unified)
│ │ └── message.dart # Chat message with streaming status
│ └── repositories/ # Thin wrappers over API classes
├── providers/ # Riverpod providers (state + dependency wiring)
│ ├── briefing_provider.dart # Today's briefing — optimistic UI, SSE, polling
│ ├── calendar_provider.dart # CalendarNotifier: month navigation + event CRUD
│ ├── chat_provider.dart # Conversations + streaming messages + status
│ ├── knowledge_provider.dart # Two-tier pagination; delegates tasks to TasksApi
│ ├── news_provider.dart # NewsNotifier + FeedsNotifier
│ └── capture_work_queue_provider.dart # Sequential in-memory capture queue
├── screens/
│ ├── briefing/ # BriefingScreen + BriefingHistoryScreen
│ ├── calendar/ # CalendarScreen (TableCalendar) + EventFormSheet
│ ├── chat/ # ConversationsTabScreen + ChatScreen
│ ├── knowledge/ # KnowledgeScreen (6-tab feed + search + tag filters)
│ ├── library/ # ProjectTasksScreen (milestone-grouped task list)
│ ├── news/ # NewsScreen (feed filter + reactions + discuss)
│ ├── notes/ # NoteDetailScreen + NoteEditScreen
│ ├── projects/ # ProjectsScreen + ProjectEditScreen
│ ├── tasks/ # TaskEditScreen
│ └── settings/ auth/ setup/ splash/
└── widgets/
├── chat_message_bubble.dart # Shared bubble (Chat + Briefing); shows tool status
├── knowledge_item_card.dart # Card for notes, people, places, lists, tasks
├── news_card.dart # RSS article card with reactions
└── voice_mic_button.dart # Animated mic button (capture bar + chat)
Key packages: flutter_riverpod, go_router, dio + cookie_jar, google_fonts, flutter_markdown_plus, table_calendar, record, just_audio
Building a Release APK
flutter build apk --release
The APK will be at build/app/outputs/flutter-apk/app-release.apk.
CI / CD
CI and build are defined in a single workflow (.forgejo/workflows/ci.yml) running on the shared py3.12-node22 act runner with the ghcr.io/cirruslabs/flutter:stable container.
| Trigger | Analyze + Test | Build APK | Release |
|---|---|---|---|
| PR | ✓ | — | — |
Push dev |
✓ | ✓ (artifact fabledapp-dev-<sha>) |
— |
Push main |
✓ | — | — |
Tag v* |
✓ | ✓ (artifact fabledapp-<sha>) |
✓ Forgejo Release + APK attached |
The build job has needs: [analyze] — a failed analyze or test blocks the APK build.
To cut a release:
git tag v26.04.06 && git push origin v26.04.06
Requires a RELEASE_TOKEN secret (Forgejo PAT with write:repository scope) set in repo Settings → Secrets → Actions.