From 67e154ed4a207b217ea01c0a3b0a57de951a123c Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Thu, 20 Mar 2025 23:22:56 +0100 Subject: [PATCH] Add character portrait display feature. --- .../kotlin/com/pixelized/desktop/lwa/App.kt | 4 +- .../com/pixelized/desktop/lwa/Module.kt | 2 + .../repository/campaign/CampaignRepository.kt | 2 +- .../lwa/repository/campaign/CampaignStore.kt | 2 +- .../ui/overlay/portrait/PortraitOverlay.kt | 100 ++++++++++++++++++ .../portrait/PortraitOverlayViewModel.kt | 51 +++++++++ .../lwa/ui/screen/campaign/CampaignScreen.kt | 11 +- .../campaign/player/CharacterPortrait.kt | 7 +- .../campaign/player/CharacterPortraitRoll.kt | 3 +- .../campaign/player/ribbon/npc/NpcRibbon.kt | 3 - .../ui/screen/campaign/text/CampaignChat.kt | 3 +- .../campaign/text/TextMessageFactory.kt | 2 + .../gamemaster/GameMasterActionUseCase.kt | 10 +- .../ui/screen/gamemaster/GameMasterFactory.kt | 1 + .../ui/screen/gamemaster/items/GMCharacter.kt | 1 - .../desktop/lwa/ui/theme/size/LwaSize.kt | 12 +++ .../com/pixelized/server/lwa/server/Engine.kt | 7 +- .../lwa/protocol/websocket/GameEvent.kt | 13 +++ 18 files changed, 214 insertions(+), 20 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/portrait/PortraitOverlay.kt create mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/portrait/PortraitOverlayViewModel.kt create mode 100644 shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/websocket/GameEvent.kt diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt index 1a5fdd1..f3fdbb2 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/App.kt @@ -52,11 +52,11 @@ import com.pixelized.desktop.lwa.ui.navigation.window.destination.RollHistoryWin import com.pixelized.desktop.lwa.ui.navigation.window.rememberMaxWindowHeight import com.pixelized.desktop.lwa.ui.overlay.roll.RollHostState import com.pixelized.desktop.lwa.ui.overlay.roll.RollOverlay -import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortraitDefault import com.pixelized.desktop.lwa.ui.screen.characterSheet.CharacterSheetMainNavHost import com.pixelized.desktop.lwa.ui.screen.gamemaster.GameMasterScreen import com.pixelized.desktop.lwa.ui.screen.rollhistory.RollHistoryPage import com.pixelized.desktop.lwa.ui.theme.LwaTheme +import com.pixelized.desktop.lwa.ui.theme.lwa import com.pixelized.desktop.lwa.utils.InstallCoil import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking @@ -108,7 +108,7 @@ fun ApplicationScope.LwaApplication() { size = DpSize( width = 800.dp, height = min( - a = 56.dp + CharacterPortraitDefault.size.height * 6 + 8.dp * 7 + 40.dp, + a = 56.dp + 128.dp * 6 + 8.dp * 7 + 40.dp, // 128 is the height of a minimized portrait. b = maxWindowHeight, ), ), 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 9b52476..a983837 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt @@ -15,6 +15,7 @@ import com.pixelized.desktop.lwa.repository.settings.SettingsRepository import com.pixelized.desktop.lwa.repository.settings.SettingsStore import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterDetailCharacteristicDialogViewModel import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogFactory +import com.pixelized.desktop.lwa.ui.overlay.portrait.PortraitOverlayViewModel import com.pixelized.desktop.lwa.ui.overlay.roll.RollViewModel import com.pixelized.desktop.lwa.ui.screen.campaign.network.NetworkFactory import com.pixelized.desktop.lwa.ui.screen.campaign.network.NetworkViewModel @@ -138,6 +139,7 @@ val viewModelDependencies viewModelOf(::SettingsViewModel) viewModelOf(::LevelUpViewModel) viewModelOf(::GameMasterViewModel) + viewModelOf(::PortraitOverlayViewModel) } val useCaseDependencies diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignRepository.kt index 0bd24e9..6d8ff20 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignRepository.kt @@ -59,8 +59,8 @@ class CampaignRepository( initialValue = campaignFlow.value.character(id = characterInstanceId), ) } - @Deprecated(message = "Check if deprecated") + @Deprecated(message = "Check if deprecated") fun characterInstance( characterInstanceId: Campaign.CharacterInstance.Id, ): Campaign.CharacterInstance { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignStore.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignStore.kt index 0b1a648..826536b 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignStore.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/campaign/CampaignStore.kt @@ -6,10 +6,10 @@ import com.pixelized.shared.lwa.model.campaign.Campaign import com.pixelized.shared.lwa.model.campaign.character import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory import com.pixelized.shared.lwa.model.campaign.npc -import com.pixelized.shared.lwa.protocol.websocket.SocketMessage import com.pixelized.shared.lwa.protocol.websocket.CampaignMessage import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation +import com.pixelized.shared.lwa.protocol.websocket.SocketMessage import com.pixelized.shared.lwa.usecase.CampaignUseCase import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/portrait/PortraitOverlay.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/portrait/PortraitOverlay.kt new file mode 100644 index 0000000..2095b64 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/portrait/PortraitOverlay.kt @@ -0,0 +1,100 @@ +package com.pixelized.desktop.lwa.ui.overlay.portrait + +import androidx.compose.animation.AnimatedContent +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.animation.fadeIn +import androidx.compose.animation.fadeOut +import androidx.compose.animation.togetherWith +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.size +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.State +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.FilterQuality +import coil3.compose.AsyncImage +import com.pixelized.desktop.lwa.ui.theme.lwa +import kotlinx.coroutines.launch +import lwacharactersheet.composeapp.generated.resources.Res +import lwacharactersheet.composeapp.generated.resources.ic_cancel_24dp +import org.jetbrains.compose.resources.painterResource +import org.koin.compose.viewmodel.koinViewModel + +@Composable +fun PortraitOverlay( + modifier: Modifier = Modifier, + viewModel: PortraitOverlayViewModel = koinViewModel(), +) { + val scope = rememberCoroutineScope() + val portrait = viewModel.portrait.collectAsState() + val isGameMaster = viewModel.isGameMaster.collectAsState() + + PortraitContent( + modifier = modifier, + portrait = portrait, + isGameMaster = isGameMaster, + onGameMaster = { + scope.launch { + viewModel.dismissPortrait() + } + } + ) +} + +@Composable +private fun PortraitContent( + modifier: Modifier = Modifier, + portrait: State, + isGameMaster: State, + onGameMaster: () -> Unit, +) { + AnimatedContent( + modifier = Modifier + .clip(shape = MaterialTheme.lwa.shapes.portrait) + .then(other = modifier), + targetState = portrait.value, + transitionSpec = { + fadeIn() togetherWith fadeOut() + } + ) { + when (it) { + null -> Box( + modifier = Modifier.size(MaterialTheme.lwa.size.portrait.maximized) + ) + + else -> Box( + modifier = Modifier.size(MaterialTheme.lwa.size.portrait.maximized) + ) { + AsyncImage( + modifier = Modifier.matchParentSize(), + model = it, + filterQuality = FilterQuality.High, + contentDescription = null + ) + + AnimatedVisibility( + modifier = Modifier.align(alignment = Alignment.TopEnd), + visible = isGameMaster.value, + enter = fadeIn(), + exit = fadeOut(), + ) { + IconButton( + onClick = onGameMaster, + ) { + Icon( + painter = painterResource(Res.drawable.ic_cancel_24dp), + tint = MaterialTheme.lwa.colorScheme.base.primary, + contentDescription = null + ) + } + } + } + } + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/portrait/PortraitOverlayViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/portrait/PortraitOverlayViewModel.kt new file mode 100644 index 0000000..db1dca8 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/portrait/PortraitOverlayViewModel.kt @@ -0,0 +1,51 @@ +package com.pixelized.desktop.lwa.ui.overlay.portrait + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository +import com.pixelized.desktop.lwa.repository.network.NetworkRepository +import com.pixelized.desktop.lwa.repository.settings.SettingsRepository +import com.pixelized.shared.lwa.protocol.websocket.GameEvent +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.stateIn + +class PortraitOverlayViewModel( + private val networkRepository: NetworkRepository, + settingsRepository: SettingsRepository, + characterSheetRepository: CharacterSheetRepository, +) : ViewModel() { + + @OptIn(ExperimentalCoroutinesApi::class) + val portrait = networkRepository.data + .mapNotNull { it as? GameEvent.DisplayPortrait } + .flatMapLatest { characterSheetRepository.characterDetailFlow(characterSheetId = it.characterSheetId) } + .map { it?.portrait } + .distinctUntilChanged() + .stateIn( + scope = viewModelScope, + started = SharingStarted.Eagerly, + initialValue = null + ) + + val isGameMaster = settingsRepository.settingsFlow() + .map { settings -> settings.isGameMaster ?: false } + .stateIn( + scope = viewModelScope, + started = SharingStarted.Eagerly, + initialValue = false + ) + + suspend fun dismissPortrait() { + networkRepository.share( + GameEvent.DisplayPortrait( + timestamp = System.currentTimeMillis(), + characterSheetId = null, + ) + ) + } +} \ 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 dc3fd3b..c60b4c9 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 @@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width import androidx.compose.material.Surface import androidx.compose.runtime.Composable @@ -35,6 +36,7 @@ import com.pixelized.desktop.lwa.ui.composable.character.characteristic.Characte import com.pixelized.desktop.lwa.ui.composable.key.KeyHandler import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController import com.pixelized.desktop.lwa.ui.navigation.screen.destination.navigateToLevelScreen +import com.pixelized.desktop.lwa.ui.overlay.portrait.PortraitOverlay import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailPanel import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailViewModel import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDiminishedViewModel @@ -84,7 +86,14 @@ fun CampaignScreen( }, main = { - + Box( + modifier = Modifier.matchParentSize(), + contentAlignment = Alignment.BottomCenter, + ) { + PortraitOverlay( + modifier = Modifier.padding(all = 8.dp) + ) + } }, chat = { CampaignChat( diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/CharacterPortrait.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/CharacterPortrait.kt index dc56554..11daa96 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/CharacterPortrait.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/CharacterPortrait.kt @@ -54,11 +54,6 @@ import org.jetbrains.compose.resources.painterResource import kotlin.math.max import kotlin.math.min -@Stable -object CharacterPortraitDefault { - val size = DpSize(96.dp, 128.dp) -} - @Stable data class CharacterPortraitUio( val id: Campaign.CharacterInstance.Id, @@ -82,7 +77,7 @@ data class CharacterPortraitUio( @Composable fun CharacterPortrait( modifier: Modifier = Modifier, - size: DpSize = CharacterPortraitDefault.size, + size: DpSize = MaterialTheme.lwa.size.portrait.minimized, levelUpOffset: Dp = 9.dp, character: CharacterPortraitUio, onCharacter: (id: Campaign.CharacterInstance.Id) -> Unit, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/CharacterPortraitRoll.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/CharacterPortraitRoll.kt index d4b0a66..e2aeb1a 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/CharacterPortraitRoll.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/CharacterPortraitRoll.kt @@ -37,6 +37,7 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.DpSize import androidx.compose.ui.unit.dp +import com.pixelized.desktop.lwa.ui.theme.lwa import com.pixelized.shared.lwa.model.campaign.Campaign import kotlinx.coroutines.launch import lwacharactersheet.composeapp.generated.resources.Res @@ -61,7 +62,7 @@ data class CharacterPortraitRollAnimation( @Composable fun CharacterPortraitRoll( modifier: Modifier = Modifier, - size: DpSize = CharacterPortraitDefault.size, + size: DpSize = MaterialTheme.lwa.size.portrait.minimized, value: CharacterPortraitRollUio?, onLeftClick: (CharacterPortraitRollUio) -> Unit, onRightClick: (CharacterPortraitRollUio) -> Unit, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/npc/NpcRibbon.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/npc/NpcRibbon.kt index dadc3a6..a928641 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/npc/NpcRibbon.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/npc/NpcRibbon.kt @@ -10,7 +10,6 @@ import androidx.compose.runtime.collectAsState import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortrait -import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortraitDefault import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortraitRoll import com.pixelized.shared.lwa.model.campaign.Campaign import org.koin.compose.viewmodel.koinViewModel @@ -38,7 +37,6 @@ fun NpcRibbon( modifier = Modifier.animateItem(), ) { CharacterPortraitRoll( - size = CharacterPortraitDefault.size, value = viewModel.roll(characterId = it.id).value, onRightClick = { viewModel.onPortraitRollRightClick(characterId = it.characterId) @@ -48,7 +46,6 @@ fun NpcRibbon( }, ) CharacterPortrait( - size = CharacterPortraitDefault.size, character = it, onCharacter = onCharacter, onLevelUp = onLevelUp, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/text/CampaignChat.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/text/CampaignChat.kt index 5be2552..7be539b 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/text/CampaignChat.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/text/CampaignChat.kt @@ -35,7 +35,6 @@ import androidx.compose.ui.window.WindowState import com.pixelized.desktop.lwa.ui.navigation.window.LocalWindowState import com.pixelized.desktop.lwa.ui.screen.campaign.CampaignLayoutScope import com.pixelized.desktop.lwa.ui.screen.campaign.LocalCampaignLayoutScope -import com.pixelized.desktop.lwa.ui.screen.campaign.player.CharacterPortraitDefault import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.CharacteristicTextMessage import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.CharacteristicTextMessageUio import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.DiminishedTextMessage @@ -90,7 +89,7 @@ fun CampaignChat( modifier = modifier .size( width = animatedChatWidth.value, - height = CharacterPortraitDefault.size.height * 2 + 8.dp, + height = MaterialTheme.lwa.size.portrait.minimized.height * 2 + 8.dp, ) .graphicsLayer { alpha = chatViewModel.chatAnimatedVisibility.value diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/text/TextMessageFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/text/TextMessageFactory.kt index b5e40a6..800991a 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/text/TextMessageFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/text/TextMessageFactory.kt @@ -9,6 +9,7 @@ import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.TextMessage import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1.CharacterInstanceJsonV1.CharacteristicV1.Damage import com.pixelized.shared.lwa.model.campaign.CampaignJsonV1.CharacterInstanceJsonV1.CharacteristicV1.Power import com.pixelized.shared.lwa.protocol.websocket.CampaignMessage +import com.pixelized.shared.lwa.protocol.websocket.GameEvent import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation import com.pixelized.shared.lwa.protocol.websocket.RollMessage @@ -105,6 +106,7 @@ class TextMessageFactory( is ToggleActiveAlteration -> null is UpdateSkillUsageMessage -> null is GameMasterEvent -> null + is GameEvent.DisplayPortrait -> null } } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterActionUseCase.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterActionUseCase.kt index f4de737..5b52393 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterActionUseCase.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterActionUseCase.kt @@ -1,17 +1,25 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository +import com.pixelized.desktop.lwa.repository.network.NetworkRepository import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterUio.Action +import com.pixelized.shared.lwa.protocol.websocket.GameEvent class GameMasterActionUseCase( private val campaignRepository: CampaignRepository, + private val networkRepository: NetworkRepository, ) { suspend fun handleAction( characterSheetId: String, action: Action, ) { when (action) { - Action.DisplayPortrait -> TODO() + Action.DisplayPortrait -> networkRepository.share( + GameEvent.DisplayPortrait( + timestamp = System.currentTimeMillis(), + characterSheetId = characterSheetId, + ) + ) Action.AddToGroup -> campaignRepository.addCharacter( characterSheetId = characterSheetId, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt index 2a35d02..f69a885 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt @@ -92,6 +92,7 @@ class GameMasterFactory { } // build the cell action list val actions = buildList { + add(Action.DisplayPortrait) add( when (characterInstanceId) { null -> Action.AddToGroup diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacter.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacter.kt index 24f5d51..7287157 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacter.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/items/GMCharacter.kt @@ -17,7 +17,6 @@ import androidx.compose.material.IconButton import androidx.compose.material.MaterialTheme import androidx.compose.material.Text import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.Edit import androidx.compose.material.icons.filled.MoreVert import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/size/LwaSize.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/size/LwaSize.kt index d036772..cec5868 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/size/LwaSize.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/theme/size/LwaSize.kt @@ -9,8 +9,15 @@ import androidx.compose.ui.unit.dp data class LwaSize( + val portrait: Portrait, val sheet: Sheet, ) { + @Stable + data class Portrait( + val maximized: DpSize, + val minimized: DpSize, + ) + @Stable data class Sheet( val subCategory: Dp, @@ -21,12 +28,17 @@ data class LwaSize( @Composable @Stable fun lwaSize( + portrait: LwaSize.Portrait = LwaSize.Portrait( + minimized = DpSize(width = 96.dp, height = 128.dp), + maximized = DpSize(width = 512.dp, height = 512.dp), + ), sheet: LwaSize.Sheet = LwaSize.Sheet( subCategory = 14.dp, characteristic = DpSize(width = 76.dp, height = 110.dp), ), ) = remember { LwaSize( + portrait = portrait, sheet = sheet, ) } \ No newline at end of file diff --git a/server/src/main/kotlin/com/pixelized/server/lwa/server/Engine.kt b/server/src/main/kotlin/com/pixelized/server/lwa/server/Engine.kt index 288ab43..210eead 100644 --- a/server/src/main/kotlin/com/pixelized/server/lwa/server/Engine.kt +++ b/server/src/main/kotlin/com/pixelized/server/lwa/server/Engine.kt @@ -5,11 +5,12 @@ import com.pixelized.server.lwa.model.campaign.CampaignService import com.pixelized.server.lwa.model.character.CharacterSheetService import com.pixelized.shared.lwa.model.campaign.Campaign import com.pixelized.shared.lwa.model.campaign.factory.CampaignJsonFactory -import com.pixelized.shared.lwa.protocol.websocket.SocketMessage import com.pixelized.shared.lwa.protocol.websocket.CampaignMessage +import com.pixelized.shared.lwa.protocol.websocket.GameEvent import com.pixelized.shared.lwa.protocol.websocket.GameMasterEvent import com.pixelized.shared.lwa.protocol.websocket.RestSynchronisation import com.pixelized.shared.lwa.protocol.websocket.RollMessage +import com.pixelized.shared.lwa.protocol.websocket.SocketMessage import com.pixelized.shared.lwa.protocol.websocket.ToggleActiveAlteration import com.pixelized.shared.lwa.protocol.websocket.UpdateSkillUsageMessage import kotlinx.coroutines.flow.MutableSharedFlow @@ -65,6 +66,10 @@ class Engine( is GameMasterEvent.TogglePlayer -> campaignService.updateToggleParty() is GameMasterEvent.ToggleNpc -> campaignService.updateToggleNpc() } + + is GameEvent -> when (message) { + is GameEvent.DisplayPortrait -> Unit // Nothing to do here. + } } } } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/websocket/GameEvent.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/websocket/GameEvent.kt new file mode 100644 index 0000000..a59c2cd --- /dev/null +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/protocol/websocket/GameEvent.kt @@ -0,0 +1,13 @@ +package com.pixelized.shared.lwa.protocol.websocket + +import kotlinx.serialization.Serializable + +@Serializable +sealed interface GameEvent : SocketMessage { + + @Serializable + data class DisplayPortrait( + override val timestamp: Long, + val characterSheetId: String?, + ) : GameEvent +} \ No newline at end of file