Add client inventory sheet management.

This commit is contained in:
Thomas Andres Gomez 2025-04-17 14:29:22 +02:00
parent 8982bab22d
commit 05a376aea8
10 changed files with 325 additions and 118 deletions

View file

@ -184,6 +184,8 @@
<string name="character_sheet__delete_dialog__title">Supprimer la feuille de personnage</string> <string name="character_sheet__delete_dialog__title">Supprimer la feuille de personnage</string>
<string name="character_sheet__delete_dialog__description">Êtes-vous sûr de vouloir supprimer "%1$s" ?</string> <string name="character_sheet__delete_dialog__description">Êtes-vous sûr de vouloir supprimer "%1$s" ?</string>
<string name="character__inventory__add_to_inventory__action">Ajouter un objet</string>
<string name="character__inventory__filter_inventory__label">Filtrer l'inventaire</string>
<string name="character__inventory__add_to_purse__title">Ajouter à la bourse</string> <string name="character__inventory__add_to_purse__title">Ajouter à la bourse</string>
<string name="character__inventory__remove_from_purse__title">Retirer de la bourse</string> <string name="character__inventory__remove_from_purse__title">Retirer de la bourse</string>

View file

@ -1,29 +1,26 @@
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.MaterialTheme import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.runtime.State import androidx.compose.runtime.State
@ -31,45 +28,57 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.LocalBlurController import com.pixelized.desktop.lwa.LocalBlurController
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialog import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialog
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogViewModel import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogViewModel
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextField
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.InventoryItem import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.InventoryItem
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.InventoryItemUio import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.InventoryItemUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.InventoryPurse
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.PurseUio
import com.pixelized.desktop.lwa.ui.theme.color.component.LwaButtonColors
import com.pixelized.desktop.lwa.ui.theme.color.component.LwaTextFieldColors
import com.pixelized.desktop.lwa.ui.theme.lwa import com.pixelized.desktop.lwa.ui.theme.lwa
import com.pixelized.desktop.lwa.utils.extention.plus
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import lwacharactersheet.composeapp.generated.resources.Res import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.ic_copper_32px import lwacharactersheet.composeapp.generated.resources.character__inventory__add_to_inventory__action
import lwacharactersheet.composeapp.generated.resources.ic_gold_32px import lwacharactersheet.composeapp.generated.resources.ic_cancel_24dp
import lwacharactersheet.composeapp.generated.resources.ic_silver_32px
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
import org.koin.compose.viewmodel.koinViewModel import org.koin.compose.viewmodel.koinViewModel
@Stable @Stable
data class CharacterDetailInventoryUio( data class CharacterDetailInventoryUio(
val characterSheetId: String, val characterSheetId: String,
val filter: LwaTextFieldUio,
val purse: PurseUio, val purse: PurseUio,
val items: List<InventoryItemUio>, val items: List<InventoryItemUio>,
) { )
@Stable
data class PurseUio(
val gold: Int,
val silver: Int,
val copper: Int,
)
}
@Stable
object CharacterDetailInventoryDefault { object CharacterDetailInventoryDefault {
val padding = PaddingValues(horizontal = 16.dp, vertical = 8.dp) @Stable
val padding = PaddingValues(
start = 16.dp,
end = 16.dp,
top = 8.dp,
bottom = 8.dp,
)
@Stable
val spacing: Dp = 8.dp
} }
@Composable @Composable
fun CharacterDetailInventory( fun CharacterDetailInventory(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
paddings: PaddingValues = CharacterDetailInventoryDefault.padding, paddings: PaddingValues = CharacterDetailInventoryDefault.padding,
spacing: Dp = CharacterDetailInventoryDefault.spacing,
purseViewModel: PurseDialogViewModel = koinViewModel(), purseViewModel: PurseDialogViewModel = koinViewModel(),
inventory: State<CharacterDetailInventoryUio?>, inventory: State<CharacterDetailInventoryUio?>,
) { ) {
@ -82,6 +91,7 @@ fun CharacterDetailInventory(
else -> CharacterDetailInventoryContent( else -> CharacterDetailInventoryContent(
modifier = modifier, modifier = modifier,
paddings = paddings, paddings = paddings,
spacing = spacing,
inventory = unWrap, inventory = unWrap,
onPurse = { onPurse = {
blur.show() blur.show()
@ -118,119 +128,95 @@ fun CharacterDetailInventory(
private fun CharacterDetailInventoryContent( private fun CharacterDetailInventoryContent(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
paddings: PaddingValues, paddings: PaddingValues,
spacing: Dp,
inventory: CharacterDetailInventoryUio, inventory: CharacterDetailInventoryUio,
onPurse: (String) -> Unit, onPurse: (String) -> Unit,
) { ) {
Column( Box(
modifier = modifier, modifier = modifier,
) { ) {
LazyColumn( LazyColumn(
modifier = Modifier.weight(1f), modifier = Modifier.matchParentSize(),
contentPadding = paddings, contentPadding = paddings + PaddingValues(bottom = 56.dp),
verticalArrangement = Arrangement.spacedBy(space = spacing),
) { ) {
item(
key = "purse",
) {
Row(
modifier = Modifier
.animateItem()
.fillMaxWidth(),
verticalAlignment = Alignment.Bottom,
horizontalArrangement = Arrangement.spacedBy(space = spacing),
) {
InventoryPurse(
modifier = Modifier.weight(weight = 1f),
purse = inventory.purse,
onPurse = { onPurse(inventory.characterSheetId) },
)
LwaTextField(
modifier = Modifier.weight(weight = 1f),
colors = LwaTextFieldColors(
backgroundColor = MaterialTheme.lwa.colorScheme.elevated.base2dp,
),
field = inventory.filter,
trailingIcon = {
val value = inventory.filter.valueFlow.collectAsState()
AnimatedVisibility(
visible = value.value.isNotBlank(),
enter = fadeIn(),
exit = fadeOut(),
) {
IconButton(
onClick = { inventory.filter.onValueChange.invoke("") },
) {
Icon(
painter = painterResource(Res.drawable.ic_cancel_24dp),
tint = MaterialTheme.lwa.colorScheme.base.primary,
contentDescription = null,
)
}
}
}
)
}
}
items( items(
items = inventory.items, items = inventory.items,
key = { it.inventoryId }, key = { it.inventoryId },
) { ) {
InventoryItem( InventoryItem(
modifier = Modifier.fillMaxWidth(), modifier = Modifier
.animateItem()
.fillMaxWidth(),
item = it, item = it,
onClick = { }, onClick = { },
) )
} }
} }
Purse(
modifier = Modifier.fillMaxWidth(),
paddings = paddings,
purse = inventory.purse,
onPurse = { onPurse(inventory.characterSheetId) },
)
}
}
@Composable
private fun Purse(
modifier: Modifier = Modifier,
paddings: PaddingValues,
purse: CharacterDetailInventoryUio.PurseUio,
onPurse: () -> Unit,
) {
Row(
modifier = Modifier
.background(color = MaterialTheme.lwa.colorScheme.elevated.base2dp)
.then(other = modifier),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End,
) {
Row( Row(
modifier = Modifier modifier = Modifier
.clickable { onPurse() } .align(alignment = Alignment.BottomEnd)
.padding(paddingValues = paddings), .padding(paddingValues = paddings),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp), horizontalArrangement = Arrangement.SpaceBetween,
) { ) {
Row(verticalAlignment = Alignment.Bottom) { Button(
Image( colors = LwaButtonColors(),
painter = painterResource(Res.drawable.ic_gold_32px), elevation = ButtonDefaults.elevation(4.dp),
modifier = Modifier.padding(bottom = 2.dp).size(size = 16.dp), shape = CircleShape,
onClick = { },
) {
Text(
modifier = Modifier.padding(end = 4.dp),
text = stringResource(Res.string.character__inventory__add_to_inventory__action),
)
Icon(
imageVector = Icons.Default.Add,
contentDescription = null, contentDescription = null,
) )
AnimatedContent(
targetState = purse.gold,
transitionSpec = coinTransitionSpec(),
) {
Text(
style = MaterialTheme.lwa.typography.base.body1,
fontWeight = FontWeight.Bold,
text = "$it",
)
}
}
Row(verticalAlignment = Alignment.Bottom) {
Image(
painter = painterResource(Res.drawable.ic_silver_32px),
modifier = Modifier.padding(bottom = 2.dp).size(size = 16.dp),
contentDescription = null,
)
AnimatedContent(
targetState = purse.silver,
transitionSpec = coinTransitionSpec(),
) {
Text(
style = MaterialTheme.lwa.typography.base.body1,
fontWeight = FontWeight.Bold,
text = "$it",
)
}
}
Row(verticalAlignment = Alignment.Bottom) {
Image(
painter = painterResource(Res.drawable.ic_copper_32px),
modifier = Modifier.padding(bottom = 2.dp).size(size = 16.dp),
contentDescription = null,
)
AnimatedContent(
targetState = purse.copper,
transitionSpec = coinTransitionSpec(),
) {
Text(
style = MaterialTheme.lwa.typography.base.body1,
fontWeight = FontWeight.Bold,
text = "$it",
)
}
} }
} }
} }
}
@Composable
@Stable
private fun coinTransitionSpec(): AnimatedContentTransitionScope<Int>.() -> ContentTransform = {
val enter = fadeIn() + slideInVertically { -16 }
val exit = fadeOut() + slideOutVertically { 16 }
enter togetherWith exit using SizeTransform(clip = false)
} }

View file

@ -2,35 +2,55 @@ package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory
import com.pixelized.desktop.lwa.repository.inventory.InventoryRepository import com.pixelized.desktop.lwa.repository.inventory.InventoryRepository
import com.pixelized.desktop.lwa.repository.item.ItemRepository import com.pixelized.desktop.lwa.repository.item.ItemRepository
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.InventoryItemUio import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.InventoryItemUio
import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item.PurseUio
import com.pixelized.desktop.lwa.utils.extention.unAccent
import com.pixelized.shared.lwa.model.inventory.Inventory import com.pixelized.shared.lwa.model.inventory.Inventory
import com.pixelized.shared.lwa.model.item.Item import com.pixelized.shared.lwa.model.item.Item
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.character__inventory__filter_inventory__label
import org.jetbrains.compose.resources.getString
import java.text.Collator
class CharacterDetailInventoryFactory( class CharacterDetailInventoryFactory(
private val inventoryRepository: InventoryRepository, private val inventoryRepository: InventoryRepository,
private val itemRepository: ItemRepository, private val itemRepository: ItemRepository,
) { ) {
fun convertToCharacterInventoryUioFlow( suspend fun convertToCharacterInventoryUioFlow(
characterSheetId: String, characterSheetId: String,
scope: CoroutineScope, scope: CoroutineScope,
started: SharingStarted = SharingStarted.Eagerly, started: SharingStarted = SharingStarted.Eagerly,
initialValue: () -> CharacterDetailInventoryUio?, initialValue: () -> CharacterDetailInventoryUio?,
): StateFlow<CharacterDetailInventoryUio?> { ): StateFlow<CharacterDetailInventoryUio?> {
val filterFlow = MutableStateFlow("")
val filterField = LwaTextFieldUio(
enable = true,
isError = MutableStateFlow(false),
valueFlow = filterFlow,
label = getString(Res.string.character__inventory__filter_inventory__label),
placeHolder = null,
onValueChange = { filterFlow.value = it },
)
return combine( return combine(
inventoryRepository.inventoryFlow(characterSheetId = characterSheetId), inventoryRepository.inventoryFlow(characterSheetId = characterSheetId),
itemRepository.itemFlow, itemRepository.itemFlow,
) { inventory, items -> filterFlow.map { it.unAccent() },
) { inventory, items, filter ->
convertToCharacterInventoryUio( convertToCharacterInventoryUio(
characterSheetId = characterSheetId, characterSheetId = characterSheetId,
filter = filterField,
purse = inventory?.purse, purse = inventory?.purse,
inventory = inventory?.items, inventory = inventory?.items,
items = items, items = items.filterValues { it.metadata.name.unAccent().contains(filter, true) },
) )
}.stateIn( }.stateIn(
scope = scope, scope = scope,
@ -41,6 +61,7 @@ class CharacterDetailInventoryFactory(
private suspend fun convertToCharacterInventoryUio( private suspend fun convertToCharacterInventoryUio(
characterSheetId: String?, characterSheetId: String?,
filter: LwaTextFieldUio,
purse: Inventory.Purse?, purse: Inventory.Purse?,
inventory: List<Inventory.Item>?, inventory: List<Inventory.Item>?,
items: Map<String, Item>, items: Map<String, Item>,
@ -49,19 +70,22 @@ class CharacterDetailInventoryFactory(
return CharacterDetailInventoryUio( return CharacterDetailInventoryUio(
characterSheetId = characterSheetId, characterSheetId = characterSheetId,
purse = CharacterDetailInventoryUio.PurseUio( purse = PurseUio(
gold = purse?.gold ?: 0, gold = purse?.gold ?: 0,
silver = purse?.silver ?: 0, silver = purse?.silver ?: 0,
copper = purse?.copper ?: 0, copper = purse?.copper ?: 0,
), ),
filter = filter,
items = inventory items = inventory
?.mapNotNull { ?.mapNotNull {
val label = items[it.itemId]?.metadata?.name ?: return@mapNotNull null val label = items[it.itemId]?.metadata?.name ?: return@mapNotNull null
InventoryItemUio( InventoryItemUio(
inventoryId = it.inventoryId, inventoryId = it.inventoryId,
label = label, label = label,
equipped = it.equipped,
) )
} }
?.sortedWith(compareBy(Collator.getInstance()) { it.label })
?: emptyList() ?: emptyList()
) )
} }

View file

@ -12,13 +12,16 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.ui.theme.lwa import com.pixelized.desktop.lwa.ui.theme.lwa
import com.pixelized.desktop.lwa.utils.extention.ribbon
@Stable @Stable
data class InventoryItemUio( data class InventoryItemUio(
val inventoryId: String, val inventoryId: String,
val label: String, val label: String,
val equipped: Boolean,
) )
@Stable @Stable
@ -36,9 +39,15 @@ fun InventoryItem(
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
.clip(shape = MaterialTheme.lwa.shapes.gameMaster) .clip(shape = MaterialTheme.lwa.shapes.item)
.clickable(onClick = onClick) .clickable(onClick = onClick)
.background(color = MaterialTheme.lwa.colorScheme.elevated.base2dp) .background(color = MaterialTheme.lwa.colorScheme.elevated.base2dp)
.ribbon(
color = when (item.equipped) {
true -> MaterialTheme.lwa.colorScheme.base.primary
else -> Color.Transparent
}
)
.minimumInteractiveComponentSize() .minimumInteractiveComponentSize()
.padding(paddingValues = padding) .padding(paddingValues = padding)
.then(other = modifier), .then(other = modifier),

View file

@ -0,0 +1,130 @@
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedContentTransitionScope
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.SizeTransform
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.pixelized.desktop.lwa.ui.theme.lwa
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.ic_copper_32px
import lwacharactersheet.composeapp.generated.resources.ic_gold_32px
import lwacharactersheet.composeapp.generated.resources.ic_silver_32px
import org.jetbrains.compose.resources.painterResource
@Stable
data class PurseUio(
val gold: Int,
val silver: Int,
val copper: Int,
)
@Stable
object InventoryPurseDefault {
@Stable
val paddings = PaddingValues(horizontal = 0.dp, vertical = 4.dp)
}
@Composable
fun InventoryPurse(
modifier: Modifier = Modifier,
paddings: PaddingValues = InventoryPurseDefault.paddings,
purse: PurseUio,
onPurse: () -> Unit,
) {
Row(
modifier = modifier,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Start,
) {
Row(
modifier = Modifier
.clip(shape = MaterialTheme.lwa.shapes.item)
.clickable { onPurse() }
.padding(paddingValues = paddings),
horizontalArrangement = Arrangement.spacedBy(space = 8.dp),
) {
Row(verticalAlignment = Alignment.Bottom) {
Image(
painter = painterResource(Res.drawable.ic_gold_32px),
modifier = Modifier.padding(bottom = 2.dp).size(size = 16.dp),
contentDescription = null,
)
AnimatedContent(
targetState = purse.gold,
transitionSpec = coinTransitionSpec(),
) {
Text(
style = MaterialTheme.lwa.typography.base.body1,
fontWeight = FontWeight.Bold,
text = "$it",
)
}
}
Row(verticalAlignment = Alignment.Bottom) {
Image(
painter = painterResource(Res.drawable.ic_silver_32px),
modifier = Modifier.padding(bottom = 2.dp).size(size = 16.dp),
contentDescription = null,
)
AnimatedContent(
targetState = purse.silver,
transitionSpec = coinTransitionSpec(),
) {
Text(
style = MaterialTheme.lwa.typography.base.body1,
fontWeight = FontWeight.Bold,
text = "$it",
)
}
}
Row(verticalAlignment = Alignment.Bottom) {
Image(
painter = painterResource(Res.drawable.ic_copper_32px),
modifier = Modifier.padding(bottom = 2.dp).size(size = 16.dp),
contentDescription = null,
)
AnimatedContent(
targetState = purse.copper,
transitionSpec = coinTransitionSpec(),
) {
Text(
style = MaterialTheme.lwa.typography.base.body1,
fontWeight = FontWeight.Bold,
text = "$it",
)
}
}
}
}
}
@Composable
@Stable
private fun coinTransitionSpec(): AnimatedContentTransitionScope<Int>.() -> ContentTransform = {
val enter = fadeIn() + slideInHorizontally { -16 }
val exit = fadeOut() + slideOutHorizontally { 16 }
enter togetherWith exit using SizeTransform(clip = false)
}

View file

@ -0,0 +1,29 @@
package com.pixelized.desktop.lwa.utils.extention
import androidx.compose.animation.animateColorAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
fun Modifier.ribbon(
width: Dp = 4.dp,
color: Color,
): Modifier = composed {
val animatedColor = animateColorAsState(
targetValue = color,
)
return@composed drawWithContent {
drawContent()
drawRect(
color = animatedColor.value,
size = Size(
width = width.toPx(),
height = size.height,
)
)
}
}

View file

@ -0,0 +1,23 @@
package com.pixelized.desktop.lwa.utils.extention
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.calculateStartPadding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalLayoutDirection
@Stable
@Composable
operator fun PaddingValues.plus(other: PaddingValues): PaddingValues {
val direction = LocalLayoutDirection.current
return remember(this, other, direction) {
PaddingValues(
start = calculateStartPadding(direction) + other.calculateStartPadding(direction),
top = calculateTopPadding() + other.calculateTopPadding(),
end = calculateEndPadding(direction) + other.calculateEndPadding(direction),
bottom = calculateBottomPadding() + other.calculateBottomPadding(),
)
}
}

View file

@ -15,6 +15,7 @@ data class Inventory(
val inventoryId: String, val inventoryId: String,
val itemId: String, val itemId: String,
val count: Int, val count: Int,
val equipped: Boolean,
) )
companion object { companion object {

View file

@ -21,5 +21,6 @@ data class InventoryJsonV1(
val inventoryId: String, val inventoryId: String,
val itemId: String, val itemId: String,
val count: Int, val count: Int,
val equipped: Boolean?,
) )
} }

View file

@ -18,6 +18,7 @@ class InventoryJsonFactoryV1 {
inventoryId = it.inventoryId, inventoryId = it.inventoryId,
itemId = it.itemId, itemId = it.itemId,
count = it.count, count = it.count,
equipped = it.equipped ?: false,
) )
}, },
) )
@ -36,6 +37,7 @@ class InventoryJsonFactoryV1 {
inventoryId = it.inventoryId, inventoryId = it.inventoryId,
itemId = it.itemId, itemId = it.itemId,
count = it.count, count = it.count,
equipped = it.equipped,
) )
}, },
) )