diff --git a/composeApp/src/commonMain/composeResources/drawable/ic_camping_24dp.xml b/composeApp/src/commonMain/composeResources/drawable/ic_camping_24dp.xml
new file mode 100644
index 0000000..8b8a019
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/drawable/ic_camping_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionPage.kt
index 52027fc..6ab0a45 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionPage.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionPage.kt
@@ -15,8 +15,10 @@ import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler
import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res
+import lwacharactersheet.composeapp.generated.resources.ic_camping_24dp
import lwacharactersheet.composeapp.generated.resources.ic_visibility_24dp
import lwacharactersheet.composeapp.generated.resources.ic_visibility_off_24dp
import org.koin.compose.viewmodel.koinViewModel
@@ -38,6 +40,11 @@ fun GMActionPage(
GMActionContent(
actions = actions,
scroll = scroll,
+ onPartyHeal = {
+ scope.launch {
+ viewModel.onPartyHeal()
+ }
+ },
onPartyVisibility = {
scope.launch {
viewModel.onPlayerVisibility()
@@ -49,6 +56,10 @@ fun GMActionPage(
}
},
)
+
+ ErrorSnackHandler(
+ error = viewModel.error,
+ )
}
@Composable
@@ -57,6 +68,7 @@ fun GMActionContent(
scroll: ScrollState,
spacing: Dp = 8.dp,
actions: State,
+ onPartyHeal: () -> Unit,
onPartyVisibility: () -> Unit,
onNpcVisibility: () -> Unit,
) {
@@ -66,6 +78,12 @@ fun GMActionContent(
.padding(vertical = spacing, horizontal = spacing),
verticalArrangement = Arrangement.spacedBy(space = spacing),
) {
+ GMAction(
+ modifier = Modifier.fillMaxWidth(),
+ icon = Res.drawable.ic_camping_24dp,
+ label = "Soigner le groupe de joueur",
+ onAction = onPartyHeal,
+ )
actions.value?.party?.let { party ->
GMAction(
modifier = Modifier.fillMaxWidth(),
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionViewModel.kt
index f858d05..0490f8a 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionViewModel.kt
@@ -3,8 +3,12 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster.action
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
+import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
+import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio
import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent
+import kotlinx.coroutines.flow.MutableSharedFlow
+import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -12,10 +16,14 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn
class GMActionViewModel(
+ private val characterRepository: CharacterSheetRepository,
private val networkRepository: NetworkRepository,
- campaignRepository: CampaignRepository,
+ private val campaignRepository: CampaignRepository,
) : ViewModel() {
+ private val _error = MutableSharedFlow()
+ val error: SharedFlow get() = _error
+
val actions: StateFlow = campaignRepository.campaignFlow
.map {
ActionPageUio(
@@ -30,19 +38,55 @@ class GMActionViewModel(
initialValue = null,
)
- suspend fun onNpcVisibility() {
- networkRepository.share(
- GameMasterEvent.ToggleNpc(
- timestamp = System.currentTimeMillis(),
+ suspend fun onPartyHeal() {
+ campaignRepository.campaignFlow.value.characters.forEach { characterSheetId ->
+ val sheet = characterRepository.characterDetail(
+ characterSheetId = characterSheetId,
+ ) ?: return@forEach
+
+ val updated = sheet.copy(
+ damage = 0,
+ fatigue = 0,
+ diminished = 0,
)
- )
+
+ if (sheet != updated) {
+ try {
+ characterRepository.updateCharacter(
+ sheet = updated,
+ create = false,
+ )
+ } catch (exception: Exception) {
+ val message = ErrorSnackUio.from(exception = exception)
+ _error.emit(message)
+ }
+ }
+ }
+ }
+
+ suspend fun onNpcVisibility() {
+ try {
+ networkRepository.share(
+ GameMasterEvent.ToggleNpc(
+ timestamp = System.currentTimeMillis(),
+ )
+ )
+ } catch (exception: Exception) {
+ val message = ErrorSnackUio.from(exception = exception)
+ _error.emit(message)
+ }
}
suspend fun onPlayerVisibility() {
- networkRepository.share(
- GameMasterEvent.TogglePlayer(
- timestamp = System.currentTimeMillis(),
+ try {
+ networkRepository.share(
+ GameMasterEvent.TogglePlayer(
+ timestamp = System.currentTimeMillis(),
+ )
)
- )
+ } catch (exception: Exception) {
+ val message = ErrorSnackUio.from(exception = exception)
+ _error.emit(message)
+ }
}
}
\ No newline at end of file