MVVM Architecture
Relevant source files
The following files were used as context for generating this wiki page:
- app/src/main/kotlin/com/shadowcheck/mobile/presentation/viewmodel/MainViewModel.kt
- app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/HomeScreen.kt
- app/src/main/kotlin/com/shadowcheck/mobile/data/Entities.kt
- app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/SettingsScreen.kt
- app/src/main/kotlin/com/shadowcheck/mobile/ui/screens/StatsScreen.kt
- README.md
ShadowCheckMobile utilizes the Model-View-ViewModel (MVVM) architectural pattern to separate the concerns of data management, business logic, and user interface representation. This architecture facilitates reactive UI updates through Kotlin Coroutines and Flows, ensuring the application remains responsive while processing high-frequency network scanning data.
The project structure organizes these components into dedicated packages: data/ for the Model layer, ui/ for the View layer (Jetpack Compose), and presentation/viewmodel/ for the ViewModel layer.
Sources: README.md:46-56, app/src/main/kotlin/com/shadowcheck/mobile/presentation/viewmodel/MainViewModel.kt:1-24
Component Overview
The Model Layer
The Model layer consists of Room database entities and Data Access Objects (DAOs). It defines the structure of the collected signal data, including WiFi networks, Bluetooth devices, and cellular towers. These entities are persistent and serve as the single source of truth for the application.
| Entity | Description | Key Fields |
|---|---|---|
WifiNetwork | Scanned WiFi access points | BSSID, SSID, Signal Level, Frequency |
BluetoothDevice | Classic Bluetooth devices | Address, Name, RSSI, Device Class |
BleDevice | Bluetooth Low Energy beacons | Address, TX Power, Manufacturer Data |
CellularTower | Mobile network base stations | Cell ID, LAC, MCC, MNC, Signal Strength |
Sources: app/src/main/kotlin/com/shadowcheck/mobile/data/Entities.kt:5-75, README.md:58-72
The View Layer
The View layer is implemented using Jetpack Compose. It is responsible for rendering the UI based on the state provided by the ViewModel. Screens like HomeScreen and StatsScreen observe state changes and trigger events back to the ViewModel through lambda callbacks.
Sources: app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/HomeScreen.kt:29-110, app/src/main/kotlin/com/shadowcheck/mobile/ui/screens/StatsScreen.kt:21-65
The ViewModel Layer
The MainViewModel manages the MainUiState. It interacts with the ShadowCheckDatabase to observe data streams (Flows) and exposes them as StateFlow to the UI. It also handles UI-driven events such as updating search queries, toggling scanning states, and navigation.
Sources: app/src/main/kotlin/com/shadowcheck/mobile/presentation/viewmodel/MainViewModel.kt:33-85
Data Flow and State Management
The application employs a unidirectional data flow. Data flows from the database through the ViewModel into a consolidated UI state, while user actions flow from the UI back to the ViewModel as function calls.
The diagram shows the reactive cycle between the persistence layer, the business logic in the ViewModel, and the declarative UI.
Reactive Updates
The ViewModel initializes observers on the database DAOs during its lifecycle. As new networks are scanned and inserted into the database by background services, the DAOs emit updated lists through Kotlin Flows, which the ViewModel then packs into the MainUiState.
private fun observeNetworks() {
viewModelScope.launch {
database.wifiNetworkDao().getAllFlow().collect { networks ->
_uiState.update { it.copy(wifiNetworks = networks, wifiCount = networks.size) }
}
}
}
Sources: app/src/main/kotlin/com/shadowcheck/mobile/presentation/viewmodel/MainViewModel.kt:42-59
UI State Structure
The MainUiState is a central data class that represents the entire state of the main application flow. This prevents state fragmentation across multiple variables in the View.
| Field | Type | Purpose |
|---|---|---|
isScanning | Boolean | Tracks if the background scanner service is active |
wifiNetworks | List | The current list of detected WiFi networks |
currentLocation | Location? | Latest GPS coordinates for mapping |
searchQuery | String | User input for filtering network lists |
isLoading | Boolean | Global loading indicator state |
Sources: app/src/main/kotlin/com/shadowcheck/mobile/presentation/viewmodel/MainViewModel.kt:10-31
Interaction Sequence
When a user interacts with a setting, such as changing the scan interval, the flow follows a specific path through the architecture to ensure persistence and UI synchronization.
Sequence of events when modifying application configurations through the settings module.
Sources: app/src/main/kotlin/com/shadowcheck/mobile/rebuilt/ui/screens/SettingsScreen.kt:85-102, app/src/main/kotlin/com/shadowcheck/mobile/presentation/viewmodel/MainViewModel.kt:73
Technical Summary
The MVVM implementation in ShadowCheckMobile leverages modern Android components to handle SIGINT data efficiently. By using ShadowCheckDatabase as a reactive source and MainViewModel as the state orchestrator, the app ensures that high-volume data from WiFi and Bluetooth scans is reflected in the UI without blocking the main thread.
Sources: README.md:38-44, app/src/main/kotlin/com/shadowcheck/mobile/presentation/viewmodel/MainViewModel.kt:33-40