Change the UI of the InventoryItem.

This commit is contained in:
Thomas Andres Gomez 2025-05-06 14:25:39 +02:00
parent fa49d8ed22
commit 898a8862db
7 changed files with 169 additions and 46 deletions

View file

@ -32,6 +32,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
@ -95,6 +96,7 @@ fun CharacterDetailInventory(
inventory: State<CharacterDetailInventoryUio?>,
) {
val blur = LocalBlurController.current
val focus = LocalFocusManager.current
val scope = rememberCoroutineScope()
when (val unWrap = inventory.value) {
@ -110,6 +112,7 @@ fun CharacterDetailInventory(
purseViewModel.showPurseDialog(
characterSheetId = it,
)
focus.clearFocus(force = true)
},
onItem = { item ->
blur.show()
@ -118,12 +121,14 @@ fun CharacterDetailInventory(
inventoryId = item.inventoryId,
itemId = item.itemId,
)
focus.clearFocus(force = true)
},
onAddItem = {
blur.show()
inventoryDialogViewModel.showInventoryDialog(
characterSheetId = it,
)
focus.clearFocus(force = true)
},
onConsume = {
scope.launch {
@ -132,6 +137,7 @@ fun CharacterDetailInventory(
inventoryId = it.inventoryId,
)
}
focus.clearFocus(force = true)
},
onEquip = {
scope.launch {
@ -140,6 +146,7 @@ fun CharacterDetailInventory(
inventoryId = it.inventoryId,
)
}
focus.clearFocus(force = true)
}
)
}

View file

@ -22,6 +22,7 @@ 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 org.koin.core.component.getScopeName
import java.text.Collator
import java.text.DecimalFormat
@ -96,6 +97,7 @@ class CharacterDetailInventoryFactory(
characterSheetId = characterSheetId,
inventoryId = it.inventoryId,
itemId = it.itemId,
icon = item.metadata.thumbnail,
label = item.metadata.label,
count = decimalFormat.format(it.count),
equipped = it.equipped,
@ -111,6 +113,7 @@ class CharacterDetailInventoryFactory(
)
}
?.sortedWith(compareBy(Collator.getInstance()) { it.label })
?.sortedByDescending { it.equipped }
?: emptyList()
)
}

View file

@ -4,8 +4,8 @@ import androidx.compose.animation.AnimatedContent
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.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
@ -15,11 +15,14 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.calculateEndPadding
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
@ -27,22 +30,24 @@ import androidx.compose.material.TextButton
import androidx.compose.material.minimumInteractiveComponentSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.FilterQuality
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpSize
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
import com.pixelized.desktop.lwa.ui.composable.image.DesaturatedAsyncImage
import com.pixelized.desktop.lwa.ui.composable.tooltip.TooltipLayout2
import com.pixelized.desktop.lwa.ui.theme.lwa
import com.pixelized.desktop.lwa.utils.extention.calculatePaddings
import com.pixelized.desktop.lwa.utils.extention.ribbon
import com.pixelized.desktop.lwa.utils.rememberSaturationFilter
import lwacharactersheet.composeapp.generated.resources.Res
@ -56,6 +61,7 @@ data class InventoryItemUio(
val characterSheetId: String,
val inventoryId: String,
val itemId: String,
val icon: String?,
val label: String,
val count: String,
val equipped: Boolean,
@ -74,11 +80,13 @@ data class InventoryItemUio(
@Stable
object GMCharacterPreviewDefault {
@Stable
val paddings = PaddingValues(horizontal = 16.dp)
val paddings = PaddingValues(horizontal = 8.dp)
@Stable
val toolTipPaddings = PaddingValues(all = 16.dp)
val icon: DpSize = DpSize(width = 32.dp, height = 32.dp)
@Stable
val spacing: Dp = 8.dp
}
@ -90,17 +98,14 @@ fun InventoryItem(
padding: PaddingValues = GMCharacterPreviewDefault.paddings,
toolTipPaddings: PaddingValues = GMCharacterPreviewDefault.toolTipPaddings,
spacing: Dp = GMCharacterPreviewDefault.spacing,
icon: DpSize = GMCharacterPreviewDefault.icon,
item: InventoryItemUio,
onClick: () -> Unit,
onConsume: () -> Unit,
onEquip: () -> Unit,
) {
val layoutDirection = LocalLayoutDirection.current
val toolTop = remember(toolTipPaddings) { toolTipPaddings.calculateTopPadding() }
val toolEnd = remember(toolTipPaddings, layoutDirection) {
toolTipPaddings.calculateEndPadding(layoutDirection)
}
val end = remember(padding, layoutDirection) { padding.calculateEndPadding(layoutDirection) }
val (start, top, end, bottom) = padding.calculatePaddings()
val (_, toolTop, toolEnd, _) = toolTipPaddings.calculatePaddings()
TooltipLayout2(
modifier = modifier,
@ -159,44 +164,84 @@ fun InventoryItem(
)
.minimumInteractiveComponentSize()
.fillMaxWidth()
.padding(paddingValues = padding)
.padding(start = start, end = end)
.then(other = modifier),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Row(
modifier = Modifier.weight(weight = 1f),
horizontalArrangement = Arrangement.spacedBy(space = spacing / 2),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(space = spacing),
) {
Box(
modifier = Modifier
.height(height = icon.height)
.widthIn(min = icon.width, max = icon.width * 3)
.graphicsLayer { clip = false },
contentAlignment = Alignment.CenterStart,
) {
Box(
modifier = Modifier
.size(size = icon)
.background(
color = MaterialTheme.lwa.colorScheme.elevated.base4dp,
shape = CircleShape,
)
)
AsyncImage(
modifier = Modifier
.size(size = icon)
.aspectRatio(ratio = 1f, matchHeightConstraintsFirst = true),
model = item.icon,
contentScale = ContentScale.Crop,
contentDescription = null,
)
if (item.consumable) {
AnimatedContent(
modifier = Modifier
.align(alignment = Alignment.BottomEnd)
.offset(y = 4.dp),
targetState = item.count,
transitionSpec = {
val enter = fadeIn() + slideInVertically { -8 }
val exit = fadeOut() + slideOutVertically { 8 }
enter togetherWith exit using SizeTransform(clip = false)
},
) {
Box(
contentAlignment = Alignment.Center,
) {
Text(
style = MaterialTheme.lwa.typography.inventory.countOutline,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
text = it,
)
Text(
style = MaterialTheme.lwa.typography.inventory.countInline,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
text = it,
)
}
}
}
}
Text(
modifier = Modifier.alignByBaseline().weight(weight = 1f, fill = false),
style = MaterialTheme.lwa.typography.base.body1,
fontWeight = FontWeight.Bold,
modifier = Modifier
.padding(top = top, bottom = bottom)
.weight(weight = 1f, fill = false),
style = MaterialTheme.lwa.typography.inventory.label,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
text = item.label,
)
if (item.consumable) {
AnimatedContent(
modifier = Modifier.alignByBaseline(),
targetState = item.count,
transitionSpec = {
val enter = fadeIn() + slideInHorizontally { 16 }
val exit = fadeOut() + slideOutHorizontally { -16 }
enter togetherWith exit using SizeTransform(clip = false)
},
) {
Text(
style = MaterialTheme.lwa.typography.base.caption,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
text = it,
)
}
}
}
Row(
modifier = Modifier.offset(x = end - spacing),
modifier = Modifier
.padding(top = top, bottom = bottom)
.offset(x = end - spacing),
horizontalArrangement = Arrangement.spacedBy(space = spacing),
) {
if (item.consumable) {

View file

@ -3,6 +3,7 @@ package com.pixelized.desktop.lwa.ui.theme
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
@ -20,8 +21,9 @@ val LocalLwaTheme = compositionLocalOf<LwaTheme> {
}
val MaterialTheme.lwa: LwaTheme
@Composable
@Stable
@Composable
@ReadOnlyComposable
get() = LocalLwaTheme.current
@Stable

View file

@ -7,6 +7,9 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.graphics.StrokeJoin
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
@ -15,6 +18,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.sp
import com.pixelized.desktop.lwa.ui.theme.color.LwaColors
import com.pixelized.desktop.lwa.ui.theme.typography.LwaTypography.Settings
import com.pixelized.shared.lwa.model.inventory.Inventory
import lwacharactersheet.composeapp.generated.resources.Res
import lwacharactersheet.composeapp.generated.resources.consola_mono_bold
import lwacharactersheet.composeapp.generated.resources.consola_mono_book
@ -26,6 +30,7 @@ data class LwaTypography(
val chat: Chat,
val settings: Settings,
val portrait: Portrait,
val inventory: Inventory,
) {
@Stable
data class Chat(
@ -46,6 +51,13 @@ data class LwaTypography(
val value: TextStyle,
val max: TextStyle,
)
@Stable
data class Inventory(
val countOutline: TextStyle,
val countInline: TextStyle,
val label: TextStyle,
)
}
@Composable
@ -118,6 +130,25 @@ fun lwaTypography(
blurRadius = 2f,
),
),
),
inventory = LwaTypography.Inventory(
countOutline = base.caption.copy(
fontWeight = FontWeight.SemiBold,
color = colors.elevated.base4dp,
drawStyle = Stroke(
miter = 3f,
width = 3f,
join = StrokeJoin.Round,
)
),
countInline = base.caption.copy(
fontWeight = FontWeight.SemiBold,
color = colors.base.onSurface,
drawStyle = Fill
),
label = base.body1.copy(
fontWeight = FontWeight.Normal,
),
)
)
}

View file

@ -0,0 +1,34 @@
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.Immutable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.Stable
import androidx.compose.ui.platform.LocalLayoutDirection
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.LayoutDirection
@Composable
@ReadOnlyComposable
fun PaddingValues.calculatePaddings(
layoutDirection: LayoutDirection = LocalLayoutDirection.current,
): ComputedPaddingValues {
return ComputedPaddingValues(
start = calculateStartPadding(layoutDirection = layoutDirection),
top = calculateTopPadding(),
end = calculateEndPadding(layoutDirection = layoutDirection),
bottom = calculateBottomPadding(),
)
}
@Immutable
@Stable
data class ComputedPaddingValues(
@Stable val start: Dp,
@Stable val top: Dp,
@Stable val end: Dp,
@Stable val bottom: Dp,
)

View file

@ -2,21 +2,22 @@ package com.pixelized.desktop.lwa.utils
import androidx.compose.material.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import com.pixelized.desktop.lwa.ui.theme.lwa
@Composable
@ReadOnlyComposable
fun rememberBackgroundGradient(
color: Color = MaterialTheme.lwa.colorScheme.base.surface,
from: Float = 0.5f,
to: Float = 1.0f,
): Brush {
val colorScheme = MaterialTheme.colors
return remember(colorScheme) {
Brush.verticalGradient(
colors = listOf(
colorScheme.surface.copy(alpha = from),
colorScheme.surface.copy(alpha = to),
)
return Brush.verticalGradient(
colors = listOf(
color.copy(alpha = from),
color.copy(alpha = to),
)
}
)
}