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