Add the icon to the alteration edit page.

This commit is contained in:
Thomas Andres Gomez 2025-05-08 14:38:24 +02:00
parent e81b66e725
commit 05a6b496cb
10 changed files with 63 additions and 22 deletions

View file

@ -305,6 +305,7 @@
<string name="game_master__alteration__edit_id">Identifiant de l'altération</string> <string name="game_master__alteration__edit_id">Identifiant de l'altération</string>
<string name="game_master__alteration__edit_label">Nom</string> <string name="game_master__alteration__edit_label">Nom</string>
<string name="game_master__alteration__edit_description">Description</string> <string name="game_master__alteration__edit_description">Description</string>
<string name="game_master__alteration__edit_icon">Icône</string>
<string name="game_master__alteration__edit_tags">Tags</string> <string name="game_master__alteration__edit_tags">Tags</string>
<string name="game_master__alteration__edit_field_id">Identifiant du champ</string> <string name="game_master__alteration__edit_field_id">Identifiant du champ</string>
<string name="game_master__alteration__edit_field_expression">Expression</string> <string name="game_master__alteration__edit_field_expression">Expression</string>

View file

@ -9,6 +9,8 @@ import com.pixelized.shared.lwa.model.alteration.Alteration
import com.pixelized.shared.lwa.model.alteration.FieldAlteration import com.pixelized.shared.lwa.model.alteration.FieldAlteration
import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet import com.pixelized.shared.lwa.model.characterSheet.CharacterSheet
private const val DEFAULT_ICON = "https://bg3.wiki/w/images/a/af/Arcana_Icon.png"
class CharacterRibbonFactory( class CharacterRibbonFactory(
private val alteredCharacterSheetFactory: AlteredCharacterSheetFactory, private val alteredCharacterSheetFactory: AlteredCharacterSheetFactory,
) { ) {
@ -29,7 +31,7 @@ class CharacterRibbonFactory(
val status = alterations.map { alteration -> val status = alterations.map { alteration ->
CharacterRibbonAlterationUio( CharacterRibbonAlterationUio(
icon = "https://bg3.wiki/w/images/2/2d/Map_Tutorial_Map_Icon.png", icon = alteration.metadata.icon ?: DEFAULT_ICON,
tooltips = BasicTooltipUio( tooltips = BasicTooltipUio(
title = alteration.metadata.name, title = alteration.metadata.name,
description = alteration.metadata.description, description = alteration.metadata.description,

View file

@ -1,5 +1,10 @@
package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.common package com.pixelized.desktop.lwa.ui.screen.campaign.player.ribbon.common
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.TooltipPlacement import androidx.compose.foundation.TooltipPlacement
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@ -46,6 +51,7 @@ fun CharacterRibbonAlteration(
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
.animateContentSize()
.size(size = size) .size(size = size)
.then(other = modifier), .then(other = modifier),
horizontalArrangement = Arrangement.spacedBy(space = 4.dp), horizontalArrangement = Arrangement.spacedBy(space = 4.dp),
@ -55,6 +61,7 @@ fun CharacterRibbonAlteration(
) { ) {
status.forEach { columns -> status.forEach { columns ->
Column( Column(
modifier = Modifier.animateContentSize(),
verticalArrangement = Arrangement.spacedBy(space = 2.dp), verticalArrangement = Arrangement.spacedBy(space = 2.dp),
) { ) {
columns.forEach { columns.forEach {
@ -63,26 +70,31 @@ fun CharacterRibbonAlteration(
tooltip = it.tooltips, tooltip = it.tooltips,
tooltipPlacement = remember(currentDirection) { tooltipPlacement = remember(currentDirection) {
TooltipPlacement.ComponentRect( TooltipPlacement.ComponentRect(
anchor = when(direction) { anchor = when (direction) {
LayoutDirection.Ltr -> Alignment.TopStart LayoutDirection.Ltr -> Alignment.TopStart
LayoutDirection.Rtl -> Alignment.TopEnd LayoutDirection.Rtl -> Alignment.TopEnd
}, },
alignment = when(direction) { alignment = when (direction) {
LayoutDirection.Ltr -> Alignment.BottomEnd LayoutDirection.Ltr -> Alignment.BottomEnd
LayoutDirection.Rtl -> Alignment.BottomStart LayoutDirection.Rtl -> Alignment.BottomStart
}, },
) )
}, },
content = { content = {
AsyncImage( AnimatedContent(
modifier = Modifier.size(24.dp), targetState = it.icon,
model = ImageRequest.Builder(context = PlatformContext.INSTANCE) transitionSpec = { fadeIn() togetherWith fadeOut() },
.data(data = it.icon) ) { icon ->
.size(size = 48) AsyncImage(
.build(), modifier = Modifier.size(24.dp),
filterQuality = FilterQuality.High, model = ImageRequest.Builder(context = PlatformContext.INSTANCE)
contentDescription = null, .data(data = icon)
) .size(size = 48)
.build(),
filterQuality = FilterQuality.High,
contentDescription = null,
)
}
} }
) )
} }

View file

@ -11,6 +11,7 @@ import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_description import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_description
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_field_expression import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_field_expression
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_field_id import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_field_id
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_icon
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_id import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_id
import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_label import lwacharactersheet.composeapp.generated.resources.game_master__alteration__edit_label
import org.jetbrains.compose.resources.getString import org.jetbrains.compose.resources.getString
@ -36,6 +37,10 @@ class GMAlterationEditFactory(
label = getString(Res.string.game_master__alteration__edit_description), label = getString(Res.string.game_master__alteration__edit_description),
value = alteration?.metadata?.description ?: "", value = alteration?.metadata?.description ?: "",
) )
val iconFlow = createLwaTextFieldFlow(
label = getString(Res.string.game_master__alteration__edit_icon),
value = alteration?.metadata?.icon ?: "",
)
val tagFlow = MutableStateFlow( val tagFlow = MutableStateFlow(
tagFactory.convertToGMTagItemUio( tagFactory.convertToGMTagItemUio(
tags = tags, tags = tags,
@ -48,6 +53,7 @@ class GMAlterationEditFactory(
idFlow = idFlow, idFlow = idFlow,
labelFlow = labelFlow, labelFlow = labelFlow,
descriptionFlow = descriptionFlow, descriptionFlow = descriptionFlow,
iconFlow = iconFlow,
tagFlow = tagFlow, tagFlow = tagFlow,
fieldsFlow = fieldsFlow, fieldsFlow = fieldsFlow,
) )
@ -61,6 +67,7 @@ class GMAlterationEditFactory(
id = form.idFlow.createLwaTextField(enable = originId == null), id = form.idFlow.createLwaTextField(enable = originId == null),
label = form.labelFlow.createLwaTextField(), label = form.labelFlow.createLwaTextField(),
description = form.descriptionFlow.createLwaTextField(), description = form.descriptionFlow.createLwaTextField(),
icon = form.iconFlow.createLwaTextField(),
tags = form.tagFlow, tags = form.tagFlow,
fields = form.fieldsFlow, fields = form.fieldsFlow,
) )
@ -84,21 +91,22 @@ class GMAlterationEditFactory(
) )
} }
suspend fun createAlteration( fun createAlteration(
form: GMAlterationEditPageUio?, form: GMAlterationEditViewModel.GMAlterationEditForm?,
): Alteration? { ): Alteration? {
if (form == null) return null if (form == null) return null
return Alteration( return Alteration(
id = form.id.valueFlow.value, id = form.idFlow.valueFlow.value,
metadata = Alteration.MetaData( metadata = Alteration.MetaData(
name = form.label.valueFlow.value, name = form.labelFlow.valueFlow.value,
description = form.description.valueFlow.value, description = form.descriptionFlow.valueFlow.value,
icon = form.iconFlow.valueFlow.value.takeIf { it.isNotBlank() },
), ),
tags = form.tags.value tags = form.tagFlow.value
.filter { it.highlight } .filter { it.highlight }
.map { it.id }, .map { it.id },
fields = form.fields.value.mapNotNull { field -> fields = form.fieldsFlow.value.mapNotNull { field ->
expressionParser.parse(input = field.expression.valueFlow.value)?.let { expressionParser.parse(input = field.expression.valueFlow.value)?.let {
Alteration.Field( Alteration.Field(
fieldId = field.id.valueFlow.value, fieldId = field.id.valueFlow.value,

View file

@ -85,6 +85,7 @@ data class GMAlterationEditPageUio(
val id: LwaTextFieldUio, val id: LwaTextFieldUio,
val label: LwaTextFieldUio, val label: LwaTextFieldUio,
val description: LwaTextFieldUio, val description: LwaTextFieldUio,
val icon: LwaTextFieldUio,
val tags: MutableStateFlow<List<GMTagUio>>, val tags: MutableStateFlow<List<GMTagUio>>,
val fields: MutableStateFlow<List<SkillUio>>, val fields: MutableStateFlow<List<SkillUio>>,
) { ) {
@ -265,6 +266,16 @@ private fun GMAlterationEditContent(
singleLine = false, singleLine = false,
) )
} }
item(key = "Icon") {
LwaTextField(
modifier = Modifier
.animateItem()
.fillMaxWidth()
.padding(paddingValues = horizontalPadding),
field = it.icon,
singleLine = false,
)
}
item(key = "Tags") { item(key = "Tags") {
LazyRow( LazyRow(
modifier = Modifier.draggable( modifier = Modifier.draggable(

View file

@ -55,7 +55,7 @@ class GMAlterationEditViewModel(
} }
suspend fun save(): Boolean { suspend fun save(): Boolean {
val edited = factory.createAlteration(form = form.value) ?: return false val edited = factory.createAlteration(form = _form.value) ?: return false
try { try {
alterationRepository.updateAlteration( alterationRepository.updateAlteration(
@ -108,6 +108,7 @@ class GMAlterationEditViewModel(
val idFlow: LwaTextFieldFlow, val idFlow: LwaTextFieldFlow,
val labelFlow: LwaTextFieldFlow, val labelFlow: LwaTextFieldFlow,
val descriptionFlow: LwaTextFieldFlow, val descriptionFlow: LwaTextFieldFlow,
val iconFlow: LwaTextFieldFlow,
val tagFlow: MutableStateFlow<List<GMTagUio>>, val tagFlow: MutableStateFlow<List<GMTagUio>>,
val fieldsFlow: MutableStateFlow<List<GMAlterationEditPageUio.SkillUio>>, val fieldsFlow: MutableStateFlow<List<GMAlterationEditPageUio.SkillUio>>,
) )

View file

@ -61,7 +61,8 @@ class LevelUpFactory(
alterationId = CharacterSheet.CharacteristicId.LVL, alterationId = CharacterSheet.CharacteristicId.LVL,
metadata = Alteration.MetaData( metadata = Alteration.MetaData(
name = "LevelUp-${CharacterSheet.CharacteristicId.LVL}", name = "LevelUp-${CharacterSheet.CharacteristicId.LVL}",
description = "Fake alteration for a levelUp simulation. Alter the ${CharacterSheet.CharacteristicId.LVL} stat." description = "Fake alteration for a levelUp simulation. Alter the ${CharacterSheet.CharacteristicId.LVL} stat.",
icon = null,
), ),
expression = Expression.Flat(1), expression = Expression.Flat(1),
) )
@ -78,7 +79,8 @@ class LevelUpFactory(
alterationId = it, alterationId = it,
metadata = Alteration.MetaData( metadata = Alteration.MetaData(
name = "LevelUp-$it", name = "LevelUp-$it",
description = "Fake alteration for a levelUp simulation. Alter the $it stat." description = "Fake alteration for a levelUp simulation. Alter the $it stat.",
icon = null,
), ),
expression = Expression.Flat(1), expression = Expression.Flat(1),
) )

View file

@ -9,6 +9,7 @@ data class Alteration(
val fields: List<Field>, val fields: List<Field>,
) { ) {
data class MetaData( data class MetaData(
val icon: String?,
val name: String, val name: String,
val description: String, val description: String,
) )

View file

@ -32,6 +32,7 @@ class AlterationJsonFactory(
return Alteration.MetaData( return Alteration.MetaData(
name = json.name, name = json.name,
description = json.description, description = json.description,
icon = json.icon,
) )
} }
@ -61,6 +62,7 @@ class AlterationJsonFactory(
return AlterationJsonV1.AlterationMetadataJsonV1( return AlterationJsonV1.AlterationMetadataJsonV1(
name = data.name, name = data.name,
description = data.description, description = data.description,
icon = data.icon,
) )
} }

View file

@ -20,5 +20,6 @@ data class AlterationJsonV1(
data class AlterationMetadataJsonV1( data class AlterationMetadataJsonV1(
val name: String, val name: String,
val description: String, val description: String,
val icon: String?,
) )
} }