How lasangnya/snaptric works
1. Project shape
- Snaptric is a single Android app module, organized as a Clean Architecture-style codebase rather than a multi-module Gradle build.
- The main boundaries are core for shared domain/data/infrastructure, feature for user-facing screens, navigation for routing, and ai for OCR/image-processing helpers.
2. App entry and composition root
- SnaptricApplication, AppModule, and DatabaseModule are the main startup/DI entry points.
- MainActivity hosts the Compose UI, and AppNavHost wires the screen graph starting from top-level destinations defined in TopLevelDestination.
3. UI architecture
- The app is Compose-only with Material 3 styling from the core/designsystem package.
- Screens are split into stateful/state-holder layers and stateless UI surfaces, which is why there are separate ui and viewmodel packages for each feature.
4. Feature subsystems
- feature/home is the landing/dashboard area.
- feature/properties manages the hierarchy of properties, utilities, and property details.
- feature/capture handles the camera-based meter reading flow.
- These features are intentionally isolated so each screen group owns its own state, UI, and navigation concerns.
5. Domain model and data flow
- The core domain revolves around Reading plus a ReadingRepository abstraction and MeterReadingAnalyzer.
- The primary user flow is: UI interaction → ViewModel → repository/domain logic → persistence or OCR analysis → UI state update.
- CaptureUiState centralizes the capture screen state so camera/OCR results can be represented consistently.
6. Persistence layer
- Room is the local persistence backbone via SnaptricDatabase, MeterDao, entity classes, and type converters.
- The database schema is relational: PropertyEntity → UtilityEntity → ReadingEntity, matching the app’s property/utility/meter structure.
- The README’s note about cascading deletes is reflected in the design: removing a property should clean up dependent utilities and readings.
7. Repository strategy
- InMemoryReadingRepository exists alongside the database-backed path, which suggests the app uses an abstraction to support tests, previews, or simplified runtime behavior.
- This keeps ViewModels insulated from the storage implementation and makes the core logic easier to test.
8. Capture and OCR pipeline
- The capture subsystem combines CameraX-style image acquisition with image preprocessing and ML Kit OCR.
- The ai/helper/CopyAssetToFiles utility indicates model or asset setup work, while ai/mlkit/MlKitReadingAnalyzer performs text recognition.
- The README describes a deliberate image-cropping step before analysis, which is an important boundary: camera frame → crop/rotate preprocess → OCR → extracted reading.
9. Property and utility management
- PropertyViewModel, UtilityViewModel, and PropertyDetailViewModel manage CRUD and selection logic for the hierarchy of tracked locations and meters.
- PropertiesScreen, UtilityScreen, and PropertyDetailScreen are the corresponding presentation surfaces.
- This subsystem is the app’s structure-management layer, feeding the capture and home flows with metadata like utility type and units.
10. Home/dashboard layer
- HomeViewModel and HomeScreen likely aggregate the current state of tracked properties, recent readings, or summary information.
- It acts as a navigation and overview entry point rather than owning core persistence rules.
11. Design system and shared UI
- core/designsystem contains reusable Compose components, tokens, spacing, shapes, colors, typography, and the app theme.
- This is a shared presentation boundary used across features to keep visual behavior consistent without coupling screens to one another.
12. Testing strategy
- Unit tests cover ViewModels, the in-memory repository, and property icon logic, which points to logic-heavy code being tested outside Android runtime.
- Instrumented tests cover Room DAO behavior and Compose UI/navigation flows, indicating the repo validates both persistence integrity and end-to-end screen behavior.
13. Infrastructure and runtime dependencies that affect architecture
- The important runtime pieces are Jetpack Compose, Hilt, Room, CameraX, Kotlin Coroutines/Flow, and Google ML Kit.
- These choices drive the architecture: asynchronous state streams in ViewModels, injected repositories/DB, and a dedicated capture/OCR pipeline instead of server-side processing.
14. Overall architectural boundary
- Snaptric is explicitly local-first: all user data stays on-device, and AI processing is performed on-device.
- The main system boundary is therefore between the UI/domain layer and local device services: camera frames, ML analysis, and Room persistence.
Main entry points: CaptureViewModel.kt Capture VM · AppNavHost.kt Nav host · MeterDao.kt Meter DAO · ReadingRepository.kt Repository
Components 24
App shell
Startup, activity, and navigation composition root.
- App · Process entry point and app setup.
app/src/main/java/com/snaptric/SnaptricApplication.kt - App module · Top-level dependency wiring for the app.
app/src/main/java/com/snaptric/AppModule.kt - MainActivity · Hosts the Compose UI tree.
app/src/main/java/com/snaptric/MainActivity.kt - Nav host · Wires top-level destinations and screen graph.
app/src/main/java/com/snaptric/navigation/AppNavHost.kt - Top level · Defines the app's top-level routes.
app/src/main/java/com/snaptric/navigation/TopLevelDestination.kt
Core
Shared domain, persistence, and design system.
- Reading · Core meter reading value object.
app/src/main/java/com/snaptric/core/domain/Reading.kt - Repository · Abstraction for persisting and loading readings.
app/src/main/java/com/snaptric/core/domain/ReadingRepository.kt - Analyzer · Interface for meter-reading extraction from images.
app/src/main/java/com/snaptric/core/domain/MeterReadingAnalyzer.kt - Capture state · Shared state model for capture flow results and progress.
app/src/main/java/com/snaptric/core/data/CaptureUiState.kt - In-memory repo · Lightweight repository implementation for tests and simple runtime use.
app/src/main/java/com/snaptric/core/data/InMemoryReadingRepository.kt - Database · Room database entry point for local persistence.
app/src/main/java/com/snaptric/core/database/SnaptricDatabase.kt - Meter DAO · Database access for properties, utilities, and readings.
app/src/main/java/com/snaptric/core/database/dao/MeterDao.kt - DB module · Provides Room database and DAO dependencies.
app/src/main/java/com/snaptric/core/database/di/DatabaseModule.kt - Design system · Shared components, theme tokens, and styling.
app/src/main/java/com/snaptric/core/designsystem
Features
User-facing screens and their state holders.
- Home screen · Landing and overview UI.
app/src/main/java/com/snaptric/feature/home/ui/HomeScreen.kt - Home VM · Aggregates overview state for the home screen.
app/src/main/java/com/snaptric/feature/home/viewmodel/HomeViewModel.kt - Properties UI · Property, utility, and detail presentation surfaces.
app/src/main/java/com/snaptric/feature/properties/ui - Properties VMs · CRUD and selection logic for properties and utilities.
app/src/main/java/com/snaptric/feature/properties/viewmodel - Capture screen · Camera-based meter reading flow UI.
app/src/main/java/com/snaptric/feature/capture/ui/CaptureScreen.kt - Capture VM · Coordinates camera, preprocessing, OCR, and capture state.
app/src/main/java/com/snaptric/feature/capture/viewmodel/CaptureViewModel.kt
AI pipeline
On-device image preprocessing and OCR analysis.
- Asset helper · Copies bundled assets into app files for runtime setup.
app/src/main/java/com/snaptric/ai/helper/CopyAssetToFiles.kt - ML Kit OCR · Performs on-device text recognition for readings.
app/src/main/java/com/snaptric/ai/mlkit/MlKitReadingAnalyzer.kt
Tests
Representative unit and instrumented coverage areas.
- DAO test · Representative Room persistence coverage.
app/src/androidTest/java/com/snaptric/core/database/dao/MeterDaoTest.kt - Capture VM test · Representative capture flow logic coverage.
app/src/test/java/com/snaptric/feature/capture/viewmodel/CaptureViewModelTest.kt
Connections 28
- App → App module: starts · Application bootstraps app-wide dependencies.
- App module → DB module: includes · Top-level DI wiring pulls in persistence bindings.
- App → MainActivity: launches · App entry launches the Compose host activity.
- MainActivity → Nav host: hosts · Activity renders the navigation graph.
- Nav host → Top level: routes · Navigation is organized around top-level destinations.
- Nav host → Home screen: shows · Home is one of the primary destinations.
- Nav host → Properties UI: shows · Property management screens are part of the graph.
- Nav host → Capture screen: shows · Capture flow is reachable from the app graph.
- Home VM → Repository: reads · Home state is derived from repository data.
- Home screen → Home VM: observes · UI renders state from its ViewModel.
- Properties VMs → Repository: uses · Property and utility logic depends on the repository abstraction.
- Properties VMs → Meter DAO: persists · Repository-backed flows ultimately reach Room access.
- Properties UI → Properties VMs: observes · Property UI is driven by feature ViewModels.
- Capture VM → Capture state: updates · Capture flow centralizes screen state in one model.
- Capture VM → Analyzer: analyzes · ViewModel delegates OCR extraction to analyzer logic.
- Capture VM → Repository: stores · Successful readings flow into the repository boundary.
- Capture VM → ML Kit OCR: implements · ML Kit is the concrete OCR backend.
- ML Kit OCR → Asset helper: depends on · OCR setup relies on bundled assets/files preparation.
- Capture screen → Capture VM: observes · Camera UI is state-driven from the ViewModel.
- Design system → Home screen: styles · Shared Compose theme and components are used across screens.
- Design system → Properties UI: styles · Property screens reuse the common visual system.
- Design system → Capture screen: styles · Capture UI is also themed by the shared design system.
- DB module → Database: provides · DI creates the Room database instance.
- Database → Meter DAO: exposes · Database surfaces DAO access.
- Meter DAO → Reading: maps · DAO persists the core reading domain data through entities.
- In-memory repo → Repository: implements · In-memory implementation satisfies the repository contract.
- Capture VM test → Capture VM: verifies · Unit coverage targets capture orchestration logic.
- DAO test → Meter DAO: verifies · Instrumented tests validate Room behavior.