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,