From 51e63202e350f608aeed7374588c75d89e84d1e4 Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Wed, 26 Mar 2025 17:12:47 +0100 Subject: [PATCH] Add support for special / critical roll action. --- .../composeResources/values/strings.xml | 9 +- .../desktop/lwa/network/LwaClientImpl.kt | 2 +- .../lwa/ui/composable/checkbox/LwaCheckBox.kt | 33 +++++ .../lwa/ui/overlay/roll/RollHostState.kt | 36 +++-- .../desktop/lwa/ui/overlay/roll/RollPage.kt | 124 +++++++++++++++++- .../lwa/ui/overlay/roll/RollViewModel.kt | 117 ++++++++++++----- .../player/detail/CharacterDetailFactory.kt | 33 ++--- .../sheet/CharacterDetailSheetAction.kt | 4 +- .../CharacterDetailSheetCharacteristic.kt | 4 +- .../detail/sheet/CharacterDetailSheetSkill.kt | 4 +- .../detail/CharacterSheetFactory.kt | 41 +++--- .../detail/CharacterSheetPage.kt | 8 +- .../edit/CharacterSheetEditFactory.kt | 78 +++++++++-- .../edit/CharacterSheetEditPage.kt | 7 +- .../edit/CharacterSheetEditViewModel.kt | 32 ++++- .../edit/composable/ActionField.kt | 101 +++++++++----- .../ui/screen/gamemaster/GameMasterScreen.kt | 6 +- .../ui/screen/gamemaster/items/GMCharacter.kt | 68 +++++----- .../lwa/ui/screen/levelup/LevelUpFactory.kt | 5 +- .../ui/screen/levelup/items/LevelUpSkill.kt | 4 +- .../model/characterSheet/CharacterSheet.kt | 4 +- .../characterSheet/CharacterSheetJsonV1.kt | 2 + .../factory/CharacterSheetJsonFactory.kt | 4 +- .../factory/CharacterSheetJsonV1Factory.kt | 4 +- 24 files changed, 537 insertions(+), 193 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/checkbox/LwaCheckBox.kt diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index 56e1209..262bad7 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -29,6 +29,10 @@ Normal Difficile Impossible + Type de jet : + Normal + Spécial + Critique Création de personnage Édition de personnage @@ -117,7 +121,10 @@ Occupations Ajouter une occupation Nom - Action de lancer + Description + Action normal + Action spécial + Action critique Compétences magiques Ajouter une compétence magique Ajouter une action de lancer diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt index 8c09f83..082271c 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/network/LwaClientImpl.kt @@ -71,7 +71,7 @@ class LwaClientImpl( override suspend fun updateCharacter( sheet: CharacterSheetJson, ) = client - .put("$root/character/update") { + .put("$root/character/update/sheet") { contentType(ContentType.Application.Json) setBody(sheet) } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/checkbox/LwaCheckBox.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/checkbox/LwaCheckBox.kt new file mode 100644 index 0000000..dbe22c3 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/composable/checkbox/LwaCheckBox.kt @@ -0,0 +1,33 @@ +package com.pixelized.desktop.lwa.ui.composable.checkbox + +import androidx.compose.material.Checkbox +import androidx.compose.material.CheckboxColors +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier +import com.pixelized.desktop.lwa.ui.theme.color.component.LwaCheckboxColors +import kotlinx.coroutines.flow.StateFlow + +@Stable +data class LwaCheckBoxUio( + val enable: Boolean = true, + val checked: StateFlow, + val onCheckedChange: (Boolean) -> Unit, +) + +@Composable +fun LwaCheckBox( + modifier: Modifier = Modifier, + colors: CheckboxColors = LwaCheckboxColors(), + field: LwaCheckBoxUio, +) { + val checked = field.checked.collectAsState() + + Checkbox( + modifier = modifier, + checked = checked.value, + colors = colors, + onCheckedChange = field.onCheckedChange, + ) +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollHostState.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollHostState.kt index e89b440..03e485d 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollHostState.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollHostState.kt @@ -3,7 +3,6 @@ package com.pixelized.desktop.lwa.ui.overlay.roll import androidx.compose.runtime.Stable import androidx.compose.runtime.State import androidx.compose.runtime.mutableStateOf -import com.pixelized.shared.lwa.model.campaign.Campaign import kotlinx.coroutines.CancellableContinuation import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.sync.Mutex @@ -24,7 +23,7 @@ class RollHostState { val rollAction: State get() = currentRollAction suspend fun showRollOverlay( - roll: RollAction.RollActionUio, + roll: RollAction.Uio, ): RollResult = mutex.withLock { try { return suspendCancellableCoroutine { continuation -> @@ -40,7 +39,7 @@ class RollHostState { @Stable private class RollActionImpl( - override val roll: RollAction.RollActionUio, + override val roll: RollAction.Uio, private val continuation: CancellableContinuation, ) : RollAction { override fun action(result: RollResult) { @@ -61,15 +60,30 @@ enum class RollResult { @Stable interface RollAction { - val roll: RollActionUio + val roll: Uio fun action(result: RollResult) - @Stable - data class RollActionUio( - val characterSheetId: String, - val label: String, - val rollAction: String, - val rollSuccessValue: Int?, - ) + sealed interface Uio { + val characterSheetId: String + val label: String + + @Stable + data class BoundedRollActionUio( + override val characterSheetId: String, + override val label: String, + val rollAction: String, + val rollSuccessValue: Int, + ): Uio + + @Stable + data class BoundlessRollActionUio( + override val characterSheetId: String, + override val label: String, + val canBeCritical: Boolean, + val rollDefaultAction: String, + val rollSpecialAction: String?, + val rollCriticalAction: String?, + ): Uio + } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollPage.kt index 45bcfdd..fc2971e 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollPage.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollPage.kt @@ -44,6 +44,7 @@ import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import com.pixelized.desktop.lwa.ui.overlay.roll.CriticalityUio.Criticality import com.pixelized.desktop.lwa.ui.overlay.roll.DifficultyUio.Difficulty import com.pixelized.desktop.lwa.ui.theme.lwa import com.pixelized.desktop.lwa.utils.DisableInteractionSource @@ -58,6 +59,10 @@ import lwacharactersheet.composeapp.generated.resources.roll_page__dc_impossible import lwacharactersheet.composeapp.generated.resources.roll_page__dc_normal__label import lwacharactersheet.composeapp.generated.resources.roll_page__roll__label import lwacharactersheet.composeapp.generated.resources.roll_page__roll__success_label +import lwacharactersheet.composeapp.generated.resources.roll_page__criticality__label +import lwacharactersheet.composeapp.generated.resources.roll_page__criticality_normal__label +import lwacharactersheet.composeapp.generated.resources.roll_page__criticality_special__label +import lwacharactersheet.composeapp.generated.resources.roll_page__criticality_critical__label import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @@ -83,6 +88,16 @@ data class DifficultyUio( } } +@Stable +data class CriticalityUio( + val open: Boolean, + val criticality: Criticality, +) { + enum class Criticality { + NORMAL, SPECIAL, CRITICAL + } +} + @Composable fun RollPage( modifier: Modifier = Modifier, @@ -231,6 +246,25 @@ fun RollPage( ) } } + + viewModel.rollCriticality.value?.let { + Box( + modifier = Modifier + .align(Alignment.BottomCenter) + .padding(bottom = 16.dp) + .clickable( + interactionSource = remember { DisableInteractionSource() }, + indication = null, + onClick = { }, + ) + ) { + Criticality( + criticality = it, + onToggle = { viewModel.toggleCriticality() }, + onCriticality = { viewModel.onCriticality(it) }, + ) + } + } } } @@ -299,19 +333,19 @@ fun Difficulty( expanded = difficulty.open, onDismissRequest = { onToggle() } ) { - DifficultyDropDownItem( + LocalDropDownItem( label = stringResource(Res.string.roll_page__dc_easy__label), onClick = { onDifficulty(Difficulty.EASY) }, ) - DifficultyDropDownItem( + LocalDropDownItem( label = stringResource(Res.string.roll_page__dc_normal__label), onClick = { onDifficulty(Difficulty.NORMAL) }, ) - DifficultyDropDownItem( + LocalDropDownItem( label = stringResource(Res.string.roll_page__dc_hard__label), onClick = { onDifficulty(Difficulty.HARD) }, ) - DifficultyDropDownItem( + LocalDropDownItem( label = stringResource(Res.string.roll_page__dc_impossible__label), onClick = { onDifficulty(Difficulty.IMPOSSIBLE) }, ) @@ -319,8 +353,88 @@ fun Difficulty( } } +@OptIn(ExperimentalMaterialApi::class) @Composable -private fun DifficultyDropDownItem( +fun Criticality( + modifier: Modifier = Modifier, + criticality: CriticalityUio, + onToggle: () -> Unit, + onCriticality: (Criticality) -> Unit, +) { + ExposedDropdownMenuBox( + modifier = modifier, + expanded = criticality.open, + onExpandedChange = { onToggle() }, + ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Row( + modifier = Modifier.padding( + horizontal = 16.dp, + vertical = 8.dp, + ), + horizontalArrangement = Arrangement.spacedBy(space = 4.dp), + ) { + Text( + modifier = Modifier.alignByBaseline(), + style = MaterialTheme.typography.body1, + text = stringResource(Res.string.roll_page__criticality__label) + ) + AnimatedContent( + targetState = criticality.criticality, + transitionSpec = { + val enter = fadeIn() + slideInVertically { -16 } + val exit = fadeOut() + slideOutVertically { 16 } + enter togetherWith exit using SizeTransform(clip = false) + }, + ) { + Text( + modifier = Modifier.alignByBaseline().animateContentSize(), + style = MaterialTheme.typography.body1, + color = MaterialTheme.colors.primary, + text = when (it) { + Criticality.NORMAL -> stringResource(Res.string.roll_page__criticality_normal__label) + Criticality.SPECIAL -> stringResource(Res.string.roll_page__criticality_special__label) + Criticality.CRITICAL -> stringResource(Res.string.roll_page__criticality_critical__label) + } + ) + } + } + val rotation = animateFloatAsState( + targetValue = if (criticality.open) -180f else 0f, + ) + Icon( + modifier = Modifier + .offset(x = (-12).dp) + .graphicsLayer { rotationZ = rotation.value }, + imageVector = Icons.Default.ArrowDropDown, + contentDescription = null + ) + } + + ExposedDropdownMenu( + expanded = criticality.open, + onDismissRequest = { onToggle() } + ) { + LocalDropDownItem( + label = stringResource(Res.string.roll_page__criticality_normal__label), + onClick = { onCriticality(Criticality.NORMAL) }, + ) + LocalDropDownItem( + label = stringResource(Res.string.roll_page__criticality_special__label), + onClick = { onCriticality(Criticality.SPECIAL) }, + ) + LocalDropDownItem( + label = stringResource(Res.string.roll_page__criticality_critical__label), + onClick = { onCriticality(Criticality.CRITICAL) }, + ) + } + } +} + +@Composable +private fun LocalDropDownItem( modifier: Modifier = Modifier, contentPadding: PaddingValues = PaddingValues(horizontal = 16.dp), label: String, diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollViewModel.kt index afa73b3..38d1be0 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/overlay/roll/RollViewModel.kt @@ -9,8 +9,8 @@ import androidx.lifecycle.ViewModel import com.pixelized.desktop.lwa.repository.alteration.AlterationRepository import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository import com.pixelized.desktop.lwa.repository.network.NetworkRepository +import com.pixelized.desktop.lwa.ui.overlay.roll.CriticalityUio.Criticality import com.pixelized.desktop.lwa.ui.overlay.roll.DifficultyUio.Difficulty -import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio import com.pixelized.shared.lwa.model.AlteredCharacterSheet import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory import com.pixelized.shared.lwa.protocol.websocket.RollEvent @@ -42,7 +42,7 @@ class RollViewModel( private val alteredCharacterSheetFactory: AlteredCharacterSheetFactory, ) : ViewModel() { private var alteredCharacterSheet: AlteredCharacterSheet? = null - private var rollAction: RollActionUio? = null + private var rollAction: RollAction.Uio? = null var lastRollResult: RollResult = RollResult.Dismissed private set @@ -64,6 +64,9 @@ class RollViewModel( private val _rollDifficulty = mutableStateOf(null) val rollDifficulty: State get() = _rollDifficulty + private val _rollCriticality = mutableStateOf(null) + val rollCriticality: State get() = _rollCriticality + private val _shareResult = mutableStateOf(true) val shareResult: State = _shareResult @@ -88,7 +91,7 @@ class RollViewModel( * return true if the viewModel is ready to roll, otherwise false. */ suspend fun prepareRoll( - roll: RollActionUio, + roll: RollAction.Uio, ) { rollRotation.snapTo(0f) rollScale.snapTo(1f) @@ -111,23 +114,39 @@ class RollViewModel( this.rollAction = roll - val rollStep = roll.rollSuccessValue?.let { - skillStepUseCase.computeSkillStep(skill = it) - } + val rollStep = roll + .let { it as? RollAction.Uio.BoundedRollActionUio } + ?.rollSuccessValue + ?.let { skillStepUseCase.computeSkillStep(skill = it) } _shareResult.value = true _cancellable.value = true _rollResult.value = null + _rollTitle.value = RollTitleUio( label = roll.label, value = rollStep?.success?.last ) - _rollDifficulty.value = roll.rollSuccessValue?.let { - DifficultyUio( - open = false, - difficulty = Difficulty.NORMAL, - ) - } + + _rollDifficulty.value = roll + .let { it as? RollAction.Uio.BoundedRollActionUio } + ?.rollSuccessValue + ?.let { + DifficultyUio( + open = false, + difficulty = Difficulty.NORMAL, + ) + } + + _rollCriticality.value = roll + .let { it as? RollAction.Uio.BoundlessRollActionUio } + ?.takeIf { it.canBeCritical } + ?.let { + CriticalityUio( + open = false, + criticality = Criticality.NORMAL + ) + } } suspend fun roll() { @@ -151,22 +170,34 @@ class RollViewModel( delay(500) _cancellable.value = false // compute the skill critical success to critical failure ranges. - val rollStep = rollAction.rollSuccessValue?.let { - skillStepUseCase.computeSkillStep( - skill = when (_rollDifficulty.value?.difficulty) { - Difficulty.EASY -> it * 2 - Difficulty.NORMAL -> it - Difficulty.HARD -> it / 2 - Difficulty.IMPOSSIBLE -> it / 4 - else -> it - } - ) - } + val rollStep = rollAction + .let { it as? RollAction.Uio.BoundedRollActionUio } + ?.rollSuccessValue?.let { + skillStepUseCase.computeSkillStep( + skill = when (_rollDifficulty.value?.difficulty) { + Difficulty.EASY -> it * 2 + Difficulty.NORMAL -> it + Difficulty.HARD -> it / 2 + Difficulty.IMPOSSIBLE -> it / 4 + else -> it + } + ) + } + // compute the expression. + val expression = when (rollAction) { + is RollAction.Uio.BoundedRollActionUio -> rollAction.rollAction + is RollAction.Uio.BoundlessRollActionUio -> when (rollCriticality.value?.criticality) { + Criticality.NORMAL -> rollAction.rollDefaultAction + Criticality.SPECIAL -> rollAction.rollSpecialAction + Criticality.CRITICAL -> rollAction.rollCriticalAction + null -> null + } + } ?: "" // compute the roll (typically use the expression inside the rollAction) val roll = skillComputation.computeRoll( sheet = alteredCharacterSheet, - expression = rollAction.rollAction, + expression = expression, ) // check where the roll fall into the rollSteps. @@ -227,22 +258,38 @@ class RollViewModel( open = false, difficulty = difficulty, ) - val rollStep = rollAction?.rollSuccessValue?.let { - skillStepUseCase.computeSkillStep( - skill = when (_rollDifficulty.value?.difficulty) { - Difficulty.EASY -> it * 2 - Difficulty.NORMAL -> it - Difficulty.HARD -> it / 2 - Difficulty.IMPOSSIBLE -> it / 4 - else -> it - } - ) - } + val rollStep = rollAction + .let { it as? RollAction.Uio.BoundedRollActionUio } + ?.rollSuccessValue + ?.let { + skillStepUseCase.computeSkillStep( + skill = when (_rollDifficulty.value?.difficulty) { + Difficulty.EASY -> it * 2 + Difficulty.NORMAL -> it + Difficulty.HARD -> it / 2 + Difficulty.IMPOSSIBLE -> it / 4 + else -> it + } + ) + } _rollTitle.value = _rollTitle.value?.copy( value = rollStep?.success?.last ) } + fun toggleCriticality() { + _rollCriticality.value = _rollCriticality.value?.copy( + open = _rollCriticality.value?.open?.not() ?: false + ) + } + + fun onCriticality(criticality: Criticality) { + _rollCriticality.value = CriticalityUio( + open = false, + criticality = criticality, + ) + } + private suspend fun diceRotationAnimation() { rollRotation.animateTo( targetValue = rollRotation.value.let { it - it % 360 } + 360f * 3, 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 index bc85488..e446675 100644 --- 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 @@ -1,7 +1,8 @@ package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio -import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio +import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction + import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.header.CharacterDetailHeaderUio import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetActionUio import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.sheet.CharacterDetailSheetCharacteristicUio @@ -130,7 +131,7 @@ class CharacterDetailFactory( title = getString(Res.string.character_sheet__characteristics__str), description = getString(Res.string.tooltip__characteristics__strength), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__str), rollAction = "1d100", @@ -144,7 +145,7 @@ class CharacterDetailFactory( title = getString(Res.string.character_sheet__characteristics__dex), description = getString(Res.string.tooltip__characteristics__dexterity), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__dex), rollAction = "1d100", @@ -158,7 +159,7 @@ class CharacterDetailFactory( title = getString(Res.string.character_sheet__characteristics__con), description = getString(Res.string.tooltip__characteristics__constitution), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__con), rollAction = "1d100", @@ -172,7 +173,7 @@ class CharacterDetailFactory( title = getString(Res.string.character_sheet__characteristics__hei), description = getString(Res.string.tooltip__characteristics__height), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__hei), rollAction = "1d100", @@ -186,7 +187,7 @@ class CharacterDetailFactory( title = getString(Res.string.character_sheet__characteristics__int), description = getString(Res.string.tooltip__characteristics__intelligence), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__int), rollAction = "1d100", @@ -200,7 +201,7 @@ class CharacterDetailFactory( title = getString(Res.string.character_sheet__characteristics__pow), description = getString(Res.string.tooltip__characteristics__power), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__pow), rollAction = "1d100", @@ -214,7 +215,7 @@ class CharacterDetailFactory( title = getString(Res.string.character_sheet__characteristics__cha), description = getString(Res.string.tooltip__characteristics__charisma), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__cha), rollAction = "1d100", @@ -241,7 +242,7 @@ class CharacterDetailFactory( description = it, ) }, - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = skill.label, rollAction = "1d100", @@ -268,7 +269,7 @@ class CharacterDetailFactory( description = it, ) }, - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = skill.label, rollAction = "1d100", @@ -295,7 +296,7 @@ class CharacterDetailFactory( description = it, ) }, - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = skill.label, rollAction = "1d100", @@ -313,14 +314,16 @@ class CharacterDetailFactory( description = it, ) }, - roll = RollActionUio( + roll = RollAction.Uio.BoundlessRollActionUio( characterSheetId = characterSheetId, label = action.label, - rollAction = action.roll, - rollSuccessValue = null, + canBeCritical = action.canBeCritical, + rollDefaultAction = action.default, + rollSpecialAction = action.special, + rollCriticalAction = action.critical, ) ) - } + }.sortedWith(compareBy(Collator.getInstance()) { it.label }), ) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetAction.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetAction.kt index 0d76c96..831d86d 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetAction.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetAction.kt @@ -17,7 +17,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.pixelized.desktop.lwa.ui.composable.shapes.MasteryShape import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio -import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio +import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.ic_d20_24dp import org.jetbrains.compose.resources.painterResource @@ -27,7 +27,7 @@ data class CharacterDetailSheetActionUio( val actionId: String, val label: String, val tooltips: TooltipUio?, - val roll: RollActionUio, + val roll: RollAction.Uio, ) @Composable diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetCharacteristic.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetCharacteristic.kt index da870e2..6e408ab 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetCharacteristic.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetCharacteristic.kt @@ -15,14 +15,14 @@ import androidx.compose.ui.unit.dp import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio -import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio +import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction @Stable data class CharacterDetailSheetCharacteristicUio( val value: String, val label: String, val tooltips: TooltipUio, - val roll: RollActionUio, + val roll: RollAction.Uio, ) @OptIn(ExperimentalFoundationApi::class) diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetSkill.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetSkill.kt index bfd86e3..adb72f9 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetSkill.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/campaign/player/detail/sheet/CharacterDetailSheetSkill.kt @@ -21,7 +21,7 @@ import androidx.compose.ui.unit.dp import com.pixelized.desktop.lwa.ui.composable.shapes.MasteryShape import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio -import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio +import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction @Stable data class CharacterDetailSheetSkillUio( @@ -31,7 +31,7 @@ data class CharacterDetailSheetSkillUio( val used: Boolean, val occupation: Boolean, val tooltips: TooltipUio?, - val roll: RollActionUio, + val roll: RollAction.Uio, ) @OptIn(ExperimentalFoundationApi::class) 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 307e683..ef7de05 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 @@ -1,7 +1,7 @@ package com.pixelized.desktop.lwa.ui.screen.characterSheet.detail import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio -import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio +import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Node import com.pixelized.shared.lwa.model.AlteredCharacterSheetFactory @@ -70,7 +70,7 @@ class CharacterSheetFactory( title = getString(Res.string.character_sheet__characteristics__str), description = getString(Res.string.tooltip__characteristics__strength), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__str), rollAction = "1d100", @@ -86,7 +86,7 @@ class CharacterSheetFactory( title = getString(Res.string.character_sheet__characteristics__dex), description = getString(Res.string.tooltip__characteristics__dexterity), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__dex), rollAction = "1d100", @@ -102,7 +102,7 @@ class CharacterSheetFactory( title = getString(Res.string.character_sheet__characteristics__con), description = getString(Res.string.tooltip__characteristics__constitution), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__con), rollAction = "1d100", @@ -118,7 +118,7 @@ class CharacterSheetFactory( title = getString(Res.string.character_sheet__characteristics__hei), description = getString(Res.string.tooltip__characteristics__height), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__hei), rollAction = "1d100", @@ -134,7 +134,7 @@ class CharacterSheetFactory( title = getString(Res.string.character_sheet__characteristics__int), description = getString(Res.string.tooltip__characteristics__intelligence), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__int), rollAction = "1d100", @@ -150,7 +150,7 @@ class CharacterSheetFactory( title = getString(Res.string.character_sheet__characteristics__pow), description = getString(Res.string.tooltip__characteristics__power), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__pow), rollAction = "1d100", @@ -166,7 +166,7 @@ class CharacterSheetFactory( title = getString(Res.string.character_sheet__characteristics__cha), description = getString(Res.string.tooltip__characteristics__charisma), ), - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = getString(Res.string.character_sheet__characteristics__cha), rollAction = "1d100", @@ -271,7 +271,7 @@ class CharacterSheetFactory( description = it, ) }, - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = skill.label, rollAction = "1d100", @@ -297,7 +297,7 @@ class CharacterSheetFactory( description = it, ) }, - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = skill.label, rollAction = "1d100", @@ -323,7 +323,7 @@ class CharacterSheetFactory( description = it, ) }, - roll = RollActionUio( + roll = RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = skill.label, rollAction = "1d100", @@ -331,16 +331,19 @@ class CharacterSheetFactory( ), ) }, - actions = characterSheet.actions.mapNotNull { - if (it.roll.isEmpty()) return@mapNotNull null + actions = characterSheet.actions.mapNotNull { action -> + if (action.default.isEmpty()) return@mapNotNull null + CharacterSheetPageUio.Roll( - label = it.label, - value = it.roll, - roll = RollActionUio( + label = action.label, + value = action.default, + roll = RollAction.Uio.BoundlessRollActionUio( characterSheetId = characterSheetId, - label = it.label, - rollAction = it.roll, - rollSuccessValue = null, + label = action.label, + canBeCritical = action.canBeCritical, + rollDefaultAction = action.default, + rollSpecialAction = action.special, + rollCriticalAction = action.critical, ) ) } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetPage.kt index d0b1c9a..45e45f6 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetPage.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/detail/CharacterSheetPage.kt @@ -64,7 +64,7 @@ import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController import com.pixelized.desktop.lwa.ui.navigation.window.LocalWindow import com.pixelized.desktop.lwa.ui.navigation.window.destination.navigateToCharacterSheetEdit -import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio +import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction import com.pixelized.desktop.lwa.ui.overlay.roll.RollPage import com.pixelized.desktop.lwa.ui.overlay.roll.RollViewModel import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic @@ -108,7 +108,7 @@ data class CharacterSheetPageUio( val value: String, val editable: Boolean, val tooltips: TooltipUio?, - val roll: RollActionUio?, + val roll: RollAction.Uio?, ) @Stable @@ -118,14 +118,14 @@ data class CharacterSheetPageUio( val value: Int, val used: Boolean, val tooltips: TooltipUio? = null, - val roll: RollActionUio, + val roll: RollAction.Uio, ) @Stable data class Roll( val label: String, val value: String, - val roll: RollActionUio, + val roll: RollAction.Uio, ) } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditFactory.kt index 158fd08..2f62679 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditFactory.kt @@ -3,6 +3,8 @@ package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.mutableStateOf +import com.pixelized.desktop.lwa.ui.composable.checkbox.LwaCheckBoxUio +import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.SkillFieldFactory import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.occupation @@ -14,9 +16,13 @@ import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfi import com.pixelized.desktop.lwa.utils.extention.unAccent import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase +import kotlinx.coroutines.flow.MutableStateFlow import lwacharactersheet.composeapp.generated.resources.Res -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__action_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__critical_action_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__default_action_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__description_label import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__name_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__spacial_action_label import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__cha import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__con import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__dex @@ -186,10 +192,12 @@ class CharacterSheetEditFactory( actions = editedSheet.actions.map { CharacterSheet.Roll( id = it.id, - label = it.label.value.value, - description = null, // TODO - canBeCritical = false, // TODO - roll = it.action.value.value, + label = it.label.valueFlow.value, + description = it.description.valueFlow.value, + canBeCritical = it.canBeCritical.checked.value, + default = it.default.valueFlow.value, + special = it.special?.valueFlow?.value, + critical = it.critical?.valueFlow?.value, ) }, ) @@ -456,13 +464,28 @@ class CharacterSheetEditFactory( actions = sheet?.actions?.map { action -> ActionFieldUio( id = action.id, - label = skillFieldFactory.createWrapper( - label = mutableStateOf(getString(Res.string.character_sheet_edit__actions__name_label)), + label = createLwaTextField( + label = getString(Res.string.character_sheet_edit__actions__name_label), value = action.label, ), - action = skillFieldFactory.createWrapper( - label = mutableStateOf(getString(Res.string.character_sheet_edit__actions__action_label)), - value = action.roll, + description = createLwaTextField( + label = getString(Res.string.character_sheet_edit__actions__description_label), + value = action.description ?: "", + ), + canBeCritical = createLwaBox( + checked = action.canBeCritical, + ), + default = createLwaTextField( + label = getString(Res.string.character_sheet_edit__actions__default_action_label), + value = action.default, + ), + special = createLwaTextField( + label = getString(Res.string.character_sheet_edit__actions__spacial_action_label), + value = action.special, + ), + critical = createLwaTextField( + label = getString(Res.string.character_sheet_edit__actions__critical_action_label), + value = action.critical, ), option = skillFieldFactory.deleteOption { onDeleteSkill(action.id) }, ) @@ -471,6 +494,41 @@ class CharacterSheetEditFactory( } } + fun createLwaTextField( + enable: Boolean = true, + isError: Boolean = false, + label: String? = null, + placeholder: String? = null, + value: String? = null, + ): LwaTextFieldUio { + val valueFlow = MutableStateFlow(value ?: "") + val labelFlow = MutableStateFlow(label) + val placeholderFlow = MutableStateFlow(placeholder) + val isErrorFlow = MutableStateFlow(isError) + + return LwaTextFieldUio( + enable = enable, + isError = isErrorFlow, + labelFlow = labelFlow, + valueFlow = valueFlow, + placeHolderFlow = placeholderFlow, + onValueChange = { valueFlow.value = it }, + ) + } + + fun createLwaBox( + enable: Boolean = true, + checked: Boolean, + ): LwaCheckBoxUio { + val checkedFlow = MutableStateFlow(checked) + + return LwaCheckBoxUio( + enable = enable, + checked = checkedFlow, + onCheckedChange = { checkedFlow.value = it }, + ) + } + private suspend fun createLevelUpWrapper( shouldLevelUp: Boolean, ): LevelUpWrapperUio { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditPage.kt index dafdaa4..5e49e00 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditPage.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditPage.kt @@ -34,7 +34,6 @@ import com.pixelized.desktop.lwa.ui.navigation.screen.LocalScreenController import com.pixelized.desktop.lwa.ui.navigation.window.LocalWindow import com.pixelized.desktop.lwa.ui.screen.characterSheet.copy.CharacterSheetCopyDialog import com.pixelized.desktop.lwa.ui.screen.characterSheet.delete.CharacterSheetDeleteDialog -import com.pixelized.desktop.lwa.ui.screen.characterSheet.detail.dialog.CharacterSheetDeleteConfirmationDialog import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.ActionField import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.ActionFieldUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.BaseSkillFieldUio @@ -430,8 +429,10 @@ fun CharacterSheetEdit( ) { form.actions.forEach { ActionField( - modifier = Modifier.fillMaxWidth().padding(end = (4 + 2).dp), - action = it + modifier = Modifier + .fillMaxWidth() + .padding(end = 6.dp, bottom = 16.dp), + action = it, ) } TextButton( diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditViewModel.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditViewModel.kt index 54116ab..028e642 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditViewModel.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/CharacterSheetEditViewModel.kt @@ -14,8 +14,11 @@ import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.Action import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.runBlocking import lwacharactersheet.composeapp.generated.resources.Res -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__action_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__critical_action_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__description_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__default_action_label import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__name_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__actions__spacial_action_label import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__copy__label import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__copy__title import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__magic_title @@ -125,11 +128,28 @@ class CharacterSheetEditViewModel( val id = UUID.randomUUID().toString() val field = ActionFieldUio( id = id, - label = skillFactory.createWrapper( - label = mutableStateOf(getString(Res.string.character_sheet_edit__actions__name_label)), + label = sheetFactory.createLwaTextField( + label = getString(Res.string.character_sheet_edit__actions__name_label), + value = "", ), - action = skillFactory.createWrapper( - label = mutableStateOf(getString(Res.string.character_sheet_edit__actions__action_label)), + description = sheetFactory.createLwaTextField( + label = getString(Res.string.character_sheet_edit__actions__description_label), + value = "", + ), + canBeCritical = sheetFactory.createLwaBox( + checked = false, + ), + default = sheetFactory.createLwaTextField( + label = getString(Res.string.character_sheet_edit__actions__default_action_label), + value = "", + ), + special = sheetFactory.createLwaTextField( + label = getString(Res.string.character_sheet_edit__actions__spacial_action_label), + value = "", + ), + critical = sheetFactory.createLwaTextField( + label = getString(Res.string.character_sheet_edit__actions__critical_action_label), + value = "", ), option = skillFactory.deleteOption { deleteSkill(id) }, ) @@ -151,7 +171,7 @@ class CharacterSheetEditViewModel( }, actions = _characterSheet.value.actions.toMutableList().also { actions -> actions.removeIf { it.id == skillId } - } + }, ) } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/ActionField.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/ActionField.kt index 5b0e20c..6f6cfae 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/ActionField.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/ActionField.kt @@ -1,9 +1,10 @@ package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable +import androidx.compose.animation.animateContentSize import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.material.DropdownMenu import androidx.compose.material.Icon import androidx.compose.material.IconButton @@ -12,45 +13,57 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.MoreVert import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable +import androidx.compose.runtime.collectAsState import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp +import com.pixelized.desktop.lwa.ui.composable.checkbox.LwaCheckBox +import com.pixelized.desktop.lwa.ui.composable.checkbox.LwaCheckBoxUio +import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField +import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.ActionOption import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.DropDownActionMenuItem -import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapper -import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapperUio @Stable data class ActionFieldUio( val id: String, - val label: TextFieldWrapperUio, - val action: TextFieldWrapperUio, + val label: LwaTextFieldUio, + val description: LwaTextFieldUio, + val canBeCritical: LwaCheckBoxUio, + val default: LwaTextFieldUio, + val special: LwaTextFieldUio?, + val critical: LwaTextFieldUio?, val option: ActionOption.DeleteOptionUio, ) @Composable fun ActionField( modifier: Modifier = Modifier, + space: Dp = 4.dp, action: ActionFieldUio, ) { val showMenu = remember { mutableStateOf(false) } + val canBeCritical = action.canBeCritical.checked.collectAsState() - Row( + Column( modifier = modifier, - horizontalArrangement = Arrangement.spacedBy(space = 4.dp, alignment = Alignment.End), - verticalAlignment = Alignment.CenterVertically, + verticalArrangement = Arrangement.spacedBy(space = space), ) { - TextFieldWrapper( - modifier = Modifier.weight(weight = 1f), - wrapper = action.label, - ) - TextFieldWrapper( - modifier = Modifier.width(width = (192+4).dp), - wrapper = action.action, - ) - Box { + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(space = space), + verticalAlignment = Alignment.CenterVertically, + ) { + LwaTextField( + modifier = Modifier.weight(1f), + field = action.label, + ) + LwaCheckBox( + field = action.canBeCritical, + ) IconButton( onClick = { showMenu.value = showMenu.value.not() }, ) { @@ -59,19 +72,47 @@ fun ActionField( tint = MaterialTheme.colors.primary, contentDescription = null, ) - } - DropdownMenu( - expanded = showMenu.value, - onDismissRequest = { showMenu.value = false } - ) { - DropDownActionMenuItem( - wrapper = action.option, - onClick = { - showMenu.value = false - action.option.onOption() - } - ) + DropdownMenu( + expanded = showMenu.value, + onDismissRequest = { showMenu.value = false } + ) { + DropDownActionMenuItem( + wrapper = action.option, + onClick = { + showMenu.value = false + action.option.onOption() + } + ) + } } } + Row( + modifier = Modifier.fillMaxWidth().animateContentSize(), + horizontalArrangement = Arrangement.spacedBy(space = space), + ) { + LwaTextField( + modifier = Modifier.weight(1f), + field = action.default, + ) + if (canBeCritical.value) { + action.special?.let { field -> + LwaTextField( + modifier = Modifier.weight(1f), + field = field, + ) + } + action.critical?.let { field -> + LwaTextField( + modifier = Modifier.weight(1f), + field = field, + ) + } + } + } + LwaTextField( + modifier = Modifier.fillMaxWidth(), + singleLine = false, + field = action.description, + ) } } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterScreen.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterScreen.kt index 2fd3933..e2ce2c5 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterScreen.kt @@ -41,6 +41,7 @@ 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.text.font.FontWeight import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import com.pixelized.desktop.lwa.LocalWindowController @@ -153,11 +154,12 @@ private fun GameMasterContent( .clickable { onGameMaster(gameMaster.value.not()) } .padding(all = 8.dp), verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(space = 4.dp) + horizontalArrangement = Arrangement.spacedBy(space = 8.dp) ) { Text( color = MaterialTheme.lwa.colorScheme.base.primary, - style = MaterialTheme.typography.caption, + style = MaterialTheme.typography.body2, + fontWeight = FontWeight.SemiBold, text = stringResource(Res.string.game_master__action), ) Switch( 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 d1d5344..ec8cdf7 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 @@ -4,7 +4,6 @@ import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.calculateStartPadding @@ -107,47 +106,40 @@ fun GMCharacter( .background(color = MaterialTheme.lwa.colorScheme.elevated.base1dp) .then(other = modifier), ) { - Column { + Row( + modifier = Modifier.padding(start = startPadding), + verticalAlignment = Alignment.CenterVertically, + ) { Row( - modifier = Modifier.padding(start = startPadding), - verticalAlignment = Alignment.CenterVertically, - ) { - Row( - modifier = Modifier.weight(weight = 1f), - horizontalArrangement = Arrangement.spacedBy(4.dp), - ) { - Text( - modifier = Modifier.alignByBaseline(), - style = MaterialTheme.lwa.typography.base.body1, - text = character.name, - ) - Text( - modifier = Modifier.alignByBaseline(), - style = MaterialTheme.lwa.typography.base.caption, - text = stringResource( - Res.string.game_master__character_level__label, - character.level, - ), - ) - } - OverflowActionMenu( - character = character, - onAction = onAction, - ) - } - Row( - modifier = Modifier - .padding(paddingValues = padding) - .padding(bottom = 8.dp), + modifier = Modifier.weight(weight = 1f), horizontalArrangement = Arrangement.spacedBy(space = 4.dp), ) { - character.tags.forEach { tag -> - GMTag( - elevation = 4.dp, - tag = tag, - ) - } + Text( + modifier = Modifier.alignByBaseline(), + style = MaterialTheme.lwa.typography.base.body1, + text = character.name, + ) + Text( + modifier = Modifier.alignByBaseline(), + style = MaterialTheme.lwa.typography.base.caption, + text = stringResource( + Res.string.game_master__character_level__label, + character.level, + ), + ) } + + character.tags.forEach { tag -> + GMTag( + elevation = 4.dp, + tag = tag, + ) + } + + OverflowActionMenu( + character = character, + onAction = onAction, + ) } } } diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/levelup/LevelUpFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/levelup/LevelUpFactory.kt index ad47bbd..c6cc753 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/levelup/LevelUpFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/levelup/LevelUpFactory.kt @@ -1,7 +1,8 @@ package com.pixelized.desktop.lwa.ui.screen.levelup import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio -import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio +import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction + import com.pixelized.desktop.lwa.ui.overlay.roll.RollResult import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpCharacteristicUio import com.pixelized.desktop.lwa.ui.screen.levelup.items.LevelUpSkillUio @@ -312,7 +313,7 @@ class LevelUpFactory( ) }, roll = when (results[skill.id]) { - null -> RollActionUio( + null -> RollAction.Uio.BoundedRollActionUio( characterSheetId = characterSheetId, label = skill.label, rollAction = "1d100", diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/levelup/items/LevelUpSkill.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/levelup/items/LevelUpSkill.kt index 718b642..e16e6df 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/levelup/items/LevelUpSkill.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/levelup/items/LevelUpSkill.kt @@ -26,7 +26,7 @@ import androidx.compose.ui.unit.dp import com.pixelized.desktop.lwa.ui.composable.shapes.MasteryShape import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio -import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction.RollActionUio +import com.pixelized.desktop.lwa.ui.overlay.roll.RollAction import com.pixelized.desktop.lwa.ui.theme.lwa import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.level_up__skill_level @@ -41,7 +41,7 @@ data class LevelUpSkillUio( val levelUp: Boolean, val occupation: Boolean, val tooltips: TooltipUio?, - val roll: RollActionUio?, + val roll: RollAction.Uio?, ) @OptIn(ExperimentalFoundationApi::class) 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 bd6b4c3..b304fac 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 @@ -43,7 +43,9 @@ data class CharacterSheet( val label: String, val description: String?, val canBeCritical: Boolean, - val roll: String, + val default: String, + val special: String?, + val critical: String?, ) object CharacteristicId { diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonV1.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonV1.kt index c72e69a..ec47459 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonV1.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/CharacterSheetJsonV1.kt @@ -50,5 +50,7 @@ data class CharacterSheetJsonV1( val description: String?, val canBeCritical: Boolean, val roll: String, + val special: String?, + val critical: String?, ) } \ No newline at end of file diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonFactory.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonFactory.kt index d17eb51..5b8edb9 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonFactory.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonFactory.kt @@ -83,7 +83,9 @@ class CharacterSheetJsonFactory( label = it.label, description = it.description, canBeCritical = it.canBeCritical, - roll = it.roll, + roll = it.default, + special = it.special, + critical = it.critical ) }, ) diff --git a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV1Factory.kt b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV1Factory.kt index 069b551..456da20 100644 --- a/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV1Factory.kt +++ b/shared/src/commonMain/kotlin/com/pixelized/shared/lwa/model/characterSheet/factory/CharacterSheetJsonV1Factory.kt @@ -70,7 +70,9 @@ class CharacterSheetJsonV1Factory( label = it.label, description = it.description, canBeCritical = it.canBeCritical, - roll = it.roll, + default = it.roll, + special = it.special, + critical = it.critical, ) }, )