Track your movies. Get AI-powered recommendations. Built with modern Android best practices.
MoviQ helps you manage your movie watchlist and discover new films using AI. Mark movies as seen, rate your favorites, and let Gemini 2.0 suggest what to watch next based on your taste.
Why this repo exists: I built MoviQ as a reference for Android developers looking for real-world examples of apps using scalable Clean Architecture, Jetpack Compose, Firebase integration, and comprehensive testing. It's the kind of codebase I wish I had when learning modern Android development.
| π¬ Track Movies You Watch | β€οΈ Rate & Mark Your Favorites | β¨ Get AI Recs on What to Watch | π Find New Films Tailored to You |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Built with Clean Architecture + MVI Pattern following Google's recommended architecture.
graph LR
subgraph Presentation["π¨ Presentation Layer"]
UI[Jetpack Compose UI]
VM[ViewModels + MVI]
end
subgraph Domain["βοΈ Domain Layer"]
UC[Use Cases]
RI[Repository Interfaces]
end
subgraph Data["πΎ Data Layer"]
REPO[Repository Implementations]
LOCAL[(Room Database)]
REMOTE[(Firestore)]
API[TMDB API]
end
UI --> VM
VM --> UC
UC --> RI
RI --> REPO
REPO --> LOCAL
REPO --> REMOTE
REPO --> API
style Presentation fill:#e3f2fd,stroke:#1565c0,stroke-width:3px,color:#000
style Domain fill:#fff3e0,stroke:#ef6c00,stroke-width:3px,color:#000
style Data fill:#f3e5f5,stroke:#6a1b9a,stroke-width:3px,color:#000
style UI fill:#bbdefb,stroke:#1565c0,stroke-width:2px,color:#000
style VM fill:#bbdefb,stroke:#1565c0,stroke-width:2px,color:#000
style UC fill:#ffe0b2,stroke:#ef6c00,stroke-width:2px,color:#000
style RI fill:#ffe0b2,stroke:#ef6c00,stroke-width:2px,color:#000
style REPO fill:#e1bee7,stroke:#6a1b9a,stroke-width:2px,color:#000
style LOCAL fill:#c5e1a5,stroke:#558b2f,stroke-width:2px,color:#000
style REMOTE fill:#c5e1a5,stroke:#558b2f,stroke-width:2px,color:#000
style API fill:#c5e1a5,stroke:#558b2f,stroke-width:2px,color:#000
| Layer | Responsibilities | Key Technologies |
|---|---|---|
| Presentation | UI components, ViewModels, state management | Jetpack Compose, Material 3, MVI |
| Domain | Business logic, use cases, repository contracts | Kotlin, Coroutines, Flow |
| Data | Data sources, repositories, sync logic | Room, Firestore, Retrofit, WorkManager |
π Key Architectural Patterns
- Offline-First: Room as single source of truth with cloud sync
- Unidirectional Data Flow: MVI pattern with sealed classes
- Dependency Injection: Hilt for compile-time DI
- Background Sync: WorkManager with conflict resolution
- Repository Pattern: Abstract data sources from business logic
- Use Case Pattern: Single responsibility for each business operation
Core Android
- Jetpack Compose - UI
- Material 3 - Google's Current Design System
- Hilt - Dependency injection
- Navigation Compose - Type-safe navigation
- Lifecycle & ViewModel - State management
- Additional Features: Cloud sync across devices β’ Google Sign-In β’ In-app purchases β’ Dark mode β’ Offline-first
Data & Networking
- Room - Local database (SQLite)
- Retrofit - REST API client
- Coil - Image loading & caching
- DataStore - Preferences storage
- WorkManager - Background tasks
Firebase Services
- Authentication - Google Sign-In
- Firestore - Cloud database
- Vertex AI - Gemini 2.0 for recommendations
- Crashlytics - Error tracking
- Analytics - User insights
Testing
- JUnit 4 - Unit testing
- Truth - Assertions
- Espresso - UI testing
- Compose Test - Compose UI tests
- Hilt Testing - DI in tests
Feature-based modularization with clear separation of concerns:
app/src/main/java/com/dthurman/moviesaver/
β
βββ π― core/ # Shared functionality
β βββ app/ # MainActivity, Navigation, Scaffold
β βββ data/ # Room DB, sync logic
β βββ domain/ # Core models (Movie, User)
β βββ observability/ # Analytics & error logging
β
βββ π¬ feature_movies/ # Movie management
β βββ data/ # TMDB API, Firestore sync
β βββ domain/ # 8 use cases (search, rate, etc.)
β βββ presentation/ # Discover, Detail, My Movies screens
β
βββ π€ feature_ai_recs/ # AI recommendations
β βββ data/ # Vertex AI integration
β βββ domain/ # 7 use cases
β βββ presentation/ # Recommendations screen
β
βββ π feature_auth/ # Authentication
βββ π³ feature_billing/ # In-app purchases
βββ π¨ ui/ # Shared components & theme
sequenceDiagram
participant User
participant UI
participant Room
participant WorkManager
participant Firestore
User->>UI: Mark movie as seen
UI->>Room: Update with PENDING_UPDATE
Room-->>UI: β
Instant feedback
UI->>WorkManager: Trigger sync
Note over WorkManager: Background sync
WorkManager->>Room: Get pending changes
Room-->>WorkManager: Movies to sync
WorkManager->>Firestore: Upload changes
Firestore-->>WorkManager: β
Success
WorkManager->>Room: Update to SYNCED
How it works:
- User action updates Room immediately (instant UI feedback)
- Item marked with sync state
- WorkManager syncs to Firestore in background
- Conflict resolution uses timestamps (most recent wins)
- Periodic sync every 6 hours + on-demand triggers
Uses Firebase Vertex AI (Gemini 2.0 Flash) to analyze your movie history and generate personalized suggestions.
flowchart LR
A[User's Seen Movies w/ Ratings] --> B[Vertex AI<br/>Gemini 2.0]
A1[User's Watchlist] --> B
A2[User's Previously Skipped Recs] --> B
B --> C[AI Recommendations<br/>with Reasoning]
C --> D[TMDB API<br/>Validation]
D --> E{Match Found?}
E -->|Yes| F[Add to<br/>Recommendations]
E -->|No| G[Skip]
F --> H[Display to User]
style B fill:#4285f4,color:#fff
style F fill:#34a853,color:#fff
style G fill:#ea4335,color:#fff
Process:
- Analyzes your seen movies + ratings
- Sends structured prompt to Gemini 2.0
- AI returns 5 movie suggestions with reasoning
- Validates against TMDB API
- Filters duplicates and already-seen movies
Requirements: Minimum 5 seen movies β’ 1 credit per generation
Comprehensive test coverage with 50+ tests across unit, integration, and E2E.
| Test Type | Framework | Count | Coverage |
|---|---|---|---|
| Unit Tests | JUnit + Truth | 30+ | Use cases, ViewModels |
| UI Tests | Compose Test + Espresso | 15+ | Screen interactions |
| E2E Tests | Hilt Testing | 5+ | Complete user flows |
Testing Strategy:
- Fake repositories for isolation
- Hilt test modules for DI
- Coroutines test for async operations
- Custom
HiltTestRunnerfor instrumented tests
Example Test
@HiltAndroidTest
@UninstallModules(AppModule::class)
class MoviesEndToEndTest {
@get:Rule(order = 0)
val hiltRule = HiltAndroidRule(this)
@get:Rule(order = 1)
val composeRule = createAndroidComposeRule<MainActivity>()
@Test
fun userCanSearchAndAddMovieToWatchlist() {
// Complete user flow test
}
}- Android Studio Ladybug | 2024.2.1+
- JDK 21
- TMDB API Key (Get one here)
- Firebase Project (Create here)
-
Clone & Configure
git clone https://github.com/yourusername/movie-saver.git cd movie-saver -
Add
local.propertiesMOVIES_API_KEY=your_tmdb_api_key -
Add Firebase
- Download
google-services.jsonfrom Firebase Console - Place in
app/directory - Enable: Authentication (Google), Firestore, Vertex AI, Crashlytics
- Download
-
Build
./gradlew assembleDebug
Detailed Firebase Setup
- Create Firebase project
- Add Android app with package name:
com.dthurman.moviesaver - Enable services:
- Authentication β Google Sign-In provider
- Firestore Database β Production mode
- Vertex AI β Enable Gemini API
- Crashlytics & Analytics
- Add SHA-1 fingerprint:
./gradlew signingReport
- Download and add
google-services.json
- Production-ready architecture
- 100% Kotlin & Compose
- Comprehensive testing examples
- Modern Android best practices
- Real-world Firebase integration
- Clean code with SOLID principles
- Offline-first with sync
- AI integration (Vertex AI)
- In-app billing implementation
- Background processing
- Type-safe navigation
- Material 3 theming
This is a reference project, but contributions are welcome! Feel free to open issues or submit PRs.
MIT License - see LICENSE file for details.
Built by David Thurman
β Star this repo if you find it helpful!




