Refactor: Extract boilerplate: safeLaunchLoad, clearToast, ToastEffect (CODE-21/22/23) (#312)

- Extracted `safeLaunchLoad` inline extension function to `ViewModelExt.kt` to encapsulate API call success/failure handling logic and replaced usages across 18 viewmodels.
- Extracted `ToastHost` interface to standardize `clearToast()` behavior across all ViewModels displaying toasts.
- Extracted `ToastEffect` composable to `SharedComponents.kt` and applied it to 16 screens, reducing repetitive side effect code blocks.

Fixes #286
This commit is contained in:
M57 authored and GitHub committed 2026-06-22 23:54:42 +03:00
1 parent 6abfabdac0
commit 98c02879b4
36 files changed
+427 -585

No files matched your search

@@ -343,3 +343,19 @@ fun InfoRow(
)
}
}
// ── ToastEffect — helper for one-shot toast messages ───────────────────
@Composable
fun ToastEffect(
toastMessage: String?,
onClearToast: () -> Unit,
) {
val context = androidx.compose.ui.platform.LocalContext.current
androidx.compose.runtime.LaunchedEffect(toastMessage) {
toastMessage?.let { msg ->
android.widget.Toast.makeText(context, msg, android.widget.Toast.LENGTH_SHORT).show()
onClearToast()
}
}
}
@@ -0,0 +1,28 @@
package com.m57.hermescontrol.ui.common
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.m57.hermescontrol.data.remote.NetworkResult
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
interface ToastHost {
fun clearToast()
}
inline fun <T> ViewModel.safeLaunchLoad(
crossinline apiCall: suspend () -> NetworkResult<T>,
crossinline onStart: () -> Unit,
crossinline onSuccess: (T) -> Unit,
crossinline onError: (String) -> Unit,
) {
onStart()
viewModelScope.launch {
val result = withContext(Dispatchers.IO) { apiCall() }
when (result) {
is NetworkResult.Success -> onSuccess(result.data)
is NetworkResult.Failure -> onError(result.error.message ?: "Unknown error")
}
}
}