Change the Damage/Fatigue/Diminished text message feature.

This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2025-04-10 11:10:51 +02:00
parent 8f87c63e34
commit 193b0d85d5
12 changed files with 51 additions and 26 deletions

View file

@ -58,7 +58,7 @@ class DataSyncViewModel(
networkRepository.status
.filter { status -> status == NetworkRepository.Status.CONNECTED }
.flatMapLatest { campaignRepository.campaignFlow.map { it.instances } }
.flatMapLatest { campaignRepository.campaignFlow().map { it.instances } }
.distinctUntilChanged()
.onEach { instances ->
instances.forEach { characterSheetId ->

View file

@ -33,7 +33,7 @@ class AlterationRepository(
*/
@OptIn(ExperimentalCoroutinesApi::class)
private val campaignCharactersFlow: Flow<Map<String, List<String>>> =
campaignRepository.campaignFlow
campaignRepository.campaignFlow()
.flatMapLatest { campaign ->
val flows = campaign.instances.map {
characterRepository.characterDetailFlow(characterSheetId = it)

View file

@ -1,9 +1,14 @@
package com.pixelized.desktop.lwa.repository.campaign
import com.pixelized.shared.lwa.model.campaign.Campaign
import kotlinx.coroutines.flow.StateFlow
class CampaignRepository(
private val store: CampaignStore,
) {
val campaignFlow = store.campaignFlow()
fun campaignFlow(): StateFlow<Campaign> {
return store.campaignFlow()
}
suspend fun updateCampaign() {
store.updateCampaignFlow()

View file

@ -15,7 +15,9 @@ class CharacterSheetRepository(
) {
private val scope = CoroutineScope(Dispatchers.IO + Job())
val characterSheetPreviewFlow get() = store.previewFlow
fun characterSheetPreviewFlow(): StateFlow<List<CharacterSheetPreview>> {
return store.previewFlow
}
suspend fun updateCharacterPreviews() {
store.updateCharactersPreviewFlow()
@ -26,7 +28,7 @@ class CharacterSheetRepository(
}
fun characterPreview(characterId: String?): CharacterSheetPreview? {
return characterSheetPreviewFlow.value.firstOrNull { it.characterSheetId == characterId }
return store.previewFlow.value.firstOrNull { it.characterSheetId == characterId }
}
fun characterDetail(

View file

@ -15,10 +15,12 @@ class RollHistoryRepository(
) {
private val scope = CoroutineScope(Dispatchers.IO + Job())
val rolls: SharedFlow<RollEvent> = network.data
private val rolls: SharedFlow<RollEvent> = network.data
.filterIsInstance(RollEvent::class)
.shareIn(
scope = scope,
started = SharingStarted.Eagerly,
)
fun rolls(): SharedFlow<RollEvent> = rolls
}

View file

@ -64,7 +64,7 @@ abstract class CharacterRibbonViewModel(
@OptIn(ExperimentalCoroutinesApi::class)
val characters: StateFlow<List<CharacterPortraitUio>> = combine(
settingsRepository.settingsFlow(),
campaignRepository.campaignFlow,
campaignRepository.campaignFlow(),
) { settings, campaign -> campaign to settings }
.distinctUntilChanged()
.flatMapLatest { (campaign, settings) ->
@ -111,7 +111,7 @@ abstract class CharacterRibbonViewModel(
LaunchedEffect(characterSheetId) {
combine(
settingsRepository.settingsFlow(),
rollHistoryRepository.rolls,
rollHistoryRepository.rolls(),
) { settings, roll ->
if (settings.portrait.dynamicDice && characterSheetId == roll.characterSheetId) {
state.value = CharacterPortraitRollUio(

View file

@ -4,6 +4,7 @@ import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.tween
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.desktop.lwa.repository.settings.SettingsRepository
import com.pixelized.shared.lwa.protocol.websocket.SocketMessage
@ -16,6 +17,7 @@ import kotlinx.coroutines.flow.stateIn
class CampaignChatViewModel(
private val settingsRepository: SettingsRepository,
private val campaignRepository: CampaignRepository,
networkRepository: NetworkRepository,
textMessageFactory: TextMessageFactory,
) : ViewModel() {
@ -36,14 +38,16 @@ class CampaignChatViewModel(
val messages = combine(
settingsRepository.settingsFlow(),
campaignRepository.campaignFlow(),
networkRepository.data.runningFold(
initial = mutableListOf(),
operation = List<SocketMessage>::plus
)
) { settings, messages ->
) { settings, campaign, messages ->
messages.mapNotNull { message ->
textMessageFactory.convertToTextMessage(
settings = settings,
campaign = campaign,
message = message,
)
}.takeLast(

View file

@ -6,8 +6,7 @@ import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.Characteristic
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.DiminishedTextMessageUio
import com.pixelized.desktop.lwa.ui.screen.campaign.text.messages.RollTextMessageUio
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.model.campaign.Campaign
import com.pixelized.shared.lwa.protocol.websocket.ApiSynchronisation
import com.pixelized.shared.lwa.protocol.websocket.CampaignEvent
import com.pixelized.shared.lwa.protocol.websocket.CharacterSheetEvent
@ -29,6 +28,7 @@ class TextMessageFactory(
suspend fun convertToTextMessage(
settings: Settings,
campaign: Campaign,
message: SocketMessage,
): TextMessage? {
return when (message) {
@ -62,6 +62,11 @@ class TextMessageFactory(
is CharacterSheetEvent -> when (message) {
is CharacterSheetEvent.UpdateDiminished -> {
// only display the message if the character is in the party or npcs.
val isInParty = campaign.characters.contains(message.characterSheetId)
val isInNpcs = campaign.npcs.contains(message.characterSheetId)
if ((isInParty || isInNpcs).not()) return null
// get the character sheet
val sheetPreview = characterSheetRepository
.characterPreview(characterId = message.characterSheetId)
?: return null
@ -75,10 +80,14 @@ class TextMessageFactory(
}
is CharacterSheetEvent.UpdateDamage -> {
val sheet = characterSheetRepository.characterDetail(
characterSheetId = message.characterSheetId,
) ?: return null
// only display the message if the character is in the party or npcs.
val isInParty = campaign.characters.contains(message.characterSheetId)
val isInNpcs = campaign.npcs.contains(message.characterSheetId)
if ((isInParty || isInNpcs).not()) return null
// get the character sheet
val sheet = characterSheetRepository
.characterDetail(characterSheetId = message.characterSheetId)
?: return null
// We are talking about damage / consumption there so old value have to be put first.
val value = message.oldValue - message.damage
@ -95,10 +104,13 @@ class TextMessageFactory(
}
is CharacterSheetEvent.UpdateFatigue -> {
val sheet = characterSheetRepository.characterDetail(
characterSheetId = message.characterSheetId,
) ?: return null
// only display the message if the character is in the party.
val isInParty = campaign.characters.contains(message.characterSheetId)
if (isInParty.not()) return null
// get the character sheet
val sheet = characterSheetRepository
.characterDetail(characterSheetId = message.characterSheetId)
?: return null
// We are talking about damage / consumption there so old value have to be put first.
val value = message.oldValue - message.fatigue

View file

@ -17,7 +17,7 @@ class CampaignToolbarViewModel(
val status = networkRepository.status
val title = campaignRepository.campaignFlow
val title = campaignRepository.campaignFlow()
.map { it.scene.name }
.stateIn(
scope = viewModelScope,

View file

@ -24,7 +24,7 @@ class GMActionViewModel(
private val _error = MutableSharedFlow<ErrorSnackUio>()
val error: SharedFlow<ErrorSnackUio> get() = _error
val actions: StateFlow<ActionPageUio?> = campaignRepository.campaignFlow
val actions: StateFlow<ActionPageUio?> = campaignRepository.campaignFlow()
.map {
ActionPageUio(
party = it.options.showParty,
@ -39,7 +39,7 @@ class GMActionViewModel(
)
suspend fun onPartyHeal() {
campaignRepository.campaignFlow.value.characters.forEach { characterSheetId ->
campaignRepository.campaignFlow().value.characters.forEach { characterSheetId ->
val sheet = characterRepository.characterDetail(
characterSheetId = characterSheetId,
) ?: return@forEach

View file

@ -59,8 +59,8 @@ class GMCharacterViewModel(
)
val characters = combine(
campaignRepository.campaignFlow,
characterSheetRepository.characterSheetPreviewFlow,
campaignRepository.campaignFlow(),
characterSheetRepository.characterSheetPreviewFlow(),
filter.valueFlow.map { it.unAccent() },
tags,
selectedTagId,

View file

@ -15,8 +15,8 @@ class RollHistoryViewModel(
private var _rolls: List<RollHistoryItemUio> = emptyList()
val rolls = combine(
characterRepository.characterSheetPreviewFlow,
rollRepository.rolls,
characterRepository.characterSheetPreviewFlow(),
rollRepository.rolls(),
) { sheets, message ->
val name = sheets.firstOrNull { it.characterSheetId == message.characterSheetId }?.name ?: ""
val roll = RollHistoryItemUio(