diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index 06d6a12..ce157a1 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -47,6 +47,7 @@
Ajouter une compétence spéciale
Compétences magiques
Ajouter une compétence magique
+ Description
Base
Bonus
Niveau
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt
index 8b333a7..274acf8 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/Module.kt
@@ -9,6 +9,7 @@ import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetJsonFactory
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetRepository
import com.pixelized.desktop.lwa.repository.characterSheet.CharacterSheetStore
+import com.pixelized.desktop.lwa.repository.characterSheet.SkillDescriptionFactory
import com.pixelized.desktop.lwa.repository.network.NetworkRepository
import com.pixelized.desktop.lwa.repository.roll_history.RollHistoryRepository
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetFactory
@@ -50,6 +51,7 @@ val factoryDependencies
factoryOf(::CharacterSheetJsonFactory)
factoryOf(::NetworkFactory)
factoryOf(::SkillFieldFactory)
+ factoryOf(::SkillDescriptionFactory)
}
val viewModelDependencies
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetJsonFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetJsonFactory.kt
index 16edad1..f6bde59 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetJsonFactory.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/CharacterSheetJsonFactory.kt
@@ -5,11 +5,30 @@ import com.pixelized.desktop.lwa.parser.arithmetic.ArithmeticParser
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJson
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJsonV1
+import kotlinx.coroutines.runBlocking
+import lwacharactersheet.composeapp.generated.resources.Res
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__acrobatics
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__aid
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__athletics
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__bargain
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__combat
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__discretion
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__dodge
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__empathy
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__grab
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__intimidation
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__perception
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__persuasion
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__search
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__sleight_of_hand
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__spiel
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__throw
+import org.jetbrains.compose.resources.getString
import kotlin.math.ceil
class CharacterSheetJsonFactory(
private val bonusDamageUseCase: DamageBonusUseCase,
- private val arithmeticParser: ArithmeticParser,
+ private val skillDescriptionFactory: SkillDescriptionFactory,
) {
fun convertToJson(
@@ -36,6 +55,7 @@ class CharacterSheetJsonFactory(
CharacterSheetJsonV1.Skill(
id = it.id,
label = it.label,
+ description = null,
base = it.base,
bonus = it.bonus,
level = it.level,
@@ -47,6 +67,7 @@ class CharacterSheetJsonFactory(
CharacterSheetJsonV1.Skill(
id = it.id,
label = it.label,
+ description = it.description,
base = it.base,
bonus = it.bonus,
level = it.level,
@@ -58,6 +79,7 @@ class CharacterSheetJsonFactory(
CharacterSheetJsonV1.Skill(
id = it.id,
label = it.label,
+ description = it.description,
base = it.base,
bonus = it.bonus,
level = it.level,
@@ -76,7 +98,7 @@ class CharacterSheetJsonFactory(
return json
}
- fun convertFromJson(
+ suspend fun convertFromJson(
json: CharacterSheetJson,
): CharacterSheet {
return when (json) {
@@ -84,7 +106,7 @@ class CharacterSheetJsonFactory(
}
}
- private fun convertFromV1(
+ private suspend fun convertFromV1(
json: CharacterSheetJsonV1,
): CharacterSheet {
val sheet = CharacterSheet(
@@ -117,6 +139,7 @@ class CharacterSheetJsonFactory(
CharacterSheet.Skill(
id = it.id,
label = it.label,
+ description = skillDescriptionFactory.baseSkillDescription(id = json.id),
base = it.base,
bonus = it.bonus,
level = it.level,
@@ -128,6 +151,7 @@ class CharacterSheetJsonFactory(
CharacterSheet.Skill(
id = it.id,
label = it.label,
+ description = it.description,
base = it.base,
bonus = it.bonus,
level = it.level,
@@ -139,6 +163,7 @@ class CharacterSheetJsonFactory(
CharacterSheet.Skill(
id = it.id,
label = it.label,
+ description = it.description,
base = it.base,
bonus = it.bonus,
level = it.level,
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 47d2dd6..a0e3986 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
@@ -3,8 +3,12 @@ package com.pixelized.desktop.lwa.repository.characterSheet
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheetJson
import com.pixelized.desktop.lwa.repository.characterStorePath
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.File
@@ -13,7 +17,15 @@ class CharacterSheetStore(
private val factory: CharacterSheetJsonFactory,
) {
private val characterDirectory = File(characterStorePath()).also { it.mkdirs() }
- private val flow = MutableStateFlow(value = load())
+ private val jsonFormatter: Json = Json { explicitNulls = false }
+ private val flow = MutableStateFlow>(value = emptyList())
+
+ init {
+ val scope = CoroutineScope(Dispatchers.IO + Job())
+ scope.launch {
+ flow.value = load()
+ }
+ }
fun characterSheetFlow(): StateFlow> = flow
@@ -25,7 +37,7 @@ class CharacterSheetStore(
fun save(sheet: CharacterSheet) {
// convert the character sheet into json format.
val json = try {
- factory.convertToJson(sheet = sheet).let(Json::encodeToString)
+ factory.convertToJson(sheet = sheet).let(jsonFormatter::encodeToString)
} catch (exception: Exception) {
throw JsonConversionException(root = exception)
}
@@ -72,7 +84,7 @@ class CharacterSheetStore(
FileReadException::class,
JsonConversionException::class,
)
- fun load(): List {
+ suspend fun load(): List {
return characterDirectory
.listFiles()
?.mapNotNull { file ->
@@ -86,7 +98,7 @@ class CharacterSheetStore(
return@mapNotNull null
}
try {
- val sheet = Json.decodeFromString(json)
+ val sheet = jsonFormatter.decodeFromString(json)
factory.convertFromJson(sheet)
} catch (exception: Exception) {
throw JsonConversionException(root = exception)
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/SkillDescriptionFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/SkillDescriptionFactory.kt
new file mode 100644
index 0000000..bc3fdf8
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/SkillDescriptionFactory.kt
@@ -0,0 +1,47 @@
+package com.pixelized.desktop.lwa.repository.characterSheet
+
+import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
+import lwacharactersheet.composeapp.generated.resources.Res
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__acrobatics
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__aid
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__athletics
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__bargain
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__combat
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__discretion
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__dodge
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__empathy
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__grab
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__intimidation
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__perception
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__persuasion
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__search
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__sleight_of_hand
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__spiel
+import lwacharactersheet.composeapp.generated.resources.tooltip__skills__throw
+import org.jetbrains.compose.resources.getString
+
+class SkillDescriptionFactory {
+
+ suspend fun baseSkillDescription(id: String): String? {
+ return when (id) {
+ CharacterSheet.CommonSkillId.COMBAT_ID -> getString(Res.string.tooltip__skills__combat)
+ CharacterSheet.CommonSkillId.DODGE_ID -> getString(Res.string.tooltip__skills__dodge)
+ CharacterSheet.CommonSkillId.GRAB_ID -> getString(Res.string.tooltip__skills__grab)
+ CharacterSheet.CommonSkillId.THROW_ID -> getString(Res.string.tooltip__skills__throw)
+ CharacterSheet.CommonSkillId.ATHLETICS_ID -> getString(Res.string.tooltip__skills__athletics)
+ CharacterSheet.CommonSkillId.ACROBATICS_ID -> getString(Res.string.tooltip__skills__acrobatics)
+ CharacterSheet.CommonSkillId.PERCEPTION_ID -> getString(Res.string.tooltip__skills__perception)
+ CharacterSheet.CommonSkillId.SEARCH_ID -> getString(Res.string.tooltip__skills__search)
+ CharacterSheet.CommonSkillId.EMPATHY_ID -> getString(Res.string.tooltip__skills__empathy)
+ CharacterSheet.CommonSkillId.PERSUASION_ID -> getString(Res.string.tooltip__skills__persuasion)
+ CharacterSheet.CommonSkillId.INTIMIDATION_ID -> getString(Res.string.tooltip__skills__intimidation)
+ CharacterSheet.CommonSkillId.SPIEL_ID -> getString(Res.string.tooltip__skills__spiel)
+ CharacterSheet.CommonSkillId.BARGAIN_ID -> getString(Res.string.tooltip__skills__bargain)
+ CharacterSheet.CommonSkillId.DISCRETION_ID -> getString(Res.string.tooltip__skills__discretion)
+ CharacterSheet.CommonSkillId.SLEIGHT_OF_HAND_ID -> getString(Res.string.tooltip__skills__sleight_of_hand)
+ CharacterSheet.CommonSkillId.AID_ID -> getString(Res.string.tooltip__skills__aid)
+ else -> null
+ }
+ }
+}
+
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheet.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheet.kt
index 2080ade..34a282a 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheet.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheet.kt
@@ -34,6 +34,7 @@ data class CharacterSheet(
data class Skill(
val id: String,
val label: String,
+ val description: String?,
val base: String,
val bonus: Int?,
val level: Int?,
@@ -48,21 +49,21 @@ data class CharacterSheet(
)
object CommonSkillId {
- const val COMBAT_ID = "Bagarre"
- const val DODGE_ID = "Esquive"
- const val GRAB_ID = "Saisie"
- const val THROW_ID = "Lancer"
- const val ATHLETICS_ID = "Athlétisme"
- const val ACROBATICS_ID = "Acrobatie"
- const val PERCEPTION_ID = "Perception"
- const val SEARCH_ID = "Recherche"
- const val EMPATHY_ID = "Empathie"
- const val PERSUASION_ID = "Persuasion"
- const val INTIMIDATION_ID = "Intimidation"
- const val SPIEL_ID = "Baratin"
- const val BARGAIN_ID = "Marchandage"
- const val DISCRETION_ID = "Discrétion"
- const val SLEIGHT_OF_HAND_ID = "Escamotage"
- const val AID_ID = "Premiers soins"
+ const val COMBAT_ID = "COMBAT"
+ const val DODGE_ID = "DODGE"
+ const val GRAB_ID = "GRAB"
+ const val THROW_ID = "THROW"
+ const val ATHLETICS_ID = "ATHLETICS"
+ const val ACROBATICS_ID = "ACROBATICS"
+ const val PERCEPTION_ID = "PERCEPTION"
+ const val SEARCH_ID = "SEARCH"
+ const val EMPATHY_ID = "EMPATHY"
+ const val PERSUASION_ID = "PERSUASION"
+ const val INTIMIDATION_ID = "INTIMIDATION"
+ const val SPIEL_ID = "SPIEL"
+ const val BARGAIN_ID = "BARGAIN"
+ const val DISCRETION_ID = "DISCRETION"
+ const val SLEIGHT_OF_HAND_ID = "SLEIGHT_OF_HAND"
+ const val AID_ID = "AID"
}
}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJsonV1.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJsonV1.kt
index 559625c..1ae8024 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJsonV1.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/repository/characterSheet/model/CharacterSheetJsonV1.kt
@@ -31,10 +31,12 @@ data class CharacterSheetJsonV1(
// attack
val rolls: List,
) : CharacterSheetJson {
+
@Serializable
data class Skill(
val id: String,
val label: String,
+ val description: String?,
val base: String,
val bonus: Int?,
val level: Int?,
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetFactory.kt
index fb9b02c..5b6b251 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetFactory.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetFactory.kt
@@ -2,8 +2,8 @@ package com.pixelized.desktop.lwa.screen.characterSheet.detail
import com.pixelized.desktop.lwa.business.SkillValueComputationUseCase
import com.pixelized.desktop.lwa.composable.tooltip.TooltipUio
+import com.pixelized.desktop.lwa.repository.characterSheet.SkillDescriptionFactory
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
-import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet.CommonSkillId
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio.Characteristic
import com.pixelized.desktop.lwa.screen.characterSheet.detail.CharacterSheetPageUio.Node
import lwacharactersheet.composeapp.generated.resources.Res
@@ -26,22 +26,6 @@ import lwacharactersheet.composeapp.generated.resources.tooltip__characteristics
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 lwacharactersheet.composeapp.generated.resources.tooltip__skills__acrobatics
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__aid
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__athletics
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__bargain
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__combat
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__discretion
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__dodge
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__empathy
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__grab
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__intimidation
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__perception
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__persuasion
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__search
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__sleight_of_hand
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__spiel
-import lwacharactersheet.composeapp.generated.resources.tooltip__skills__throw
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__armor
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__bonus_damage
import lwacharactersheet.composeapp.generated.resources.tooltip__sub_characteristics__hit_point
@@ -51,6 +35,7 @@ import org.jetbrains.compose.resources.getString
class CharacterSheetFactory(
private val skillUseCase: SkillValueComputationUseCase,
+ private val skillDescriptionFactory: SkillDescriptionFactory,
) {
companion object {
const val HP = "HP"
@@ -189,25 +174,6 @@ class CharacterSheetFactory(
),
),
commonSkills = sheet.commonSkills.map { skill ->
- val description = when (skill.id) {
- CommonSkillId.COMBAT_ID -> getString(Res.string.tooltip__skills__combat)
- CommonSkillId.DODGE_ID -> getString(Res.string.tooltip__skills__dodge)
- CommonSkillId.GRAB_ID -> getString(Res.string.tooltip__skills__grab)
- CommonSkillId.THROW_ID -> getString(Res.string.tooltip__skills__throw)
- CommonSkillId.ATHLETICS_ID -> getString(Res.string.tooltip__skills__athletics)
- CommonSkillId.ACROBATICS_ID -> getString(Res.string.tooltip__skills__acrobatics)
- CommonSkillId.PERCEPTION_ID -> getString(Res.string.tooltip__skills__perception)
- CommonSkillId.SEARCH_ID -> getString(Res.string.tooltip__skills__search)
- CommonSkillId.EMPATHY_ID -> getString(Res.string.tooltip__skills__empathy)
- CommonSkillId.PERSUASION_ID -> getString(Res.string.tooltip__skills__persuasion)
- CommonSkillId.INTIMIDATION_ID -> getString(Res.string.tooltip__skills__intimidation)
- CommonSkillId.SPIEL_ID -> getString(Res.string.tooltip__skills__spiel)
- CommonSkillId.BARGAIN_ID -> getString(Res.string.tooltip__skills__bargain)
- CommonSkillId.DISCRETION_ID -> getString(Res.string.tooltip__skills__discretion)
- CommonSkillId.SLEIGHT_OF_HAND_ID -> getString(Res.string.tooltip__skills__sleight_of_hand)
- CommonSkillId.AID_ID -> getString(Res.string.tooltip__skills__aid)
- else -> null
- }
Node(
label = skill.label,
value = skillUseCase.computeSkillValue(
@@ -215,7 +181,7 @@ class CharacterSheetFactory(
skill = skill,
diminished = diminished,
),
- tooltips = description?.let {
+ tooltips = skillDescriptionFactory.baseSkillDescription(id = skill.id)?.let {
TooltipUio(
title = skill.label,
description = it,
@@ -224,26 +190,38 @@ class CharacterSheetFactory(
used = skill.used,
)
},
- specialSKills = sheet.specialSkills.map {
+ specialSKills = sheet.specialSkills.map { skill ->
Node(
- label = it.label,
+ label = skill.label,
+ tooltips = skill.description?.takeIf { it.isNotBlank() }?.let { description ->
+ TooltipUio(
+ title = skill.label,
+ description = description,
+ )
+ },
value = skillUseCase.computeSkillValue(
sheet = sheet,
- skill = it,
+ skill = skill,
diminished = diminished,
),
- used = it.used,
+ used = skill.used,
)
},
- magicsSkills = sheet.magicSkills.map {
+ magicsSkills = sheet.magicSkills.map { skill ->
Node(
- label = it.label,
+ label = skill.label,
+ tooltips = skill.description?.takeIf { it.isNotBlank() }?.let { description ->
+ TooltipUio(
+ title = skill.label,
+ description = description,
+ )
+ },
value = skillUseCase.computeSkillValue(
sheet = sheet,
- skill = it,
+ skill = skill,
diminished = diminished,
),
- used = it.used,
+ used = skill.used,
)
},
actions = sheet.actions.mapNotNull {
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetPage.kt
index 38de253..f201d64 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetPage.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/detail/CharacterSheetPage.kt
@@ -1,6 +1,7 @@
package com.pixelized.desktop.lwa.screen.characterSheet.detail
import androidx.compose.animation.AnimatedContent
+import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
@@ -446,47 +447,55 @@ fun CharacterSheetPageContent(
}
}
}
- DecoratedBox(
- modifier = Modifier
- .fillMaxWidth()
- .padding(vertical = 8.dp),
+ AnimatedVisibility(
+ visible = characterSheet.specialSKills.isNotEmpty()
) {
- Column {
- Text(
- modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
- style = MaterialTheme.typography.caption,
- textAlign = TextAlign.Center,
- text = stringResource(Res.string.character_sheet__skills__special_title),
- )
- characterSheet.specialSKills.forEach { occupation ->
- Skill(
- modifier = Modifier.cell(),
- node = occupation,
- onClick = { onSkill(occupation) },
- onUse = { onUseSkill(occupation) },
+ DecoratedBox(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 8.dp),
+ ) {
+ Column {
+ Text(
+ modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
+ style = MaterialTheme.typography.caption,
+ textAlign = TextAlign.Center,
+ text = stringResource(Res.string.character_sheet__skills__special_title),
)
+ characterSheet.specialSKills.forEach { occupation ->
+ Skill(
+ modifier = Modifier.cell(),
+ node = occupation,
+ onClick = { onSkill(occupation) },
+ onUse = { onUseSkill(occupation) },
+ )
+ }
}
}
}
- DecoratedBox(
- modifier = Modifier
- .fillMaxWidth()
- .padding(vertical = 8.dp),
+ AnimatedVisibility(
+ visible = characterSheet.magicsSkills.isNotEmpty()
) {
- Column {
- Text(
- modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
- style = MaterialTheme.typography.caption,
- textAlign = TextAlign.Center,
- text = stringResource(Res.string.character_sheet__skills__magic_title),
- )
- characterSheet.magicsSkills.forEach { magic ->
- Skill(
- modifier = Modifier.cell(),
- node = magic,
- onClick = { onSkill(magic) },
- onUse = { onUseSkill(magic) },
+ DecoratedBox(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(vertical = 8.dp),
+ ) {
+ Column {
+ Text(
+ modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
+ style = MaterialTheme.typography.caption,
+ textAlign = TextAlign.Center,
+ text = stringResource(Res.string.character_sheet__skills__magic_title),
)
+ characterSheet.magicsSkills.forEach { magic ->
+ Skill(
+ modifier = Modifier.cell(),
+ node = magic,
+ onClick = { onSkill(magic) },
+ onUse = { onUseSkill(magic) },
+ )
+ }
}
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditFactory.kt
index 3a584b9..3c5a4cb 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditFactory.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditFactory.kt
@@ -5,6 +5,7 @@ import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf
import com.pixelized.desktop.lwa.business.DamageBonusUseCase
import com.pixelized.desktop.lwa.business.SkillNormalizerUseCase
+import com.pixelized.desktop.lwa.repository.characterSheet.SkillDescriptionFactory
import com.pixelized.desktop.lwa.repository.characterSheet.model.CharacterSheet
import com.pixelized.desktop.lwa.screen.characterSheet.edit.common.SkillFieldFactory
import com.pixelized.desktop.lwa.screen.characterSheet.edit.common.occupation
@@ -57,10 +58,11 @@ import kotlin.math.min
class CharacterSheetEditFactory(
private val bonusDamageUseCase: DamageBonusUseCase,
- private val skillFactory: SkillFieldFactory,
+ private val skillFieldFactory: SkillFieldFactory,
+ private val skillDescriptionFactory: SkillDescriptionFactory,
private val normalizer: SkillNormalizerUseCase,
) {
- fun updateCharacterSheet(
+ suspend fun updateCharacterSheet(
currentSheet: CharacterSheet?,
editedSheet: CharacterSheetEditPageUio,
): CharacterSheet {
@@ -121,6 +123,7 @@ class CharacterSheetEditFactory(
CharacterSheet.Skill(
id = editedSkill.id,
label = editedSkill.label,
+ description = skillDescriptionFactory.baseSkillDescription(editedSkill.id),
base = "${editedSkill.base.value}",
bonus = editedSkill.bonus.value.value.toIntOrNull(),
level = editedSkill.level.value.value.toIntOrNull(),
@@ -135,6 +138,7 @@ class CharacterSheetEditFactory(
CharacterSheet.Skill(
id = editedSkill.id,
label = editedSkill.label.value.value,
+ description = editedSkill.description.value.value,
base = editedSkill.base.value.value,
bonus = editedSkill.bonus.value.value.toIntOrNull(),
level = editedSkill.level.value.value.toIntOrNull(),
@@ -149,6 +153,7 @@ class CharacterSheetEditFactory(
CharacterSheet.Skill(
id = editedSkill.id,
label = editedSkill.label.value.value,
+ description = editedSkill.description.value.value,
base = editedSkill.base.value.value,
bonus = editedSkill.bonus.value.value.toIntOrNull(),
level = editedSkill.level.value.value.toIntOrNull(),
@@ -172,49 +177,49 @@ class CharacterSheetEditFactory(
): CharacterSheetEditPageUio {
val str = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__characteristics__str),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = sheet?.strength?.toString() ?: "",
placeholder = mutableStateOf("10")
),
)
val dex = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__characteristics__dex),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = sheet?.dexterity?.toString() ?: "",
placeholder = mutableStateOf("10"),
),
)
val con = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__characteristics__con),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = sheet?.constitution?.toString() ?: "",
placeholder = mutableStateOf("10"),
)
)
val hei = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__characteristics__hei),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = sheet?.height?.toString() ?: "",
placeholder = mutableStateOf("10"),
)
)
val int = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__characteristics__int),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = sheet?.intelligence?.toString() ?: "",
placeholder = mutableStateOf("10"),
)
)
val pow = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__characteristics__pow),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = sheet?.power?.toString() ?: "",
placeholder = mutableStateOf("10"),
)
)
val cha = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__characteristics__cha),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = sheet?.charisma?.toString() ?: "",
placeholder = mutableStateOf("10"),
)
@@ -233,14 +238,14 @@ class CharacterSheetEditFactory(
val maxHitPoint = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__max_hit_point),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideMaxHp == true) "${sheet.maxHp}" else "",
placeholder = derivedStateOf { "${ceil((con() + hei()) / 2f).toInt()}" },
)
)
val maxPowerPoint = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__max_power_point),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideMaxPP == true) "${sheet.maxPp}" else "",
placeholder = derivedStateOf { "${pow()}" },
)
@@ -248,7 +253,7 @@ class CharacterSheetEditFactory(
return CharacterSheetEditPageUio(
id = sheet?.id ?: UUID.randomUUID().toString(),
- name = skillFactory.createWrapper(
+ name = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__name_label)),
value = sheet?.name ?: ""
),
@@ -261,7 +266,7 @@ class CharacterSheetEditFactory(
charisma = cha,
movement = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__movement),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideMovement == true) "${sheet.movement}" else "",
placeholder = mutableStateOf("10"),
)
@@ -269,7 +274,7 @@ class CharacterSheetEditFactory(
maxHp = maxHitPoint,
currentHp = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__hit_point),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
enable = false,
placeholder = derivedStateOf {
val min = min(
@@ -283,7 +288,7 @@ class CharacterSheetEditFactory(
maxPp = maxPowerPoint,
currentPp = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__power_point),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
enable = false,
placeholder = derivedStateOf {
val min = min(
@@ -296,7 +301,7 @@ class CharacterSheetEditFactory(
),
damageBonus = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__damage_bonus),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideDamageBonus == true) sheet.damageBonus else "",
placeholder = derivedStateOf {
bonusDamageUseCase.bonusDamage(
@@ -308,7 +313,7 @@ class CharacterSheetEditFactory(
),
armor = SimpleFieldUio(
label = getString(Res.string.character_sheet_edit__sub_characteristics__armor),
- value = skillFactory.createWrapper(
+ value = skillFieldFactory.createWrapper(
value = if (sheet?.overrideArmor == true) "${sheet.armor}" else "",
placeholder = mutableStateOf("0"),
)
@@ -412,9 +417,10 @@ class CharacterSheetEditFactory(
),
),
specialSkills = sheet?.specialSkills?.map { skill ->
- skillFactory.createSkill(
+ skillFieldFactory.createSkill(
id = skill.id,
label = specialSkillsLabel,
+ descriptionValue = skill.description ?: "",
labelValue = skill.label,
baseValue = skill.base,
bonusValue = skill.bonus?.toString() ?: "",
@@ -422,16 +428,17 @@ class CharacterSheetEditFactory(
options = run {
val current = sheet.specialSkills.firstOrNull { it.id == skill.id }
listOf(
- skillFactory.occupationOption(checked = current?.occupation ?: false),
- skillFactory.deleteOption { onDeleteSkill(skill.id) },
+ skillFieldFactory.occupationOption(checked = current?.occupation ?: false),
+ skillFieldFactory.deleteOption { onDeleteSkill(skill.id) },
)
},
)
} ?: emptyList(),
magicSkills = sheet?.magicSkills?.map { skill ->
- skillFactory.createSkill(
+ skillFieldFactory.createSkill(
id = skill.id,
label = magicSkillsLabel,
+ descriptionValue = skill.description ?: "",
labelValue = skill.label,
baseValue = skill.base,
bonusValue = skill.bonus?.toString() ?: "",
@@ -439,8 +446,8 @@ class CharacterSheetEditFactory(
options = run {
val current = sheet.magicSkills.firstOrNull { it.id == skill.id }
listOf(
- skillFactory.occupationOption(checked = current?.occupation ?: false),
- skillFactory.deleteOption { onDeleteSkill(skill.id) },
+ skillFieldFactory.occupationOption(checked = current?.occupation ?: false),
+ skillFieldFactory.deleteOption { onDeleteSkill(skill.id) },
)
},
)
@@ -448,15 +455,15 @@ class CharacterSheetEditFactory(
actions = sheet?.actions?.map { action ->
ActionFieldUio(
id = action.id,
- label = skillFactory.createWrapper(
+ label = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__actions__name_label)),
value = action.label,
),
- action = skillFactory.createWrapper(
+ action = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__actions__action_label)),
value = action.roll,
),
- option = skillFactory.deleteOption { onDeleteSkill(action.id) },
+ option = skillFieldFactory.deleteOption { onDeleteSkill(action.id) },
)
} ?: emptyList(),
)
@@ -474,15 +481,15 @@ class CharacterSheetEditFactory(
id = id,
label = label,
base = base,
- bonus = skillFactory.createWrapper(
+ bonus = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__bonus_label)),
value = skill?.bonus?.toString() ?: "",
),
- level = skillFactory.createWrapper(
+ level = skillFieldFactory.createWrapper(
label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__level_label)),
value = skill?.level?.toString() ?: "",
),
- option = skillFactory.occupationOption(skill?.occupation ?: false),
+ option = skillFieldFactory.occupationOption(skill?.occupation ?: false),
)
}
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditPage.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditPage.kt
index 86a84c0..98c50f6 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditPage.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/CharacterSheetEditPage.kt
@@ -273,6 +273,7 @@ fun CharacterSheetEdit(
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(space = 16.dp),
) {
Text(
modifier = Modifier.padding(vertical = 8.dp),
@@ -319,6 +320,7 @@ fun CharacterSheetEdit(
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
+ verticalArrangement = Arrangement.spacedBy(space = 16.dp),
) {
Text(
modifier = Modifier.padding(vertical = 8.dp),
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/common/SkillFieldFactory.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/common/SkillFieldFactory.kt
index 0d8b8c3..5efc012 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/common/SkillFieldFactory.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/common/SkillFieldFactory.kt
@@ -15,6 +15,7 @@ import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__de
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__occupation__label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__base_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__bonus_label
+import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__description_label
import lwacharactersheet.composeapp.generated.resources.character_sheet_edit__skills__level_label
import org.jetbrains.compose.resources.getString
import java.util.UUID
@@ -25,6 +26,7 @@ class SkillFieldFactory {
id: String = UUID.randomUUID().toString(),
label: String,
labelValue: String = "",
+ descriptionValue: String = "",
baseValue: String = "",
bonusValue: String = "",
levelValue: String = "",
@@ -37,6 +39,10 @@ class SkillFieldFactory {
label = mutableStateOf(label),
value = labelValue,
),
+ description = createWrapper(
+ label = mutableStateOf(getString(Res.string.character_sheet_edit__skills__description_label)),
+ value = descriptionValue,
+ ),
base = createWrapper(
label = derivedStateOf {
options
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/composable/SpecialSkillField.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/composable/SpecialSkillField.kt
index 7fb3abd..a63a756 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/composable/SpecialSkillField.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/composable/SpecialSkillField.kt
@@ -2,7 +2,9 @@ package com.pixelized.desktop.lwa.screen.characterSheet.edit.composable
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.width
import androidx.compose.material.DropdownMenu
import androidx.compose.material.Icon
@@ -14,7 +16,6 @@ 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.unit.dp
import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.option.DropDownMenuItemWrapper
@@ -26,6 +27,7 @@ import com.pixelized.desktop.lwa.screen.characterSheet.edit.composable.textfield
class SkillFieldUio(
val id: String,
val label: TextFieldWrapperUio,
+ val description: TextFieldWrapperUio,
val base: TextFieldWrapperUio,
val bonus: TextFieldWrapperUio,
val level: TextFieldWrapperUio,
@@ -41,25 +43,38 @@ fun SkillForm(
Row(
modifier = modifier,
- horizontalArrangement = Arrangement.spacedBy(space = 4.dp, alignment = Alignment.End),
- verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
) {
- TextFieldWrapper(
+ Column(
modifier = Modifier.weight(1f),
- wrapper = field.label,
- )
- TextFieldWrapper(
- modifier = Modifier.width(width = 96.dp),
- wrapper = field.base,
- )
- TextFieldWrapper(
- modifier = Modifier.width(width = 96.dp),
- wrapper = field.bonus,
- )
- TextFieldWrapper(
- modifier = Modifier.width(width = 96.dp),
- wrapper = field.level,
- )
+ verticalArrangement = Arrangement.spacedBy(space = 4.dp)
+ ) {
+ Row(
+ horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
+ ) {
+ TextFieldWrapper(
+ modifier = Modifier.weight(1f),
+ wrapper = field.label,
+ )
+ TextFieldWrapper(
+ modifier = Modifier.width(width = 96.dp),
+ wrapper = field.base,
+ )
+ TextFieldWrapper(
+ modifier = Modifier.width(width = 96.dp),
+ wrapper = field.bonus,
+ )
+ TextFieldWrapper(
+ modifier = Modifier.width(width = 96.dp),
+ wrapper = field.level,
+ )
+ }
+ TextFieldWrapper(
+ modifier = Modifier.fillMaxWidth(),
+ singleLine = false,
+ wrapper = field.description,
+ )
+ }
if (field.options.isNotEmpty()) {
Box {
IconButton(
diff --git a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/composable/textfield/FormWrapper.kt b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/composable/textfield/FormWrapper.kt
index b869d44..e55f2f1 100644
--- a/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/composable/textfield/FormWrapper.kt
+++ b/composeApp/src/commonMain/kotlin/com/pixelized/desktop/lwa/screen/characterSheet/edit/composable/textfield/FormWrapper.kt
@@ -15,6 +15,7 @@ import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.utils.rememberKeyboardActions
+import kotlin.math.sin
@Stable
data class TextFieldWrapperUio(
@@ -28,13 +29,19 @@ data class TextFieldWrapperUio(
@Composable
fun TextFieldWrapper(
modifier: Modifier = Modifier,
+ singleLine: Boolean = true,
wrapper: TextFieldWrapperUio,
) {
val colorScheme = MaterialTheme.colors
val focus = LocalFocusManager.current
+ val localModifier = if (singleLine) {
+ Modifier.height(height = 56.dp)
+ } else {
+ Modifier
+ }
TextField(
- modifier = Modifier.height(height = 56.dp).then(other = modifier),
+ modifier = localModifier.then(other = modifier),
colors = TextFieldDefaults.textFieldColors(
backgroundColor = remember(wrapper.enable) {
when (wrapper.enable) {
@@ -47,7 +54,7 @@ fun TextFieldWrapper(
focus.moveFocus(FocusDirection.Next)
},
enabled = wrapper.enable,
- singleLine = true,
+ singleLine = singleLine,
placeholder = wrapper.placeholder.value?.let {
{
Text(