From 50ed975913af7d082ba9158081d89edf7a20f1b7 Mon Sep 17 00:00:00 2001 From: Thomas Andres Gomez Date: Mon, 17 Mar 2025 15:46:17 +0100 Subject: [PATCH] Add id + levelUp + base expression to the charactersheet edition. --- .../composeResources/values/strings.xml | 65 +++-- .../characterSheet/CharacterSheetStore.kt | 13 +- .../edit/CharacterSheetEditFactory.kt | 223 ++++++++++++++---- .../edit/CharacterSheetEditPage.kt | 21 +- .../edit/CharacterSheetEditViewModel.kt | 2 +- .../edit/composable/BaseSkillField.kt | 36 +-- .../edit/composable/LevelUpField.kt | 39 +++ .../edit/composable/option/ActionOption.kt | 12 +- .../edit/composable/option/CheckedOption.kt | 11 +- .../ui/screen/gamemaster/GameMasterFactory.kt | 8 +- .../desktop/lwa/utils/extention/StringExt.kt | 11 +- 11 files changed, 352 insertions(+), 89 deletions(-) create mode 100644 composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/LevelUpField.kt diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml index 39eea3a..dd625a6 100644 --- a/composeApp/src/commonMain/composeResources/values/strings.xml +++ b/composeApp/src/commonMain/composeResources/values/strings.xml @@ -62,22 +62,55 @@ Bonus Niveau Compétences - Bagarre - Esquive - Saisie - Lancer - Athlétisme - Acrobatie - Perception - Recherche - Empathie - Persuasion - Intimidation - Baratin - Marchandage - Discrétion - Escamotage - Premiers soins + Bagarre + Attaque en combat à mains nues. Une attaque réussie inflige 1D3 + BDGT.\n\n- Base : DEX * 2 + floor5(DEX*2) + Esquive + Éviter une attaque, un projectile, etc.\n\n- Base : DEX*2 + floor5(DEX*2) + Saisie + Maitriser/immobiliser un adversaire.\n\n- Base : STR + HEI + floor5(STR+HEI) + Lancer + Viser et lancer quelque chose à travers les airs et vers une cible.\n\n- Base : STR + DEX + floor5(STR+DEX) + Athlétisme + Réaliser un mouvement nécessitant une certaine force (Enfoncer une porte, nager à contre-courant, etc.).\n\n- Base : STR + CON * 2 + floor5(STR+CON*2) + Acrobatie + Réaliser un mouvement nécessitant une certaine agilité (Marcher sur une corde, courir sur la glace, etc.).\n\n- Base : DEX + CON * 2 + floor5(DEX+CON*2) + Perception + Aptitude à percevoir via ses sens ou à percevoir un détail difficile à remarquer.\n\n- Base : 10 + INT * 2 + floor5(10+INT*2) + Recherche + Aptitude à trouver des indices et à émettre des suppositions sur la base de ceux-ci.\n\n- Base : 10 + INT * 2 + floor5(10+INT*2) + Empathie + Évaluer les pensées et/ou les motivations cachées d’un autre personnage en se basant sur des signaux subliminaux.\n\n- Base : CHA + INT + floor5(CHA+INT) + Persuasion + Influencer quelqu'un ou un groupe de personnes avec tact, grâce, ou de bonnes manières.\n\n- Base : CHA * 3 + floor5(CHA*3) + Intimidation + Influencer quelqu'un ou un groupe de personnes par des menaces, des actions hostiles, ou de la violence physique.\n\n- Base : CHA + max(HEI + POW) * 2 + floor5(CHA+max(HEI,POW)*2) + Baratin + Mentir ou cacher la vérité avec efficacité, soit verbalement, soit par vos actions.\n\n- Base : CHA * 2 + INT + floor5(CHA*2+INT) + Marchandage + Négocier les prix.\n\n- Base : CHA * 2 + floor5(CHA*2) + Discrétion + Passer inaperçu.\n\n- Base : CHA + DEX * 2 - HEI + floor5(CHA+DEX*2-HEI) + Escamotage + Réaliser une manipulation ou une fourberie, comme prendre quelque chose à quelqu'un ou dissimuler un objet sur vous-même.\n\n- Base : DEX * 2 + floor5(DEX*2) + Premiers soins + Traiter les blessures légères. Une réussite rétablit 1D3 points de vie. Une réussite spéciale restaure 1D3+3 points de vie.\n\n- Base : INT + DEX + floor5(INT+DEX) + Level Up Occupations Ajouter une occupation Nom diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt index 129fe50..b0cbb03 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetStore.kt @@ -99,10 +99,15 @@ class CharacterSheetStore( private suspend fun handleMessage(message: Message) { when (val payload = message.value) { - is RestSynchronisation.CharacterUpdate -> getCharacterSheet( - characterSheetId = payload.id, - forceUpdate = true - ) + is RestSynchronisation.CharacterUpdate -> { + getCharacterSheet( + characterSheetId = payload.id, + forceUpdate = true, + ) + if (_previewFlow.value.firstOrNull { it.characterSheetId == payload.id } == null) { + charactersPreview() + } + } is RestSynchronisation.CharacterDelete -> { _previewFlow.value = previewFlow.value.toMutableList() 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 ac12afc..807581f 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,11 +3,14 @@ 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.tooltip.TooltipUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.SkillFieldFactory import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.common.occupation import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.ActionFieldUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.BaseSkillFieldUio +import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.LevelUpWrapperUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SimpleFieldUio +import com.pixelized.desktop.lwa.utils.extention.unAccent import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet import com.pixelized.shared.lwa.usecase.CharacterSheetUseCase import lwacharactersheet.composeapp.generated.resources.Res @@ -20,29 +23,61 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__ch import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__int import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__pow import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__characteristics__str +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__level_up import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__name_label -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__acrobatics -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__aid -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__athletics -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bargain +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__acrobatics_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__acrobatics_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__acrobatics_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__aid_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__aid_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__aid_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__athletics_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__athletics_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__athletics_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bargain_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bargain_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bargain_label import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bonus_label -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__combat -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__discretion -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__dodge -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__empathy -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__grab -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__intimidation +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__combat_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__combat_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__combat_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__discretion_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__discretion_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__discretion_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__dodge_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__dodge_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__dodge_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__empathy_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__empathy_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__empathy_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__grab_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__grab_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__grab_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__intimidation_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__intimidation_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__intimidation_label import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__level_label import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__magic_title -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__perception -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__persuasion -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__search -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__sleight_of_hand +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__perception_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__perception_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__perception_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__persuasion_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__persuasion_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__persuasion_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__search_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__search_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__search_label +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__sleight_of_hand_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__sleight_of_hand_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__sleight_of_hand_label import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__special_title -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__spiel -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__throw +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__spiel_base +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__spiel_description +import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__spiel_label +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 org.jetbrains.compose.resources.getString -import java.util.UUID import kotlin.math.max class CharacterSheetEditFactory( @@ -78,12 +113,12 @@ class CharacterSheetEditFactory( ?: 0 return CharacterSheet( - id = editedSheet.id, + id = editedSheet.id.value, name = editedSheet.name.value.value, portrait = currentSheet?.portrait, thumbnail = currentSheet?.thumbnail, level = level, - shouldLevelUp = currentSheet?.shouldLevelUp ?: false, + shouldLevelUp = editedSheet.levelUp.checked.value, strength = strength, dexterity = dexterity, constitution = constitution, @@ -100,8 +135,10 @@ class CharacterSheetEditFactory( CharacterSheet.Skill( id = editedSkill.id, label = editedSkill.label, - description = currentSkill?.description, - base = "${editedSkill.base.value}", + description = currentSkill?.description + ?: commonSkillDescription(skillId = editedSkill.id), + base = currentSkill?.base + ?: commonSkillBase(skillId = editedSkill.id), bonus = editedSkill.bonus.value.value.takeIf { it.isNotBlank() }, level = editedSkill.level.value.value.toIntOrNull() ?: 0, occupation = editedSkill.option.checked.value, @@ -216,12 +253,16 @@ class CharacterSheetEditFactory( val magicSkillsLabel = getString(Res.string.character_sheet_edit__skills__magic_title) return with(characterSheetUseCase) { + val name = skillFieldFactory.createWrapper( + label = mutableStateOf(getString(Res.string.character_sheet_edit__name_label)), + value = sheet?.name ?: "" + ) CharacterSheetEditPageUio( - id = sheet?.id ?: UUID.randomUUID().toString(), - name = skillFieldFactory.createWrapper( - label = mutableStateOf(getString(Res.string.character_sheet_edit__name_label)), - value = sheet?.name ?: "" - ), + id = derivedStateOf { + sheet?.id ?: name.value.value.unAccent().replace(" ", "_") + }, + levelUp = createLevelUpWrapper(shouldLevelUp = sheet?.shouldLevelUp ?: false), + name = name, strength = str, dexterity = dex, constitution = con, @@ -233,97 +274,113 @@ class CharacterSheetEditFactory( createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.COMBAT_ID, - label = getString(Res.string.character_sheet_edit__skills__combat), + label = getString(Res.string.character_sheet_edit__skills__combat_label), + description = getString(Res.string.character_sheet_edit__skills__combat_description), base = derivedStateOf { normalize(dex() * 2) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.DODGE_ID, - label = getString(Res.string.character_sheet_edit__skills__dodge), + label = getString(Res.string.character_sheet_edit__skills__dodge_label), + description = getString(Res.string.character_sheet_edit__skills__dodge_description), base = derivedStateOf { normalize(dex() * 2) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.GRAB_ID, - label = getString(Res.string.character_sheet_edit__skills__grab), + label = getString(Res.string.character_sheet_edit__skills__grab_label), + description = getString(Res.string.character_sheet_edit__skills__grab_description), base = derivedStateOf { normalize(str() + hei()) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.THROW_ID, - label = getString(Res.string.character_sheet_edit__skills__throw), + label = getString(Res.string.character_sheet_edit__skills__throw_label), + description = getString(Res.string.character_sheet_edit__skills__throw_description), base = derivedStateOf { normalize(str() + dex()) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.ATHLETICS_ID, - label = getString(Res.string.character_sheet_edit__skills__athletics), + label = getString(Res.string.character_sheet_edit__skills__athletics_label), + description = getString(Res.string.character_sheet_edit__skills__athletics_description), base = derivedStateOf { normalize(str() + con() * 2) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.ACROBATICS_ID, - label = getString(Res.string.character_sheet_edit__skills__acrobatics), + label = getString(Res.string.character_sheet_edit__skills__acrobatics_label), + description = getString(Res.string.character_sheet_edit__skills__acrobatics_description), base = derivedStateOf { normalize(dex() + con() * 2) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.PERCEPTION_ID, - label = getString(Res.string.character_sheet_edit__skills__perception), + label = getString(Res.string.character_sheet_edit__skills__perception_label), + description = getString(Res.string.character_sheet_edit__skills__perception_description), base = derivedStateOf { normalize(10 + int() * 2) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.SEARCH_ID, - label = getString(Res.string.character_sheet_edit__skills__search), + label = getString(Res.string.character_sheet_edit__skills__search_label), + description = getString(Res.string.character_sheet_edit__skills__search_description), base = derivedStateOf { normalize(10 + int() * 2) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.EMPATHY_ID, - label = getString(Res.string.character_sheet_edit__skills__empathy), + label = getString(Res.string.character_sheet_edit__skills__empathy_label), + description = getString(Res.string.character_sheet_edit__skills__empathy_description), base = derivedStateOf { normalize(cha() + int()) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.PERSUASION_ID, - label = getString(Res.string.character_sheet_edit__skills__persuasion), + label = getString(Res.string.character_sheet_edit__skills__persuasion_label), + description = getString(Res.string.character_sheet_edit__skills__persuasion_description), base = derivedStateOf { normalize(cha() * 3) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.INTIMIDATION_ID, - label = getString(Res.string.character_sheet_edit__skills__intimidation), + label = getString(Res.string.character_sheet_edit__skills__intimidation_label), + description = getString(Res.string.character_sheet_edit__skills__intimidation_description), base = derivedStateOf { normalize(cha() + max(pow(), hei()) * 2) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.SPIEL_ID, - label = getString(Res.string.character_sheet_edit__skills__spiel), + label = getString(Res.string.character_sheet_edit__skills__spiel_label), + description = getString(Res.string.character_sheet_edit__skills__spiel_description), base = derivedStateOf { normalize(cha() * 2 + int()) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.BARGAIN_ID, - label = getString(Res.string.character_sheet_edit__skills__bargain), + label = getString(Res.string.character_sheet_edit__skills__bargain_label), + description = getString(Res.string.character_sheet_edit__skills__bargain_description), base = derivedStateOf { normalize(cha() * 2) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.DISCRETION_ID, - label = getString(Res.string.character_sheet_edit__skills__discretion), + label = getString(Res.string.character_sheet_edit__skills__discretion_label), + description = getString(Res.string.character_sheet_edit__skills__discretion_description), base = derivedStateOf { normalize(cha() + dex() * 2 - hei()) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID, - label = getString(Res.string.character_sheet_edit__skills__sleight_of_hand), + label = getString(Res.string.character_sheet_edit__skills__sleight_of_hand_label), + description = getString(Res.string.character_sheet_edit__skills__sleight_of_hand_description), base = derivedStateOf { normalize(dex() * 2) }, ), createBaseSkill( sheet = sheet, id = CharacterSheet.CommonSkillId.AID_ID, - label = getString(Res.string.character_sheet_edit__skills__aid), + label = getString(Res.string.character_sheet_edit__skills__aid_label), + description = getString(Res.string.character_sheet_edit__skills__aid_description), base = derivedStateOf { normalize(int() + dex()) }, ), ), @@ -383,10 +440,22 @@ class CharacterSheetEditFactory( } } + private suspend fun createLevelUpWrapper( + shouldLevelUp: Boolean, + ): LevelUpWrapperUio { + val field = mutableStateOf(shouldLevelUp) + return LevelUpWrapperUio( + label = getString(Res.string.character_sheet_edit__level_up), + checked = field, + onCheck = { field.value = it }, + ) + } + private suspend fun createBaseSkill( sheet: CharacterSheet?, id: String, label: String, + description: String, base: State, ): BaseSkillFieldUio { val skill = sheet?.commonSkills?.firstOrNull { it.id == id } @@ -404,10 +473,80 @@ class CharacterSheetEditFactory( value = skill?.level?.takeIf { it > 0 }?.toString() ?: "", ), option = skillFieldFactory.occupationOption(skill?.occupation ?: false), + tooltip = TooltipUio( + title = label, + description = description, + ) ) } private fun SimpleFieldUio.unpack(): String? { return value.value.value.ifBlank { value.placeholder.value } } + + private suspend fun commonSkillBase(skillId: String): String { + return when (skillId) { + CharacterSheet.CommonSkillId.COMBAT_ID -> getString(Res.string.character_sheet_edit__skills__combat_base) + CharacterSheet.CommonSkillId.DODGE_ID -> getString(Res.string.character_sheet_edit__skills__dodge_base) + CharacterSheet.CommonSkillId.GRAB_ID -> getString(Res.string.character_sheet_edit__skills__grab_base) + CharacterSheet.CommonSkillId.THROW_ID -> getString(Res.string.character_sheet_edit__skills__throw_base) + CharacterSheet.CommonSkillId.ATHLETICS_ID -> getString(Res.string.character_sheet_edit__skills__athletics_base) + CharacterSheet.CommonSkillId.ACROBATICS_ID -> getString(Res.string.character_sheet_edit__skills__acrobatics_base) + CharacterSheet.CommonSkillId.PERCEPTION_ID -> getString(Res.string.character_sheet_edit__skills__perception_base) + CharacterSheet.CommonSkillId.SEARCH_ID -> getString(Res.string.character_sheet_edit__skills__search_base) + CharacterSheet.CommonSkillId.EMPATHY_ID -> getString(Res.string.character_sheet_edit__skills__empathy_base) + CharacterSheet.CommonSkillId.PERSUASION_ID -> getString(Res.string.character_sheet_edit__skills__persuasion_base) + CharacterSheet.CommonSkillId.INTIMIDATION_ID -> getString(Res.string.character_sheet_edit__skills__intimidation_base) + CharacterSheet.CommonSkillId.SPIEL_ID -> getString(Res.string.character_sheet_edit__skills__spiel_base) + CharacterSheet.CommonSkillId.BARGAIN_ID -> getString(Res.string.character_sheet_edit__skills__bargain_base) + CharacterSheet.CommonSkillId.DISCRETION_ID -> getString(Res.string.character_sheet_edit__skills__discretion_base) + CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID -> getString(Res.string.character_sheet_edit__skills__sleight_of_hand_base) + CharacterSheet.CommonSkillId.AID_ID -> getString(Res.string.character_sheet_edit__skills__aid_base) + else -> "" + } + } + + private suspend fun commonSkillLabel(skillId: String): String { + return when (skillId) { + CharacterSheet.CommonSkillId.COMBAT_ID -> getString(Res.string.character_sheet_edit__skills__combat_label) + CharacterSheet.CommonSkillId.DODGE_ID -> getString(Res.string.character_sheet_edit__skills__dodge_label) + CharacterSheet.CommonSkillId.GRAB_ID -> getString(Res.string.character_sheet_edit__skills__grab_label) + CharacterSheet.CommonSkillId.THROW_ID -> getString(Res.string.character_sheet_edit__skills__throw_label) + CharacterSheet.CommonSkillId.ATHLETICS_ID -> getString(Res.string.character_sheet_edit__skills__athletics_label) + CharacterSheet.CommonSkillId.ACROBATICS_ID -> getString(Res.string.character_sheet_edit__skills__acrobatics_label) + CharacterSheet.CommonSkillId.PERCEPTION_ID -> getString(Res.string.character_sheet_edit__skills__perception_label) + CharacterSheet.CommonSkillId.SEARCH_ID -> getString(Res.string.character_sheet_edit__skills__search_label) + CharacterSheet.CommonSkillId.EMPATHY_ID -> getString(Res.string.character_sheet_edit__skills__empathy_label) + CharacterSheet.CommonSkillId.PERSUASION_ID -> getString(Res.string.character_sheet_edit__skills__persuasion_label) + CharacterSheet.CommonSkillId.INTIMIDATION_ID -> getString(Res.string.character_sheet_edit__skills__intimidation_label) + CharacterSheet.CommonSkillId.SPIEL_ID -> getString(Res.string.character_sheet_edit__skills__spiel_label) + CharacterSheet.CommonSkillId.BARGAIN_ID -> getString(Res.string.character_sheet_edit__skills__bargain_label) + CharacterSheet.CommonSkillId.DISCRETION_ID -> getString(Res.string.character_sheet_edit__skills__discretion_label) + CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID -> getString(Res.string.character_sheet_edit__skills__sleight_of_hand_label) + CharacterSheet.CommonSkillId.AID_ID -> getString(Res.string.character_sheet_edit__skills__aid_label) + else -> "" + } + } + + private suspend fun commonSkillDescription(skillId: String): String { + return when (skillId) { + CharacterSheet.CommonSkillId.COMBAT_ID -> getString(Res.string.character_sheet_edit__skills__combat_description) + CharacterSheet.CommonSkillId.DODGE_ID -> getString(Res.string.character_sheet_edit__skills__dodge_description) + CharacterSheet.CommonSkillId.GRAB_ID -> getString(Res.string.character_sheet_edit__skills__grab_description) + CharacterSheet.CommonSkillId.THROW_ID -> getString(Res.string.character_sheet_edit__skills__throw_description) + CharacterSheet.CommonSkillId.ATHLETICS_ID -> getString(Res.string.character_sheet_edit__skills__athletics_description) + CharacterSheet.CommonSkillId.ACROBATICS_ID -> getString(Res.string.character_sheet_edit__skills__acrobatics_description) + CharacterSheet.CommonSkillId.PERCEPTION_ID -> getString(Res.string.character_sheet_edit__skills__perception_description) + CharacterSheet.CommonSkillId.SEARCH_ID -> getString(Res.string.character_sheet_edit__skills__search_description) + CharacterSheet.CommonSkillId.EMPATHY_ID -> getString(Res.string.character_sheet_edit__skills__empathy_description) + CharacterSheet.CommonSkillId.PERSUASION_ID -> getString(Res.string.character_sheet_edit__skills__persuasion_description) + CharacterSheet.CommonSkillId.INTIMIDATION_ID -> getString(Res.string.character_sheet_edit__skills__intimidation_description) + CharacterSheet.CommonSkillId.SPIEL_ID -> getString(Res.string.character_sheet_edit__skills__spiel_description) + CharacterSheet.CommonSkillId.BARGAIN_ID -> getString(Res.string.character_sheet_edit__skills__bargain_description) + CharacterSheet.CommonSkillId.DISCRETION_ID -> getString(Res.string.character_sheet_edit__skills__discretion_description) + CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID -> getString(Res.string.character_sheet_edit__skills__sleight_of_hand_description) + CharacterSheet.CommonSkillId.AID_ID -> getString(Res.string.character_sheet_edit__skills__aid_description) + else -> "" + } + } } \ No newline at end of file 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 16d5eb1..9c24d1e 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 @@ -21,6 +21,7 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.Add import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable +import androidx.compose.runtime.State import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -34,12 +35,15 @@ import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.Action import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.ActionFieldUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.BaseSkillFieldUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.BaseSkillForm +import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.LevelUpField +import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.LevelUpWrapperUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SimpleField import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SimpleFieldUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SkillFieldUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.SkillForm import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapper import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapperUio +import com.pixelized.desktop.lwa.ui.theme.lwa import kotlinx.coroutines.launch import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.character_sheet__skills__common_title @@ -50,7 +54,6 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__ch import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__save_action import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__magic_action import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__special_action -import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__sub_characteristics__title import lwacharactersheet.composeapp.generated.resources.ic_save_24dp import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.stringResource @@ -58,7 +61,8 @@ import org.koin.compose.viewmodel.koinViewModel @Stable data class CharacterSheetEditPageUio( - val id: String, + val id: State, + val levelUp: LevelUpWrapperUio, val name: TextFieldWrapperUio, val strength: SimpleFieldUio, val dexterity: SimpleFieldUio, @@ -168,6 +172,19 @@ fun CharacterSheetEdit( .padding(all = 16.dp), verticalArrangement = Arrangement.spacedBy(space = 16.dp) ) { + Row( + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + modifier = Modifier.weight(1f), + style = MaterialTheme.lwa.typography.base.caption, + text = form.id.value + ) + LevelUpField( + field = form.levelUp, + ) + } + TextFieldWrapper( modifier = Modifier.fillMaxWidth(), wrapper = form.name, 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 9be7f37..bbe9da5 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 @@ -108,7 +108,7 @@ class CharacterSheetEditViewModel( suspend fun save() { val updatedSheet = sheetFactory.updateCharacterSheet( - currentSheet = characterSheetRepository.characterDetail(characterSheetId = _characterSheet.value.id), + currentSheet = characterSheetRepository.characterDetail(characterSheetId = _characterSheet.value.id.value), editedSheet = _characterSheet.value, ) characterSheetRepository.updateCharacter( diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/BaseSkillField.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/BaseSkillField.kt index 6f96d51..5965f79 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/BaseSkillField.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/BaseSkillField.kt @@ -1,5 +1,6 @@ package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -24,6 +25,8 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp +import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout +import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipUio import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.CheckedOption import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.option.DropDownCheckedMenuItem import com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable.textfield.TextFieldWrapper @@ -40,8 +43,10 @@ class BaseSkillFieldUio( val bonus: TextFieldWrapperUio, val level: TextFieldWrapperUio, val option: CheckedOption, + val tooltip: TooltipUio, ) +@OptIn(ExperimentalFoundationApi::class) @Composable fun BaseSkillForm( modifier: Modifier = Modifier, @@ -75,24 +80,27 @@ fun BaseSkillForm( maxLines = 1, text = field.label, ) - Column( + TooltipLayout( modifier = Modifier .width(width = 96.dp) .padding(start = 16.dp), + tooltip = field.tooltip, ) { - Text( - style = MaterialTheme.typography.caption, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - color = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium), - text = baseLabel.value, - ) - Text( - style = MaterialTheme.typography.body1, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - text = "+${field.base.value}", - ) + Column { + Text( + style = MaterialTheme.typography.caption, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + color = MaterialTheme.colors.onSurface.copy(ContentAlpha.medium), + text = baseLabel.value, + ) + Text( + style = MaterialTheme.typography.body1, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + text = "+${field.base.value}", + ) + } } TextFieldWrapper( modifier = Modifier.width(width = 96.dp), diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/LevelUpField.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/LevelUpField.kt new file mode 100644 index 0000000..cd5eb2e --- /dev/null +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/LevelUpField.kt @@ -0,0 +1,39 @@ +package com.pixelized.desktop.lwa.ui.screen.characterSheet.edit.composable + +import androidx.compose.foundation.layout.Row +import androidx.compose.material.Checkbox +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.State +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import com.pixelized.desktop.lwa.ui.theme.lwa + +@Stable +class LevelUpWrapperUio( + val label: String, + val checked: State, + val onCheck: (Boolean) -> Unit, +) + +@Composable +fun LevelUpField( + modifier: Modifier = Modifier, + field: LevelUpWrapperUio, +) { + Row( + modifier = modifier, + verticalAlignment = Alignment.CenterVertically, + ) { + Text( + style = MaterialTheme.lwa.typography.base.body1, + text = field.label, + ) + Checkbox( + checked = field.checked.value, + onCheckedChange = field.onCheck, + ) + } +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/option/ActionOption.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/option/ActionOption.kt index 66c0811..14d4e01 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/option/ActionOption.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/option/ActionOption.kt @@ -17,9 +17,15 @@ sealed class ActionOption( val label: String, onOption: () -> Unit, ) : OptionUio(onOption = onOption) { - - class DeleteOptionUio(icon: ImageVector, label: String, onOption: () -> Unit) : - ActionOption(icon = icon, label = label, onOption = onOption) + class DeleteOptionUio( + icon: ImageVector, + label: String, + onOption: () -> Unit, + ) : ActionOption( + icon = icon, + label = label, + onOption = onOption, + ) } @Composable diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/option/CheckedOption.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/option/CheckedOption.kt index 6425f3b..c0b657e 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/option/CheckedOption.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/characterSheet/edit/composable/option/CheckedOption.kt @@ -19,8 +19,15 @@ sealed class CheckedOption( val checked: State, onOption: () -> Unit, ) : OptionUio(onOption = onOption) { - class OccupationOption(label: String, checked: State, onOption: () -> Unit) : - CheckedOption(label = label, checked = checked, onOption = onOption) + class OccupationOption( + label: String, + checked: State, + onOption: () -> Unit, + ) : CheckedOption( + label = label, + checked = checked, + onOption = onOption, + ) } @Composable diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt index f760711..2a35d02 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/ui/screen/gamemaster/GameMasterFactory.kt @@ -1,15 +1,15 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster -import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetPreview import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterUio import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMCharacterUio.Action import com.pixelized.desktop.lwa.ui.screen.gamemaster.items.GMTagUio +import com.pixelized.desktop.lwa.utils.extention.unAccent import com.pixelized.shared.lwa.model.campaign.Campaign +import com.pixelized.shared.lwa.model.characterSheet.CharacterSheetPreview import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__character_label import lwacharactersheet.composeapp.generated.resources.game_master__character_tag__npc_label import org.jetbrains.compose.resources.getString -import java.text.Normalizer class GameMasterFactory { @@ -19,7 +19,7 @@ class GameMasterFactory { filter: String, tags: Map, ): List { - val normalizedFilter = Normalizer.normalize(filter, Normalizer.Form.NFD) + val normalizedFilter = filter.unAccent() return characters.mapNotNull { convertToGMCharacterPreviewUio( @@ -48,7 +48,7 @@ class GameMasterFactory { } // Filter process : Name. if (filter.isNotEmpty()) { - val normalizedName = Normalizer.normalize(character.name, Normalizer.Form.NFD) + val normalizedName = character.name.unAccent() // If the filter is not empty and the character is not val nameHighlight = normalizedName.contains(other = filter, ignoreCase = true) if (nameHighlight.not()) { diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/utils/extention/StringExt.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/utils/extention/StringExt.kt index 3975d9a..81dce9c 100644 --- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/utils/extention/StringExt.kt +++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/utils/extention/StringExt.kt @@ -1,3 +1,12 @@ package com.pixelized.desktop.lwa.utils.extention -val String.ARG: String get() = "$this={$this}" \ No newline at end of file +import java.text.Normalizer + +private val REGEX_UN_ACCENT = "\\p{InCombiningDiacriticalMarks}+".toRegex() + +val String.ARG: String get() = "$this={$this}" + +fun CharSequence.unAccent(): String { + val temp = Normalizer.normalize(this, Normalizer.Form.NFD) + return REGEX_UN_ACCENT.replace(temp, "") +} \ No newline at end of file