This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2025-11-29 10:25:05 +01:00
parent ce05e6a4c4
commit f6f2a8b4f8
11 changed files with 490 additions and 109 deletions

View file

@ -5,8 +5,13 @@ import com.pixelized.desktop.lwa.ui.composable.checkbox.LwaCheckBoxUio
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextField
import com.pixelized.desktop.lwa.ui.composable.textfield.createLwaTextFieldFlow
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMActionFieldUio
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMCharacteristicFieldUio
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMSkillFieldUio
import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagFactory
import com.pixelized.desktop.lwa.utils.extention.constitution
import com.pixelized.desktop.lwa.utils.extention.dexterity
import com.pixelized.desktop.lwa.utils.extention.height
import com.pixelized.desktop.lwa.utils.extention.strength
import com.pixelized.desktop.lwa.utils.extention.unpack
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet.CommonSkillId.ACROBATICS_ID
@ -109,6 +114,13 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sk
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_base
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_description
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw_label
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__charisma
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__constitution
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__dexterity
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__height
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__intelligence
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__power
import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics__strength
import org.jetbrains.compose.resources.getString
import java.util.UUID
@ -132,20 +144,17 @@ class GMCharacterEditFactory(
level = form.level.unpack()
?: error("Missing character level"),
shouldLevelUp = form.levelUp.checked.value,
strength = form.characteristics.strength.unpack()
?: error("Missing character strength"),
dexterity = form.characteristics.dexterity.unpack()
?: error("Missing character dexterity"),
constitution = form.characteristics.constitution.unpack()
?: error("Missing character constitution"),
height = form.characteristics.height.unpack()
?: error("Missing character height"),
intelligence = form.characteristics.intelligence.unpack()
?: error("Missing character intelligence"),
power = form.characteristics.power.unpack()
?: error("Missing character power"),
charisma = form.characteristics.charisma.unpack()
?: error("Missing character charisma"),
characteristics = form.characteristics.map { characteristic ->
val characteristicId: String = characteristic.id.unpack()
?: error("Missing characteristic id")
CharacterSheet.Characteristic(
id = characteristicId,
label = characteristic.label.unpack() ?: "",
description = characteristic.description.unpack() ?: "",
base = characteristic.base.unpack() ?: 0,
level = characteristic.level.unpack() ?: 0,
)
},
alterations = sheet?.alterations ?: emptyList(),
damage = sheet?.damage ?: 0,
fatigue = sheet?.fatigue ?: 0,
@ -185,7 +194,6 @@ class GMCharacterEditFactory(
magicSkills = form.magicSkills.map { editedSkill ->
val skillId: String = editedSkill.id.unpack()
?: error("Missing skill id")
CharacterSheet.Skill(
id = skillId,
label = editedSkill.label.unpack()
@ -333,10 +341,18 @@ class GMCharacterEditFactory(
actions = sheet?.actions?.map { createAction(action = it) } ?: emptyList())
}
private suspend fun createCharacteristic(
scope: CoroutineScope,
skill: CharacterSheet.Skill,
characteristics: List<GMCharacteristicFieldUio>,
): List<GMCharacteristicFieldUio> {
}
private suspend fun createCommonSkill(
scope: CoroutineScope,
skill: CharacterSheet.Skill,
characteristics: GMCharacterEditPageUio.CharacteristicsUio,
characteristics: List<GMCharacteristicFieldUio>,
): GMSkillFieldUio {
val baseLabel = getString(Res.string.character_sheet_edit__skills__base_label)
val idFlow = createLwaTextFieldFlow(
@ -585,6 +601,23 @@ class GMCharacterEditFactory(
}
}
private suspend fun commonCharacteristicDescription(
skillId: String,
): String? {
return when (skillId) {
CharacterSheet.CharacteristicId.STR -> Res.string.tooltip__characteristics__strength
CharacterSheet.CharacteristicId.CON -> Res.string.tooltip__characteristics__constitution
CharacterSheet.CharacteristicId.HEI -> Res.string.tooltip__characteristics__height
CharacterSheet.CharacteristicId.INT -> Res.string.tooltip__characteristics__intelligence
CharacterSheet.CharacteristicId.POW -> Res.string.tooltip__characteristics__power
CharacterSheet.CharacteristicId.DEX -> Res.string.tooltip__characteristics__dexterity
CharacterSheet.CharacteristicId.CHA -> Res.string.tooltip__characteristics__charisma
else -> null
}?.let {
getString(it)
}
}
private suspend fun commonSkillDescription(
skillId: String,
): String? {
@ -639,10 +672,11 @@ class GMCharacterEditFactory(
private fun commonSkillBaseFlow(
scope: CoroutineScope,
characteristics: GMCharacterEditPageUio.CharacteristicsUio,
characteristics: List<GMCharacteristicFieldUio>,
skillId: String,
): MutableStateFlow<String> {
val flow = combine(
characteristics.map { it. }
characteristics.strength.valueFlow.map { it.toIntOrNull() ?: 0 },
characteristics.dexterity.valueFlow.map { it.toIntOrNull() ?: 0 },
characteristics.constitution.valueFlow.map { it.toIntOrNull() ?: 0 },

View file

@ -67,6 +67,8 @@ import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.dialog.GMCharact
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.dialog.GMCharacterSheetCopyDialogViewModel
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMActionField
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMActionFieldUio
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMCharacteristicField
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMCharacteristicFieldUio
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMSkillField
import com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item.GMSkillFieldUio
import com.pixelized.desktop.lwa.ui.screen.admin.common.tag.GMTagButton
@ -96,27 +98,13 @@ data class GMCharacterEditPageUio(
val externalLink: LwaTextFieldUio,
val level: LwaTextFieldUio,
val levelUp: LwaCheckBoxUio,
val characteristics: CharacteristicsUio,
val characteristics: List<GMCharacteristicFieldUio>,
val tags: MutableStateFlow<List<GMTagUio>>,
val commonSkills: List<GMSkillFieldUio>,
val specialSkills: List<GMSkillFieldUio>,
val magicSkills: List<GMSkillFieldUio>,
val actions: List<GMActionFieldUio>,
) {
@Stable
data class CharacteristicsUio(
val strength: LwaTextFieldUio,
val dexterity: LwaTextFieldUio,
val constitution: LwaTextFieldUio,
val height: LwaTextFieldUio,
val intelligence: LwaTextFieldUio,
val power: LwaTextFieldUio,
val charisma: LwaTextFieldUio,
) {
val values =
listOf(strength, dexterity, constitution, height, intelligence, power, charisma)
}
}
)
@Stable
object GMCharacterEditPageDefault {
@ -166,6 +154,13 @@ fun GMCharacterEditPage(
onTag = { tag ->
viewModel.addTag(tag = tag)
},
onCharacteristicAdd = {
},
onCharacteristicDelete = { index ->
focus.clearFocus(force = true)
scope.launch { viewModel.deleteCharacteristic(index = index) }
},
onSpecialSkillAdd = {
focus.clearFocus(force = true)
scope.launch { viewModel.addSpecialSkill() }
@ -244,6 +239,8 @@ fun GMCharacterEditContent(
onSaveAs: () -> Unit,
onSave: () -> Unit,
onTag: (GMTagUio) -> Unit,
onCharacteristicAdd: () -> Unit,
onCharacteristicDelete: (Int) -> Unit,
onSpecialSkillAdd: () -> Unit,
onSpecialSkillDelete: (Int) -> Unit,
onMagicSkillAdd: () -> Unit,
@ -482,17 +479,17 @@ fun GMCharacterEditContent(
text = "Characteristics",
)
}
items(
items = form.characteristics.values,
key = { "characteristics-${it.labelFlow}" },
) { characteristic ->
LwaTextField(
itemsIndexed(
items = form.characteristics,
key = { _, item -> item.key },
) { index, characteristic ->
GMCharacteristicField(
modifier = Modifier
.animateItem()
.fillMaxWidth()
.padding(paddingValues = horizontalPadding),
field = characteristic,
singleLine = true,
characteristic = characteristic,
onDelete = { onCharacteristicDelete(index) },
)
}
item(key = "CommonSkillsTitle") {

View file

@ -103,6 +103,18 @@ class GMCharacterEditViewModel(
}
}
suspend fun deleteCharacteristic(
index: Int
) {
_form.update { form ->
form?.copy(
characteristics = form.characteristics.toMutableList().also {
it.removeAt(index)
},
)
}
}
suspend fun deleteSpecialSkill(
index: Int,
) {

View file

@ -0,0 +1,144 @@
package com.pixelized.desktop.lwa.ui.screen.admin.character.edit.item
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.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.DropdownMenu
import androidx.compose.material.DropdownMenuItem
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
import com.pixelized.desktop.lwa.utils.extention.moveFocusOnTab
@Stable
data class GMCharacteristicFieldUio(
val key: String,
val id: LwaTextFieldUio,
val label: LwaTextFieldUio,
val description: LwaTextFieldUio,
val base: LwaTextFieldUio,
val level: LwaTextFieldUio,
)
@Stable
object GMCharacteristicFieldDefault {
@Stable
val spacing: DpSize = DpSize(4.dp, 4.dp)
}
@Composable
fun GMCharacteristicField(
modifier: Modifier = Modifier,
spacing: DpSize = GMCharacteristicFieldDefault.spacing,
characteristic: GMCharacteristicFieldUio,
onDelete: ((GMCharacteristicFieldUio) -> Unit)?,
) {
val focus = LocalFocusManager.current
val showMenu = remember { mutableStateOf(false) }
val onDismissRequest = remember {
{
focus.clearFocus(force = true)
showMenu.value = false
}
}
Row(
modifier = modifier,
horizontalArrangement = Arrangement.spacedBy(space = spacing.width),
) {
Column(
modifier = Modifier.weight(weight = 1f),
verticalArrangement = Arrangement.spacedBy(space = spacing.height),
) {
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(space = spacing.width),
) {
LwaTextField(
modifier = Modifier.weight(weight = 1f),
field = skill.id,
)
LwaTextField(
modifier = Modifier.weight(weight = 1f),
field = skill.label,
)
}
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(space = spacing.width),
) {
LwaTextField(
modifier = Modifier.weight(weight = 1f),
field = skill.base,
)
LwaTextField(
modifier = Modifier.weight(weight = 1f),
field = skill.level,
)
}
skill.description?.let { description ->
LwaTextField(
modifier = Modifier
.fillMaxWidth()
.moveFocusOnTab(focusManager = LocalFocusManager.current),
field = description,
singleLine = false,
)
}
}
Box {
IconButton(
onClick = { showMenu.value = showMenu.value.not() },
) {
Icon(
imageVector = Icons.Default.MoreVert,
tint = MaterialTheme.colors.primary,
contentDescription = null,
)
}
DropdownMenu(
expanded = showMenu.value,
offset = DpOffset(x = (-48).dp - spacing.width, y = (-48).dp),
onDismissRequest = onDismissRequest,
) {
DropdownMenuItem(
modifier = modifier,
enabled = onDelete != null,
onClick = {
onDismissRequest()
onDelete?.invoke(skill)
},
) {
Icon(
imageVector = Icons.Default.Delete,
tint = MaterialTheme.colors.primary,
contentDescription = null,
)
Text(
modifier = Modifier.padding(start = 8.dp),
text = "Supprimer",
)
}
}
}
}
}