Files
honeyDueKMP/composeApp/src/commonMain/kotlin/com/example/casera/viewmodel/TaskCompletionViewModel.kt
Trey t cf0cd1cda2 Add unified DataManager as single source of truth for all app data
- Create DataManager.kt with StateFlows for all cached data:
  - Authentication (token, user)
  - Residences, tasks, documents, contractors
  - Subscription status and upgrade triggers
  - All lookup data (residence types, task categories, etc.)
  - Theme preferences and state metadata

- Add PersistenceManager with platform-specific implementations:
  - Android: SharedPreferences
  - iOS: NSUserDefaults
  - JVM: Properties file
  - WasmJS: localStorage

- Migrate APILayer to update DataManager on every API response
- Update Kotlin ViewModels to use DataManager for token access
- Deprecate LookupsRepository (delegates to DataManager)
- Create iOS DataManagerObservable Swift wrapper for SwiftUI
- Update iOS auth flow to use DataManager.isAuthenticated()

Data flow: User Action → API Call → DataManager Updated → All Screens React

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 00:21:24 -06:00

77 lines
3.1 KiB
Kotlin

package com.example.casera.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.casera.data.DataManager
import com.example.casera.models.TaskCompletion
import com.example.casera.models.TaskCompletionCreateRequest
import com.example.casera.network.ApiResult
import com.example.casera.network.TaskCompletionApi
import com.example.casera.util.ImageCompressor
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
class TaskCompletionViewModel : ViewModel() {
private val taskCompletionApi = TaskCompletionApi()
private val _createCompletionState = MutableStateFlow<ApiResult<TaskCompletion>>(ApiResult.Idle)
val createCompletionState: StateFlow<ApiResult<TaskCompletion>> = _createCompletionState
fun createTaskCompletion(request: TaskCompletionCreateRequest) {
viewModelScope.launch {
_createCompletionState.value = ApiResult.Loading
val token = DataManager.authToken.value
if (token != null) {
_createCompletionState.value = taskCompletionApi.createCompletion(token, request)
} else {
_createCompletionState.value = ApiResult.Error("Not authenticated", 401)
}
}
}
/**
* Create task completion with images.
*
* @param request The completion request data
* @param images List of ImageData (from platform-specific image pickers)
*/
fun createTaskCompletionWithImages(
request: TaskCompletionCreateRequest,
images: List<com.example.casera.platform.ImageData> = emptyList()
) {
viewModelScope.launch {
_createCompletionState.value = ApiResult.Loading
val token = DataManager.authToken.value
if (token != null) {
// Compress images and prepare for upload
val compressedImages = images.map { ImageCompressor.compressImage(it) }
val imageFileNames = images.mapIndexed { index, image ->
// Always use .jpg extension since we compress to JPEG
val baseName = image.fileName.ifBlank { "completion_$index" }
if (baseName.endsWith(".jpg", ignoreCase = true) ||
baseName.endsWith(".jpeg", ignoreCase = true)) {
baseName
} else {
// Remove any existing extension and add .jpg
baseName.substringBeforeLast('.', baseName) + ".jpg"
}
}
_createCompletionState.value = taskCompletionApi.createCompletionWithImages(
token = token,
request = request,
images = compressedImages,
imageFileNames = imageFileNames
)
} else {
_createCompletionState.value = ApiResult.Error("Not authenticated", 401)
}
}
}
fun resetCreateState() {
_createCompletionState.value = ApiResult.Idle
}
}