Fetch server-side settings on app launch via new serverSettingsProvider. Hide News from bottom sheet and NavigationRail when RSS is disabled. Skip news card rendering in briefing messages when disabled. Refactor tab navigation to use dynamic tabs list and route-based refresh. 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.