diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index 4f9d158..e9363d3 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -329,5 +329,17 @@ Consommable Ajouter une alteration Édition de personnage + Synchronisation du serveur + Demander au serveur d'invalider son cache + Soigner les personnages joueurs + Cette action réinitialisera les points de vie, de pouvoir et d'état diminué de chaque personnage joueur présent dans le groupe. + Cacher le groupe de personnages joueur + Cacher le panneau latéral gauche pour tous les joueurs. + Montrer les personnages joueurs + Montrer le panneau latéral gauche pour tous les joueurs. + Cacher le groupe de npcs + Cacher le panneau latéral droit pour tous les joueurs. + Montrer le groupe de npcs + Montrer le panneau latéral droit pour tous les joueurs. \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt index 78e7204..888e447 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt @@ -47,6 +47,7 @@ import com.pixelized.desktop.lwa.ui.screen.campaign.text.TextMessageFactory import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.CampaignToolbarViewModel import com.pixelized.desktop.lwa.ui.screen.campaign.toolbar.links.ResourcesViewModel import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterViewModel +import com.pixelized.desktop.lwa.ui.screen.gamemaster.action.GMActionUseCase import com.pixelized.desktop.lwa.ui.screen.gamemaster.action.GMActionViewModel import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit.GMAlterationEditFactory import com.pixelized.desktop.lwa.ui.screen.gamemaster.alteration.edit.GMAlterationEditViewModel @@ -198,4 +199,5 @@ val viewModelDependencies val useCaseDependencies get() = module { factoryOf(::SettingsUseCase) + factoryOf(::GMActionUseCase) } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/LwaDialog.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/LwaDialog.kt index 856450d..80e8b46 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/LwaDialog.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/LwaDialog.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.State import androidx.compose.runtime.remember @@ -18,6 +19,8 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog +import com.pixelized.desktop.lwa.LocalBlurController +import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox import com.pixelized.desktop.lwa.utils.extention.onPreviewEscape @@ -29,6 +32,7 @@ object LwaDialogDefault { @Composable fun LwaDialog( modifier: Modifier = Modifier, + blur: BlurContentController? = LocalBlurController.current, paddings: PaddingValues = LwaDialogDefault.paddings, color: Color = MaterialTheme.colors.surface, state: State, @@ -37,6 +41,16 @@ fun LwaDialog( content: @Composable BoxScope.(T) -> Unit, ) { state.value?.let { dialog -> + + blur?.let { + DisposableEffect("LwaDialog") { + blur.show() + onDispose { + blur.hide() + } + } + } + Dialog( onDismissRequest = onDismissRequest, content = { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/alterteration/CharacterSheetAlterationDialog.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/alterteration/CharacterSheetAlterationDialog.kt index 23ead9d..8dea0f1 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/alterteration/CharacterSheetAlterationDialog.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/character/alterteration/CharacterSheetAlterationDialog.kt @@ -19,6 +19,7 @@ import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.minimumInteractiveComponentSize import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.Stable import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState @@ -28,13 +29,12 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.DialogProperties -import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler -import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio +import com.pixelized.desktop.lwa.LocalBlurController +import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.GMFilterHeader import com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag.GMTagUio import com.pixelized.desktop.lwa.ui.theme.lwa -import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.StateFlow import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.ic_close_24dp @@ -52,12 +52,23 @@ data class CharacterSheetAlterationDialogUio( @OptIn(ExperimentalComposeUiApi::class) @Composable fun CharacterSheetAlterationDialog( + blur: BlurContentController? = LocalBlurController.current, dialog: State, onTag: (String) -> Unit, onAlteration: (characterSheetId: String, alterationId: String, active: Boolean) -> Unit, onDismissRequest: () -> Unit, ) { dialog.value?.let { + + blur?.let { + DisposableEffect("LwaDialog") { + blur.show() + onDispose { + blur.hide() + } + } + } + Dialog( properties = DialogProperties( usePlatformDefaultWidth = false, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/confirmation/ConfirmationDialog.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/confirmation/ConfirmationDialog.kt new file mode 100644 index 0000000..7aab76c --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/confirmation/ConfirmationDialog.kt @@ -0,0 +1,98 @@ +package com.pixelized.desktop.lwa.ui.composable.confirmation + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.padding +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.material.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.State +import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp +import androidx.compose.ui.unit.dp +import com.pixelized.desktop.lwa.LocalBlurController +import com.pixelized.desktop.lwa.ui.composable.character.LwaDialog +import lwacharactersheet.composeapp.generated.resources.Res +import lwacharactersheet.composeapp.generated.resources.dialog__cancel_action +import lwacharactersheet.composeapp.generated.resources.dialog__confirm_action +import org.jetbrains.compose.resources.stringResource + +@Stable +data class ConfirmationDialogUio( + val title: String, + val description: String, + val onConfirmRequest: () -> Unit, + val onDismissRequest: () -> Unit, +) + +@Stable +object ConfirmationDialogDefault { + + @Stable + val paddings = PaddingValues(start = 16.dp, top = 16.dp, end = 16.dp) + + @Stable + val spacings: Dp = 8.dp +} + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +fun ConfirmationDialog( + modifier: Modifier = Modifier, + paddingValues: PaddingValues = ConfirmationDialogDefault.paddings, + spacing: Dp = ConfirmationDialogDefault.spacings, + dialog: State, +) { + LwaDialog( + modifier = modifier, + blur = LocalBlurController.current, + state = dialog, + onDismissRequest = { dialog.value?.onDismissRequest?.invoke() }, + onConfirm = { dialog.value?.onConfirmRequest?.invoke() }, + ) { + Column( + modifier = Modifier.padding(paddingValues = paddingValues), + verticalArrangement = Arrangement.spacedBy(space = spacing), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Text( + style = MaterialTheme.typography.caption, + text = it.title, + ) + Text( + style = MaterialTheme.typography.body1, + text = it.description, + ) + Row( + modifier = Modifier.align(alignment = Alignment.End), + horizontalArrangement = Arrangement.spacedBy( + space = spacing / 2, + alignment = Alignment.End, + ), + ) { + TextButton( + onClick = it.onDismissRequest, + ) { + Text( + color = MaterialTheme.colors.primaryVariant, + text = stringResource(Res.string.dialog__cancel_action) + ) + } + TextButton( + onClick = it.onConfirmRequest, + ) { + Text( + color = MaterialTheme.colors.primary, + text = stringResource(Res.string.dialog__confirm_action) + ) + } + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignScreen.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignScreen.kt index c18e99b..06fe469 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/CampaignScreen.kt @@ -169,7 +169,6 @@ fun CampaignScreen( .width(width = 128.dp * 4) .fillMaxHeight(), transitionSpec = rememberTransitionAnimation(direction = LayoutDirection.Ltr), - blurController = blurController, detailPanelViewModel = npcDetailViewModel, characterDiminishedViewModel = dismissedViewModel, characteristicDialogViewModel = characteristicDialogViewModel, @@ -186,7 +185,6 @@ fun CampaignScreen( .width(width = 128.dp * 4) .fillMaxHeight(), transitionSpec = rememberTransitionAnimation(direction = LayoutDirection.Rtl), - blurController = blurController, detailPanelViewModel = playerDetailViewModel, characterDiminishedViewModel = dismissedViewModel, characteristicDialogViewModel = characteristicDialogViewModel, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailPanel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailPanel.kt index ccf2552..6119193 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailPanel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailPanel.kt @@ -15,7 +15,6 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.PagerState import androidx.compose.foundation.pager.rememberPagerState @@ -31,7 +30,6 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Shape import androidx.compose.ui.unit.LayoutDirection -import androidx.compose.ui.unit.dp import com.pixelized.desktop.lwa.LocalRollHostState import com.pixelized.desktop.lwa.ui.composable.blur.BlurContentController import com.pixelized.desktop.lwa.ui.composable.character.alterteration.CharacterSheetAlterationDialogViewModel @@ -74,7 +72,6 @@ enum class DetailPanelUio { @Composable fun CharacterDetailPanel( modifier: Modifier = Modifier, - blurController: BlurContentController, transitionSpec: AnimatedContentTransitionScope.() -> ContentTransform = rememberTransitionAnimation(), detailPanelViewModel: CharacterDetailPanelViewModel, characteristicDialogViewModel: CharacterSheetCharacteristicDialogViewModel, @@ -121,12 +118,10 @@ fun CharacterDetailPanel( } }, onAlteration = { - blurController.show() alterationViewModel.show(characterSheetId = it) }, onDiminished = { scope.launch { - blurController.show() characterDiminishedViewModel.showDiminishedDialog( characterSheetId = it ) @@ -134,7 +129,6 @@ fun CharacterDetailPanel( }, onHp = { scope.launch { - blurController.show() characteristicDialogViewModel.showSubCharacteristicDialog( characterSheetId = it, characteristic = CharacterSheetCharacteristicDialogUio.Characteristic.Damage, @@ -143,7 +137,6 @@ fun CharacterDetailPanel( }, onPp = { scope.launch { - blurController.show() characteristicDialogViewModel.showSubCharacteristicDialog( characterSheetId = it, characteristic = CharacterSheetCharacteristicDialogUio.Characteristic.Fatigue, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventory.kt index 714593f..0221bef 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/inventory/CharacterDetailInventory.kt @@ -107,7 +107,6 @@ fun CharacterDetailInventory( itemDetailDialogViewModel: ItemDetailDialogViewModel = koinViewModel(), inventory: State, ) { - val blur = LocalBlurController.current val focus = LocalFocusManager.current val scope = rememberCoroutineScope() @@ -120,14 +119,12 @@ fun CharacterDetailInventory( spacing = spacing, inventory = unWrap, onPurse = { - blur.show() purseViewModel.showPurseDialog( characterSheetId = it, ) focus.clearFocus(force = true) }, onItem = { item -> - blur.show() itemDetailDialogViewModel.showItemDialog( characterSheetId = item.characterSheetId, inventoryId = item.inventoryId, @@ -136,7 +133,6 @@ fun CharacterDetailInventory( focus.clearFocus(force = true) }, onAddItem = { - blur.show() inventoryDialogViewModel.showInventoryDialog( characterSheetId = it, ) @@ -166,7 +162,6 @@ fun CharacterDetailInventory( PurseDialog( dialog = purseViewModel.purseDialog.collectAsState(), onDismissRequest = { - blur.hide() purseViewModel.hidePurseDialog() }, onSwapSign = { @@ -175,7 +170,6 @@ fun CharacterDetailInventory( onConfirm = { scope.launch { if (purseViewModel.confirmPurse(dialog = it)) { - blur.hide() purseViewModel.hidePurseDialog() } } @@ -185,11 +179,9 @@ fun CharacterDetailInventory( InventoryDialog( dialog = inventoryDialogViewModel.inventoryDialog.collectAsState(), onDismissRequest = { - blur.hide() inventoryDialogViewModel.hideInventoryDialog() }, onItem = { dialog, itemId -> - blur.show() itemDetailDialogViewModel.showItemDialog( characterSheetId = dialog.characterSheetId, inventoryId = null, @@ -201,7 +193,6 @@ fun CharacterDetailInventory( ItemDetailDialog( dialog = itemDetailDialogViewModel.itemDialog.collectAsState(), onDismissRequest = { - blur.hide() itemDetailDialogViewModel.hideItemDialog() }, onAddItem = { dialog -> @@ -210,7 +201,6 @@ fun CharacterDetailInventory( dialog = dialog, ) if (result) { - blur.hide() itemDetailDialogViewModel.hideItemDialog() } } @@ -221,7 +211,6 @@ fun CharacterDetailInventory( dialog = dialog, ) if (result) { - blur.hide() itemDetailDialogViewModel.hideItemDialog() } } @@ -233,7 +222,6 @@ fun CharacterDetailInventory( inventoryId = dialog.inventoryId, ) if (result) { - blur.hide() itemDetailDialogViewModel.hideItemDialog() } } @@ -245,7 +233,6 @@ fun CharacterDetailInventory( inventoryId = dialog.inventoryId, ) if (result) { - blur.hide() itemDetailDialogViewModel.hideItemDialog() } } @@ -257,7 +244,6 @@ fun CharacterDetailInventory( inventoryId = dialog.inventoryId, ) if (result) { - blur.hide() itemDetailDialogViewModel.hideItemDialog() } } 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 e7a5dcb..74860c8 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 @@ -10,12 +10,13 @@ import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.State -import androidx.compose.runtime.collectAsState import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler +import com.pixelized.desktop.lwa.ui.composable.confirmation.ConfirmationDialog import kotlinx.coroutines.launch import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.ic_camping_24dp @@ -36,7 +37,8 @@ fun GMActionPage( ) { val scope = rememberCoroutineScope() val scroll = rememberScrollState() - val actions = viewModel.actions.collectAsState() + val actions = viewModel.actions.collectAsStateWithLifecycle() + val validationDialog = viewModel.validationDialog.collectAsStateWithLifecycle() GMActionContent( actions = actions, @@ -66,6 +68,10 @@ fun GMActionPage( ErrorSnackHandler( error = viewModel.error, ) + + ConfirmationDialog( + dialog = validationDialog, + ) } @Composable diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionUseCase.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionUseCase.kt new file mode 100644 index 0000000..895f9a0 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/action/GMActionUseCase.kt @@ -0,0 +1,58 @@ +package com.pixelized.desktop.lwa.ui.screen.gamemaster.action + +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.shared.lwa.protocol.websocket.GameAdminEvent +import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent + +class GMActionUseCase( + private val characterRepository: CharacterSheetRepository, + private val networkRepository: NetworkRepository, + private val campaignRepository: CampaignRepository, +) { + suspend fun invalidateServerCache() { + networkRepository.share( + GameAdminEvent.ServerSynchronization( + timestamp = System.currentTimeMillis(), + ) + ) + } + + suspend fun healPlayerParty() { + 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) { + characterRepository.updateCharacter( + sheet = updated, + create = false, + ) + } + } + } + + suspend fun toggleNpcVisibility() { + networkRepository.share( + GameMasterEvent.ToggleNpc( + timestamp = System.currentTimeMillis(), + ) + ) + } + + suspend fun togglePlayerVisibility() { + networkRepository.share( + GameMasterEvent.TogglePlayer( + timestamp = System.currentTimeMillis(), + ) + ) + } +} \ No newline at end of file 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 3a980c3..c80f8be 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,23 +3,36 @@ 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.confirmation.ConfirmationDialogUio import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackUio -import com.pixelized.shared.lwa.protocol.websocket.GameAdminEvent -import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch +import lwacharactersheet.composeapp.generated.resources.Res +import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_npc__description +import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_npc__title +import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_player__description +import lwacharactersheet.composeapp.generated.resources.game_master__actions__hide_player__title +import lwacharactersheet.composeapp.generated.resources.game_master__actions__on_server_sync__description +import lwacharactersheet.composeapp.generated.resources.game_master__actions__on_server_sync__title +import lwacharactersheet.composeapp.generated.resources.game_master__actions__party_heal__description +import lwacharactersheet.composeapp.generated.resources.game_master__actions__party_heal__title +import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_npc__description +import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_npc__title +import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_player__description +import lwacharactersheet.composeapp.generated.resources.game_master__actions__show_player__title +import org.jetbrains.compose.resources.StringResource +import org.jetbrains.compose.resources.getString class GMActionViewModel( - private val characterRepository: CharacterSheetRepository, - private val networkRepository: NetworkRepository, - private val campaignRepository: CampaignRepository, + private val actionUseCase: GMActionUseCase, + campaignRepository: CampaignRepository, ) : ViewModel() { private val _error = MutableSharedFlow() @@ -39,68 +52,102 @@ class GMActionViewModel( initialValue = null, ) + private val _validationDialog = MutableStateFlow(null) + val validationDialog: StateFlow = _validationDialog + suspend fun onServerSync() { - try { - networkRepository.share( - GameAdminEvent.ServerSynchronization( - timestamp = System.currentTimeMillis(), - ) - ) - } catch (exception: Exception) { - val message = ErrorSnackUio.from(exception = exception) - _error.emit(message) - } - } - - 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) { + showConfirmationDialog( + title = Res.string.game_master__actions__on_server_sync__title, + description = Res.string.game_master__actions__on_server_sync__description, + onConfirmationRequest = { try { - characterRepository.updateCharacter( - sheet = updated, - create = false, - ) + actionUseCase.invalidateServerCache() } catch (exception: Exception) { val message = ErrorSnackUio.from(exception = exception) _error.emit(message) } + }, + onDismissRequest = { + _validationDialog.value = null } - } + ) } - 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 onPartyHeal() { + showConfirmationDialog( + title = Res.string.game_master__actions__party_heal__title, + description = Res.string.game_master__actions__party_heal__description, + onConfirmationRequest = { + try { + actionUseCase.healPlayerParty() + } catch (exception: Exception) { + val message = ErrorSnackUio.from(exception = exception) + _error.emit(message) + } + }, + ) } suspend fun onPlayerVisibility() { - try { - networkRepository.share( - GameMasterEvent.TogglePlayer( - timestamp = System.currentTimeMillis(), - ) - ) - } catch (exception: Exception) { - val message = ErrorSnackUio.from(exception = exception) - _error.emit(message) - } + showConfirmationDialog( + title = when (actions.value?.party) { + true -> Res.string.game_master__actions__hide_player__title + else -> Res.string.game_master__actions__show_player__title + }, + description = when (actions.value?.party) { + true -> Res.string.game_master__actions__hide_player__description + else -> Res.string.game_master__actions__show_player__description + }, + onConfirmationRequest = { + try { + actionUseCase.togglePlayerVisibility() + } catch (exception: Exception) { + val message = ErrorSnackUio.from(exception = exception) + _error.emit(message) + } + }, + ) + } + + suspend fun onNpcVisibility() { + showConfirmationDialog( + title = when (actions.value?.npc) { + true -> Res.string.game_master__actions__hide_npc__title + else -> Res.string.game_master__actions__show_npc__title + }, + description = when (actions.value?.npc) { + true -> Res.string.game_master__actions__hide_npc__description + else -> Res.string.game_master__actions__show_npc__description + }, + onConfirmationRequest = { + try { + actionUseCase.toggleNpcVisibility() + } catch (exception: Exception) { + val message = ErrorSnackUio.from(exception = exception) + _error.emit(message) + } + }, + ) + } + + private suspend inline fun showConfirmationDialog( + title: StringResource, + description: StringResource, + crossinline onConfirmationRequest: suspend () -> Unit, + crossinline onDismissRequest: () -> Unit = { _validationDialog.value = null }, + ) { + _validationDialog.value = ConfirmationDialogUio( + title = getString(title), + description = getString(description), + onConfirmRequest = { + viewModelScope.launch { + onConfirmationRequest() + onDismissRequest() + } + }, + onDismissRequest = { + onDismissRequest() + }, + ) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/character/list/GMCharacterPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/character/list/GMCharacterPage.kt index 79899c8..b5e8c3a 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/character/list/GMCharacterPage.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/character/list/GMCharacterPage.kt @@ -109,7 +109,6 @@ fun GMCharacterPage( .width(width = 128.dp * 4) .fillMaxHeight(), transitionSpec = rememberTransitionAnimation(direction = LayoutDirection.Rtl), - blurController = blurController, detailPanelViewModel = characterDetailViewModel, characterDiminishedViewModel = dismissedViewModel, characteristicDialogViewModel = characteristicDialogViewModel, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/color/LwaColors.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/color/LwaColors.kt index 98bfedc..968d573 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/color/LwaColors.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/color/LwaColors.kt @@ -55,7 +55,10 @@ data class LwaColors( @Composable @Stable fun darkLwaColorTheme( - base: Colors = darkColors(), + base: Colors = darkColors( + primary = Color(0xFFBB86FC), + primaryVariant = Color(0xB2BB86FC), + ), elevated: LwaColors.Elevated = LwaColors.Elevated( base1dp = base.calculateElevatedColor( color = base.surface,