Restaurants App is a modern Android application designed to explore and manage a list of restaurants. The project follows Android development best practices, applying Clean Architecture, Dagger Hilt, Jetpack Compose, and a reactive, offline-first strategy.
- Offline Caching: High-performance data management where API results are cached in a local Room database, allowing the app to work even without an internet connection.
- Restaurant List: A dynamic list of restaurants fetched from Firebase, sorted server-side, and organized using domain Use Cases.
- Details and Deep Links: Support for opening specific restaurant details directly via URL (e.g.,
https://www.restaurantsapp.details.com/2). - Favorites Management: Ability to mark restaurants as favorites with state persistence across app restarts.
- Comprehensive Testing: Full coverage including UI Compose tests, ViewModel coroutine tests, UseCase business logic tests, and Repository data layer tests.
- UI: Jetpack Compose for a modern, declarative UI.
- Dependency Injection: Dagger Hilt with KSP for compile-time dependency injection.
- Networking: Retrofit 3.0 with GSON Converter for Firebase Realtime Database integration.
- Local Database: Room for robust local persistence and offline support.
- Concurrency: Kotlin Coroutines & Flow for non-blocking asynchronous operations.
- Navigation: Navigation Compose with
hiltViewModel()integration and deep link support. - Testing: JUnit 4, Kotlinx Coroutines Test (
runTest,StandardTestDispatcher), Compose UI Test JUnit4, and custom Fakes. - Dependency Management: Gradle Version Catalog (
libs.versions.toml) for centralized library management.
The app follows Clean Architecture principles combined with MVVM and Unidirectional Data Flow (UDF), organized in a package-by-feature structure:
-
Presentation Layer:
- View: Declarative UI screens built with Compose, decoupled from ViewModels for testability and Preview support.
- ViewModel: Encapsulates business logic and exposes UI state using the Backing Property pattern (
private val _stateandpublic val state: State<T>) to enforce encapsulation.
-
Domain Layer:
- Use Cases: Encapsulate isolated business rules (
GetInitialRestaurantsUseCase,ToggleRestaurantUseCase,GetSortedRestaurantsUseCase). - Domain Model: Pure Kotlin model (
Restaurant) representing app domain logic.
- Use Cases: Encapsulate isolated business rules (
-
Data Layer:
- Repository Pattern:
RestaurantsRepositoryserves as the Single Source of Truth, unifying remote network calls (Retrofit) and local caching (Room). - Model Separation: Clean mapping between Remote DTOs (
RemoteRestaurant), Room Local Entities (LocalRestaurant), and Domain Models (Restaurant).
- Repository Pattern:
- UI Tests (
androidTest):RestaurantsScreenTestverifies initial loading states, content rendering, error states, and semantics descriptions. - ViewModel Tests (
test):RestaurantsViewModelTestverifies state emissions and coroutine exception handling usingStandardTestDispatcherandTestScope. - Domain Tests (
test):GetSortedRestaurantsUseCaseTestverifies business logic sorting behavior. - Data Tests (
test):RestaurantsRepositoryTesttests data flow, offline caching, and favorites updates using fakes (FakeApiService,FakeRoomDao).
Project created for educational purposes to explore modern Android development.