Overview
WhimAway is an AI-assisted, local-first Android task manager that supports image, voice, and manual task creation.
The UI emits typed actions to a central ViewModel, updates a single UI state model, persists tasks to Room, and syncs changes in the background to Firebase.
- Photo capture → AI suggests title, details, due date, and subtasks
- Voice recording → AI transcribes and structures task content
- Written mode → manual task entry with consistent domain flow
Local writes happen first for responsiveness and resilience. Sync, media upload, and remote reconciliation run asynchronously through WorkManager and sync coordination.
Architecture
Action-driven, layered architecture with local-first persistence and async sync orchestration.
| Layer | Primary Responsibility |
|---|---|
| Presentation | Render state and emit strongly typed actions |
| State Orchestration | Route actions, execute use cases, coordinate async work |
| Domain | Expose business operations for create, update, observe, and toggle |
| Data | Local CRUD, soft delete, sync enqueue, media coordination |
| Sync | Realtime merge plus periodic/one-shot reconciliation to Firebase |
| AI | Image/audio parsing via backend and structured extraction |
| Reminders | Due-date notification scheduling with quick actions |
Data Flow
All UI interactions are action-dispatched, persisted locally, then synchronized remotely.
- Task observation pipeline: Room Flow → ViewModel mapping → UI state emission
- Realtime merge path: Firestore listener → sync coordinator merge → Room upsert
- AI parse path: action → coordinator → backend endpoint → structured suggestion state
Task Creation Flows
Three entry modes share a common confirmation and persistence path.
- Photo flow falls back to editable defaults if parsing fails.
- Voice recording auto-stops at 60s and keeps manual confirmation controls.
- Written flow bypasses AI and still follows the same repository and sync path.
Tech Stack
Android-first stack with Firebase services and a FastAPI AI backend.
| Category | Tools |
|---|---|
| Android | Kotlin, Jetpack Compose, Material 3 |
| State | StateFlow, action-driven UI updates |
| Local Storage | Room |
| Background Jobs | WorkManager |
| Backend | FastAPI (Python) |
| AI | OpenAI APIs (backend-only usage) |
| Cloud | Firebase Auth, Firestore, Firebase Storage |
| Networking | Retrofit + OkHttp |
| Reliability | Firebase Crashlytics |
Core Architecture Concepts
The app is centered around typed intents, deterministic state, and local-first consistency.
HomeAction as the intent contract
UI layers emit strongly typed actions only. HomeViewModel.onAction() is the single router for behavior.
HomeUiState as single source of truth
MutableStateFlow<HomeUiState> is the only mutable UI state container. Compose screens render by collecting this state stream.
Repository as integration boundary
TaskRepositoryImpl writes locally first, schedules reminders, and delegates sync/upload logic while exposing a stable domain API.
HomeScreen interaction
→ HomeAction
→ HomeViewModel.onAction()
→ Use Case
→ TaskRepositoryImpl
→ Room write + reminder scheduling
→ Sync enqueueNotifications
Due-date notifications are WorkManager-backed and include quick actions for completion and snooze.
- Notification channel is created at app startup and worker execution time.
- Reminders are scheduled only for active tasks with dueAt timestamps.
- ReminderWorker publishes high-priority notifications with action intents.
- Mark Done action updates repository state and enqueues sync.
- Snooze action shifts due date (10 minutes) and reschedules reminder.
- Android 13+ notification permission is checked before display.
Project Structure
Codebase is split into Android app modules and backend service with clear layer boundaries.
app/
src/main/java/dev/saipranith/toflowai/
ui/
screens/
components/
domain/
model/
repository/
usecase/
data/
datasource/
repository/
remote/
sync/
reminder/
backend/
main.py
requirements.txtRun Locally
Android app and backend can run independently during development.
Android app
# Open project in Android Studio
# Ensure app/google-services.json exists
./gradlew.bat :app:assembleDebugBackend
cd backend
# create .env with OPENAI_API_KEY=...
pip install -r requirements.txt
uvicorn main:app --reload