Skip to main content

MVVM Architecture

Evatar Android uses the classic MVVM (Model-View-ViewModel) architecture, implementing reactive data flow through Jetpack Compose's StateFlow + collectAsState().

Architecture Layers​

┌─────────────────────────────────────────────────┐
│ View Layer (Compose) │
│ OnboardingScreen / ChatTab / DynamicTab / ... │
│ Subscribes to StateFlow via collectAsState() │
├─────────────────────────────────────────────────┤
│ ViewModel Layer │
│ ChatViewModel / DynamicViewModel / ... │
│ MutableStateFlow<UiState> + viewModelScope │
├─────────────────────────────────────────────────┤
│ Model Layer │
│ ApiClient (Singleton) + SyncManager │
│ OkHttp sync calls + Dispatchers.IO coroutines │
└─────────────────────────────────────────────────┘

State Management Pattern​

All ViewModels follow a unified state management pattern using immutable UiState data classes, internal MutableStateFlow, .copy() updates, and collectAsState() subscriptions in Compose.

ApiClient Singleton​

ApiClient is the app's sole HTTP client entry point, using double-checked locking singleton pattern with OkHttp (15s connect, 120s write, 180s read timeouts).

Retry Mechanism (executeWithRetry)​

Retry only for SocketTimeoutException and ConnectException, other exceptions throw directly. Exponential backoff: 1000ms -> 2000ms -> 4000ms.

Key Components​

ComponentFileResponsibility
ChatViewModelviewmodel/ChatViewModel.ktChat state: conversations, messages, active conversation
DynamicViewModelviewmodel/DynamicViewModel.ktDynamics state: items, pagination, filters, cache
SettingsViewModelviewmodel/SettingsViewModel.ktSettings state: server URL, connection status, sync control
SyncManagersync/SyncManager.ktCore sync coordinator: MediaStore scan + concurrent upload
WorkSchedulersync/WorkScheduler.ktWorkManager periodic task scheduler

Concurrency Control​

Uses kotlinx.coroutines.sync.Semaphore to limit max concurrent uploads to 3.

content:// URI Handling​

API 29+ MediaStore returns content:// URIs instead of file paths, requiring copy to temp file before upload.