From 4ed11660c31bf4ec16fe1bbc8de8a20c9af880d0 Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Mon, 24 Feb 2025 21:35:33 +0100 Subject: [PATCH] Link the player character ribbon to the server. --- .../com/pixelized/desktop/lwa/Module.kt | 4 +- .../desktop/lwa/business/ExpressionUseCase.kt | 4 ++ .../lwa/parser/expression/Expression.kt | 8 +++ .../lwa/parser/expression/ExpressionParser.kt | 28 +++++++++-- .../alteration/AlterationRepository.kt | 2 +- .../CharacterSheetRepository.kt | 11 +--- .../campaign/player/detail/CharacterDetail.kt | 14 +++--- .../player/detail/CharacterDetailFactory.kt | 39 +++++++++++++++ .../player/detail/CharacterDetailViewModel.kt | 42 ++++++++++------ .../player/ribbon/PlayerRibbonFactory.kt | 36 ++++++++++--- .../player/ribbon/PlayerRibbonViewModel.kt | 50 +++++++++++++++---- .../detail/CharacterSheetFactory.kt | 1 - .../detail/CharacterSheetViewModel.kt | 2 +- .../lwa/business/DamageBonusUseCaseTest.kt | 1 + .../business/SkillNormalizerUseCaseText.kt | 1 + .../parser/expression/ExpressionParserTest.kt | 20 ++++++++ .../model/characterSheet/CharacterSheet.kt | 37 +++++++------- 17 files changed, 228 insertions(+), 72 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailFactory.kt 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 e183690..4fccf22 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt @@ -20,6 +20,7 @@ import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository import com.pixelized.desktop.lwa.repository.settings.SettingsFactory import com.pixelized.desktop.lwa.repository.settings.SettingsRepository import com.pixelized.desktop.lwa.repository.settings.SettingsStore +import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailFactory import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDetailViewModel import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.CharacterDiminishedViewModel import com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.PlayerRibbonFactory @@ -105,6 +106,7 @@ val factoryDependencies factoryOf(::SettingsFactory) factoryOf(::CampaignJsonFactory) factoryOf(::PlayerRibbonFactory) + factoryOf(::CharacterDetailFactory) } val viewModelDependencies @@ -134,4 +136,4 @@ val useCaseDependencies factoryOf(::ExpressionUseCase) factoryOf(::SettingsUseCase) factoryOf(::CharacterSheetUseCase) - } + } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/business/ExpressionUseCase.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/business/ExpressionUseCase.kt index ca27eb0..d558b32 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/business/ExpressionUseCase.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/business/ExpressionUseCase.kt @@ -99,6 +99,10 @@ class ExpressionUseCase( rollUseCase.roll(expression.dice) } + is Expression.UrlExpression -> { + 0 // Ignore this case. + } + is Expression.WordExpression -> when (expression.word.type) { Word.Type.BDC -> evaluate(expressionParser.parse(sheet.damageBonus)) Word.Type.BDD -> evaluate(expressionParser.parse(sheet.damageBonus)) diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/parser/expression/Expression.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/parser/expression/Expression.kt index e26a082..14b9c4b 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/parser/expression/Expression.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/parser/expression/Expression.kt @@ -67,6 +67,14 @@ sealed interface Expression { } } + data class UrlExpression( + val url: String, + ) : Expression { + override fun toString(): String { + return url + } + } + data class DiceExpression( val dice: Dice, ) : Expression { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/parser/expression/ExpressionParser.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/parser/expression/ExpressionParser.kt index 79c21ec..9ad9d6e 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/parser/expression/ExpressionParser.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/parser/expression/ExpressionParser.kt @@ -2,6 +2,9 @@ package com.pixelized.desktop.lwa.parser.expression import com.pixelized.desktop.lwa.parser.dice.DiceParser import com.pixelized.desktop.lwa.parser.word.WordParser +import org.jetbrains.skia.toIPoint +import java.net.URI +import java.net.URL /** * Highly inspired by the following javascript implementation: @@ -15,6 +18,12 @@ class ExpressionParser( private val tokenBreak = arrayOf( '+', '-', '/', '*', '(', ')', ',' ) + private val tokenBreakException = mapOf( + '/' to listOf("http:", "https:"), + '.' to listOf("http:", "https:"), + '+' to listOf("http:", "https:"), + '-' to listOf("http:", "https:"), + ) private val operators = mapOf( '+' to Operator( evaluations = { first, second -> Expression.Add(first, second) }, @@ -50,8 +59,11 @@ class ExpressionParser( * Every characters that are not un the [Companion.tokenBreak] list can be part of a token. * @see Companion.tokenBreak */ - private fun isToken(): Boolean = stack.peek().let { - it != null && !tokenBreak.contains(it) + private fun isToken( + currentToken: String? = null, + ): Boolean = stack.peek().let { + it != null && !tokenBreak.contains(it) || + (tokenBreakException[it]?.any { currentToken?.contains(it) ?: false } ?: false) } /** @@ -69,7 +81,7 @@ class ExpressionParser( val token = StringBuilder() do { stack.pull().let(token::append) - } while (isToken()) + } while (isToken(token.toString())) return token.toString() } @@ -186,6 +198,16 @@ class ExpressionParser( return Expression.DiceExpression(dice) } + val url = try { + println(token) + URI.create(token).toString() + } catch (_: Exception) { + null + } + if (url != null) { + return Expression.UrlExpression(url) + } + throw Error.UnRecognizedToken(actual = token, expression = stack.input) } } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/alteration/AlterationRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/alteration/AlterationRepository.kt index f460541..1d1cd9a 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/alteration/AlterationRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/alteration/AlterationRepository.kt @@ -15,7 +15,7 @@ class AlterationRepository( private val activeAlterationIdMapFlow: HashMap>> = hashMapOf("0f2117e9-e077-4354-8d77-20150df1c462" to MutableStateFlow(listOf("7c00dafa-a67d-4351-8ea9-67d933012cde", "65e37d32-3031-4bf8-9369-d2c45d2efac0"))) - fun alterations(characterId: String): Flow>> { + fun alterationsFlow(characterId: String): Flow>> { return activeAlterationIdMapFlow .getOrPut(characterId) { MutableStateFlow(emptyList()) } .map { activeAlterationIds -> diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt index 0dd4b0b..fcae482 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetRepository.kt @@ -9,7 +9,6 @@ import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn -import kotlinx.coroutines.launch class CharacterSheetRepository( private val store: CharacterSheetStore, @@ -17,6 +16,7 @@ class CharacterSheetRepository( private val scope = CoroutineScope(Dispatchers.IO + Job()) val characterSheetPreviewFlow get() = store.previewFlow + val characterDetailFlow get() = store.detailFlow fun characterPreview(characterId: String?): CharacterSheetPreview? { return characterSheetPreviewFlow.value.firstOrNull { it.id == characterId } @@ -35,17 +35,8 @@ class CharacterSheetRepository( fun characterDetailFlow( characterId: String?, - forceUpdate: Boolean = false, ): StateFlow { val initial = store.detailFlow.value[characterId] - if (forceUpdate || initial == null) { - scope.launch { - characterDetail( - characterId = characterId, - forceUpdate = forceUpdate, - ) - } - } return store.detailFlow .map { sheets -> sheets[characterId] diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetail.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetail.kt index 36c6837..879c63b 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetail.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetail.kt @@ -45,7 +45,7 @@ import org.jetbrains.compose.resources.painterResource import org.koin.compose.viewmodel.koinViewModel @Stable -data class CharacterDetailUio( +data class CharacterDetailHeaderUio( val id: String, val portrait: String?, val name: String, @@ -55,7 +55,7 @@ data class CharacterDetailUio( ) @Stable -data class CharacterDynDetailUio( +data class CharacterDetailHeaderInstanceUio( val hp: String, val pp: String, ) @@ -109,8 +109,8 @@ fun CharacterDetail( @Composable fun CharacterDetailContent( modifier: Modifier = Modifier, - character: CharacterDetailUio, - dynDetail: State, + character: CharacterDetailHeaderUio, + dynDetail: State, onDismissRequest: () -> Unit, onDiminished: () -> Unit, onHp: () -> Unit, @@ -139,7 +139,7 @@ fun CharacterDetailContent( @Composable private fun Background( modifier: Modifier = Modifier, - character: CharacterDetailUio, + character: CharacterDetailHeaderUio, ) { Surface( modifier = modifier.fillMaxSize(), @@ -168,8 +168,8 @@ private fun Background( @Composable private fun CharacterHeader( modifier: Modifier = Modifier, - character: CharacterDetailUio, - dynDetail: State, + character: CharacterDetailHeaderUio, + dynDetail: State, onDismissRequest: () -> Unit, onDiminished: () -> Unit, onHp: () -> Unit, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailFactory.kt new file mode 100644 index 0000000..f35e4c3 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailFactory.kt @@ -0,0 +1,39 @@ +package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail + +import com.pixelized.desktop.lwa.business.ExpressionUseCase +import com.pixelized.desktop.lwa.parser.expression.Expression +import com.pixelized.desktop.lwa.repository.alteration.model.FieldAlteration +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.HP +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.MOV +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.PORTRAIT +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.PP + +class CharacterDetailFactory( + private val expressionUseCase: ExpressionUseCase, +) { + + fun convertToCharacterDetailHeaderUio( + sheet: CharacterSheet?, + alterations: Map>, + ): CharacterDetailHeaderUio? { + if (sheet == null) return null + + fun List?.sum(): Int { + return this?.sumOf { + expressionUseCase.computeExpression(sheet = sheet, expression = it.expression) + } ?: 0 + } + + return CharacterDetailHeaderUio( + id = sheet.id, + portrait = alterations[PORTRAIT] + ?.firstNotNullOfOrNull { (it.expression as? Expression.UrlExpression)?.url } + ?: sheet.portrait, + name = sheet.name, + hp = "${sheet.hp + alterations[HP].sum()}", + pp = "${sheet.pp + alterations[PP].sum()}", + mov = "${sheet.movement + alterations[MOV].sum()}" + ) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailViewModel.kt index 49f6404..fd4520d 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/CharacterDetailViewModel.kt @@ -13,33 +13,43 @@ import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository import com.pixelized.shared.lwa.model.campaign.damage import com.pixelized.shared.lwa.model.campaign.power +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.flatMap +import kotlinx.coroutines.flow.flatMapConcat +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.stateIn -import androidx.compose.runtime.collectAsState -import kotlinx.coroutines.flow.map class CharacterDetailViewModel( private val characterRepository: CharacterSheetRepository, private val campaignRepository: CampaignRepository, private val alterationRepository: AlterationRepository, + private val characterDetailFactory: CharacterDetailFactory, ) : ViewModel() { private val displayedCharacterId = MutableStateFlow(null) - val detail: StateFlow = displayedCharacterId.map { id -> - val sheet = characterRepository.characterDetail(id) ?: return@map null - CharacterDetailUio( - id = sheet.id, - portrait = sheet.portrait, - name = sheet.name, - hp = "${sheet.hp}", - pp = "${sheet.pp}", - mov = "${sheet.movement}" - ) + @OptIn(ExperimentalCoroutinesApi::class) + val detail: StateFlow = displayedCharacterId.flatMapLatest { id -> + if (id != null) { + combine( + characterRepository.characterDetailFlow(characterId = id), + alterationRepository.alterationsFlow(characterId = id), + ) { sheet, alteration -> + characterDetailFactory.convertToCharacterDetailHeaderUio( + sheet = sheet, + alterations = alteration, + ) + } + } else { + flowOf(null) + } }.stateIn( scope = viewModelScope, started = SharingStarted.Eagerly, @@ -48,15 +58,15 @@ class CharacterDetailViewModel( @Composable @Stable - fun collectDynamicDetailAsState(id: String): State { + fun collectDynamicDetailAsState(id: String): State { val scope = rememberCoroutineScope() - val flow: StateFlow = remember(id) { + val flow: StateFlow = remember(id) { combine( characterRepository.characterDetailFlow(id), campaignRepository.characterInstanceFlow(id = id), ) { sheet, instance -> if (sheet == null) return@combine null - CharacterDynDetailUio( + CharacterDetailHeaderInstanceUio( hp = "${sheet.hp - instance.damage}", pp = "${sheet.power - instance.power}", ) diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonFactory.kt index 0bf52c9..415122b 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonFactory.kt @@ -1,24 +1,48 @@ package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon +import com.pixelized.desktop.lwa.business.ExpressionUseCase +import com.pixelized.desktop.lwa.parser.expression.Expression +import com.pixelized.desktop.lwa.repository.alteration.model.FieldAlteration import com.pixelized.shared.lwa.model.campaign.Campaign import com.pixelized.shared.lwa.model.campaign.damage import com.pixelized.shared.lwa.model.campaign.power import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.HP +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.PP +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CharacteristicId.THUMBNAIL -class PlayerRibbonFactory { +class PlayerRibbonFactory( + private val expressionUseCase: ExpressionUseCase, +) { fun convertToPlayerPortraitUio( characterSheet: CharacterSheet?, characterInstance: Campaign.CharacterInstance, + alterations: Map>, ): PlayerPortraitUio? { if (characterSheet == null) return null + + fun List?.sum(): Int { + return this?.sumOf { + expressionUseCase.computeExpression( + sheet = characterSheet, + expression = it.expression, + ) + } ?: 0 + } + + val maxHp = characterSheet.hp + alterations[HP].sum() + val maxPp = characterSheet.pp + alterations[PP].sum() + return PlayerPortraitUio( id = characterSheet.id, - portrait = characterSheet.thumbnail, - hp = characterSheet.hp - characterInstance.damage, - maxHp = characterSheet.hp, - pp = characterSheet.pp - characterInstance.power, - maxPp = characterSheet.pp, + portrait = alterations[THUMBNAIL] + ?.firstNotNullOfOrNull { (it.expression as? Expression.UrlExpression)?.url } + ?: characterSheet.thumbnail, + hp = maxHp - characterInstance.damage, + maxHp = maxHp, + pp = maxPp - characterInstance.power, + maxPp = maxPp, ) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonViewModel.kt index bacbef7..0a442a4 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/ribbon/PlayerRibbonViewModel.kt @@ -8,30 +8,49 @@ import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository import com.pixelized.desktop.lwa.repository.campaign.CampaignRepository import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow -import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flatMapMerge import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.launch class PlayerRibbonViewModel( private val rollHistoryRepository: RollHistoryRepository, characterRepository: CharacterSheetRepository, + alterationRepository: AlterationRepository, private val ribbonFactory: PlayerRibbonFactory, campaignRepository: CampaignRepository, ) : ViewModel() { + @OptIn(ExperimentalCoroutinesApi::class) val characters: StateFlow> = campaignRepository.campaignFlow - .map { campaign -> - campaign.characters.mapNotNull { entry -> - ribbonFactory.convertToPlayerPortraitUio( - characterSheet = characterRepository.characterDetail(characterId = entry.key), - characterInstance = entry.value, - ) - } - }.stateIn( + .flatMapMerge { campaign -> + combine>( + flows = campaign.characters.map { entry -> + combine( + characterRepository.characterDetailFlow(characterId = entry.key), + alterationRepository.alterationsFlow(characterId = entry.key), + ) { sheet, alterations -> + ribbonFactory.convertToPlayerPortraitUio( + characterSheet = sheet, + characterInstance = entry.value, + alterations = alterations, + ) + } + }, + transform = { headers -> + headers.mapNotNull { it }.toList() + } + ) + } + .stateIn( scope = viewModelScope, started = SharingStarted.Eagerly, initialValue = emptyList() @@ -39,6 +58,19 @@ class PlayerRibbonViewModel( private val rolls = hashMapOf>() + init { + viewModelScope.launch { + campaignRepository.campaignFlow.collectLatest { + it.characters.keys.forEach { id -> + characterRepository.characterDetail( + characterId = id, + forceUpdate = true, + ) + } + } + } + } + @Composable @Stable fun roll(characterId: String): State { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetFactory.kt index 55dc544..3928b18 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetFactory.kt @@ -46,7 +46,6 @@ class CharacterSheetFactory( private val skillUseCase: ExpressionUseCase, private val expressionUseCase: ExpressionUseCase, ) { - suspend fun convertToUio( sheet: CharacterSheet?, campaign: Campaign, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetViewModel.kt index eb5dc05..9e2b0cf 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetViewModel.kt @@ -73,7 +73,7 @@ class CharacterSheetViewModel( private val sheetFlow = combine( characterRepository.characterDetailFlow(characterId = argument.id), campaignRepository.campaignFlow, - alteration.alterations(characterId = argument.id), + alteration.alterationsFlow(characterId = argument.id), transform = { sheet, campaign, alterations -> factory.convertToUio( sheet = sheet, diff --git a/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/business/DamageBonusUseCaseTest.kt b/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/business/DamageBonusUseCaseTest.kt index f6fcc7b..2722e7c 100644 --- a/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/business/DamageBonusUseCaseTest.kt +++ b/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/business/DamageBonusUseCaseTest.kt @@ -1,5 +1,6 @@ package com.pixelized.desktop.lwa.business +import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase import org.junit.Test class DamageBonusUseCaseTest { diff --git a/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/business/SkillNormalizerUseCaseText.kt b/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/business/SkillNormalizerUseCaseText.kt index f5b67da..e90dedf 100644 --- a/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/business/SkillNormalizerUseCaseText.kt +++ b/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/business/SkillNormalizerUseCaseText.kt @@ -1,5 +1,6 @@ package com.pixelized.desktop.lwa.business +import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase import org.junit.Test class SkillNormalizerUseCaseText { diff --git a/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/parser/expression/ExpressionParserTest.kt b/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/parser/expression/ExpressionParserTest.kt index ed22ecd..eed0fe1 100644 --- a/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/parser/expression/ExpressionParserTest.kt +++ b/composeApp/src/commonTest/kotlin/com/pixelized/desktop/lwa/parser/expression/ExpressionParserTest.kt @@ -62,6 +62,26 @@ class ExpressionParserTest { ) } + @Test + fun textUrlExpression() { + val parser = ExpressionParser( + diceParser = DiceParser(), + wordParser = WordParser(), + ) + parser.test( + expression = "https://drive.google.com/uc?export=view&id=19ME-r7LiDQSrDCq8faVlTNQ7tfX8UUOO", + expected = Expression.UrlExpression("https://drive.google.com/uc?export=view&id=19ME-r7LiDQSrDCq8faVlTNQ7tfX8UUOO"), + ) + parser.test( + expression = "www.google.fr", + expected = Expression.UrlExpression("www.google.fr"), + ) + parser.test( + expression = "google.fr", + expected = Expression.UrlExpression("google.fr"), + ) + } + @Test fun testFunctionExpression() { val parser = ExpressionParser( diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheet.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheet.kt index afde7bd..73816ff 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheet.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheet.kt @@ -48,6 +48,26 @@ data class CharacterSheet( val roll: String, ) + object CharacteristicId { + const val PORTRAIT = "PORTRAIT" + const val THUMBNAIL = "THUMBNAIL" + const val LVL = "LEVEL" + const val STR = "STR" + const val DEX = "DEX" + const val CON = "CON" + const val HEI = "HEI" + const val INT = "INT" + const val POW = "POW" + const val CHA = "CHA" + const val MOV = "MOV" + const val HP = "HP" + const val PP = "PP" + const val DMG = "DMG" + const val ARMOR = "ARMOR" + const val LB = "LEARNING" + const val GHP = "HP_GROW" + } + object CommonSkillId { const val COMBAT_ID = "COMBAT" const val DODGE_ID = "DODGE" @@ -66,21 +86,4 @@ data class CharacterSheet( const val SLEIGHT_OF_HAND_ID = "SLEIGHT_OF_HAND" const val AID_ID = "AID" } - - object CharacteristicId { - const val STR = "STR" - const val DEX = "DEX" - const val CON = "CON" - const val HEI = "HEI" - const val INT = "INT" - const val POW = "POW" - const val CHA = "CHA" - const val MOV = "MOV" - const val HP = "HP" - const val PP = "PP" - const val DMG = "DMG" - const val ARMOR = "ARMOR" - const val LB = "LEARNING" - const val GHP = "HP_GROW" - } } \ No newline at end of file