mirror of
https://github.com/googlemaps/android-samples.git
synced 2025-12-08 18:02:20 +00:00
* feat: Adds a new sample demonstrating how to use Google Maps with Firebase Realtime Database on Android. * feat(viewmodel): Add tests and error handling for controller logic This commit introduces unit tests for the `MarkersViewModel` and enhances the app's robustness by adding error handling and improving documentation. - **ViewModel Unit Tests:** Adds unit tests for `MarkersViewModel` using Mockito, Turbine, and Robolectric. The tests verify the controller/agent logic, ensuring that state is correctly managed based on the `controllerId` from Firebase. It also tests the new error reporting mechanism. - **Error Handling:** Implements a `SharedFlow` in the `MarkersViewModel` to propagate database errors to the UI. The `MainActivity` now observes this flow and displays errors to the user in a `Snackbar`. - **Architecture Documentation:** Replaces the static SVG architecture diagram with a more detailed Mermaid diagram in `ARCHITECTURE.md`. The new documentation explains the controller/agent synchronization pattern used for animations. - **Dependency Updates:** Upgrades Gradle to version 9.1.0 and adds `mockito-kotlin` and `turbine` as test dependencies. The `libs.versions.toml` file is reorganized for better clarity. * chore: Configure Gradle JVM args and expose ViewModel property This commit includes two maintenance changes: enabling custom JVM arguments for the Gradle daemon and updating the visibility of a property in the `MarkersViewModel`. * chore: Annotate the version catalog and build.gradle.kts file - **Gradle Build Documentation:** Introduces extensive documentation and organization to the `libs.versions.toml` and `app/build.gradle.kts` files. Dependencies, plugins, and versions are now grouped logically with comments explaining their purpose, improving maintainability and clarity. - **README Update:** The main `README.md` is updated to include a description of the new `FireMarkers` sample. - **Manifest Cleanup:** Removes the redundant `android:label` from the `MainActivity` in the manifest. * chore: adds copyright to the new source files * chore: headers --------- Co-authored-by: Enrique López Mañas <eenriquelopez@gmail.com>
4.5 KiB
4.5 KiB
FireMarkers Architecture
This document provides a visual overview of the FireMarkers application's architecture. The core of the app is a controller/agent synchronization pattern that uses Firebase Realtime Database to keep multiple devices in sync.
Architecture Diagram
flowchart TD
subgraph "Firebase Cloud"
MarkersDB[(Firebase Realtime Database\n/markers)]
AnimationDB[(Firebase Realtime Database\n/animation)]
end
subgraph "Android App"
subgraph "UI Layer (View)"
A[MainActivity] --> B(MapScreen Composable);
B -- User Clicks --> C["TopAppBar Actions<br>(toggleAnimation, seedDatabase, clearMarkers, takeControl)"];
B -- Renders Markers --> D[GoogleMap Composable];
end
subgraph "State & Logic Layer (ViewModel)"
VM[MarkersViewModel];
end
subgraph "Data Layer"
FC[FirebaseConnection];
SD[ShapeData];
M(MarkerData Model);
end
subgraph "Dependency Injection"
Hilt(Hilt/Dagger);
end
end
%% --- Interactions ---
C -- Calls function --> VM;
VM -- Uses --> FC;
VM -- Reads shape vectors --> SD;
%% Controller writes to Firebase
VM -- Writes animation state --> AnimationDB;
VM -- Writes marker data --> MarkersDB;
%% All clients listen for real-time updates
MarkersDB -.->|Real-time updates| FC;
AnimationDB -.->|Real-time updates| FC;
FC -.-> VM;
VM -- Updates StateFlow --> B;
VM -- Uses Model --> M;
%% --- DI Graph ---
Hilt -- Injects --> FC;
Hilt -- Injects --> VM;
%% --- Styling ---
style A fill:#cde,stroke:#333,stroke-width:2px
style B fill:#cde,stroke:#333,stroke-width:2px
style C fill:#cde,stroke:#333,stroke-width:2px
style D fill:#cde,stroke:#333,stroke-width:2px
style VM fill:#dce,stroke:#333,stroke-width:2px
style FC fill:#edc,stroke:#333,stroke-width:2px
style SD fill:#edc,stroke:#333,stroke-width:2px
style M fill:#edc,stroke:#333,stroke-width:2px
style MarkersDB fill:#f9d,stroke:#333,stroke-width:2px
style AnimationDB fill:#f9d,stroke:#333,stroke-width:2px
style Hilt fill:#eee,stroke:#333,stroke-width:2px
How it Works
The application uses a controller/agent model to synchronize animations across devices.
- Controller and Agents: At any time, only one device is the controller. It is responsible for running the animation loop and writing the current animation state (progress, running status) to the
/animationnode in Firebase. All other devices are agents that passively listen for changes to this node. - UI Layer: The
MainActivityhosts theMapScreencomposable. The UI in theTopAppBaris dynamic:- If the device is the controller, it shows buttons to
toggleAnimation,seedDatabase, andclearMarkers. - If the device is an agent, it shows a single button that allows the user to
takeControl.
- If the device is the controller, it shows buttons to
- ViewModel: UI interactions call functions on the
MarkersViewModel.- If the controller toggles the animation, the ViewModel starts a local animation loop and writes the progress to the
/animationnode in Firebase. - If an agent requests control, the ViewModel updates the
controllerIdfield in the/animationnode.
- If the controller toggles the animation, the ViewModel starts a local animation loop and writes the progress to the
- Data Layer:
- The
MarkersViewModeluses theFirebaseConnectionservice to interact with Firebase. - The
ShapeDataobject provides the static vector coordinates for the jack-o'-lantern and tree shapes.
- The
- Real-time Updates: The
MarkersViewModelestablishes listeners on two Firebase paths:/markers: When the marker data changes (e.g., after seeding), Firebase pushes the updates to all clients./animation: When the animation state changes (written by the controller), Firebase pushes the new state to all agents.
- State Flow & Interpolation: The
MarkersViewModeluses acombineoperator on twoStateFlows (one for markers, one for animation state). When new data is received from either listener, it recalculates the interpolated position and color for every marker based on the animation progress (fraction). - UI Update: The
MapScreencomposable collects the finalStateFlowof interpolated marker data. On each new emission, theGoogleMaprecomposes and smoothly animates the markers to their new positions and colors. - Dependency Injection: Hilt provides the
FirebaseConnectionas a singleton to theMarkersViewModel.