Add toggable addIventoryItem action linked to the Addable tag.
This commit is contained in:
parent
ae820f5979
commit
04825cafda
9 changed files with 180 additions and 41 deletions
|
|
@ -187,6 +187,8 @@
|
||||||
<string name="character__inventory__filter_inventory__label">Filtrer l'inventaire</string>
|
<string name="character__inventory__filter_inventory__label">Filtrer l'inventaire</string>
|
||||||
<string name="character__inventory__add_to_inventory__action">Ajouter un objet</string>
|
<string name="character__inventory__add_to_inventory__action">Ajouter un objet</string>
|
||||||
<string name="character__inventory__use__action">Utiliser</string>
|
<string name="character__inventory__use__action">Utiliser</string>
|
||||||
|
<string name="character__inventory__equip__action">Équiper</string>
|
||||||
|
<string name="character__inventory__unequip__action">Déséquiper</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>
|
||||||
<string name="character__inventory__filter_item_inventory__label">Filtrer les objets</string>
|
<string name="character__inventory__filter_item_inventory__label">Filtrer les objets</string>
|
||||||
|
|
@ -194,7 +196,7 @@
|
||||||
<string name="character__inventory__inventory__dialog__action">Ajouter à l'inventaire</string>
|
<string name="character__inventory__inventory__dialog__action">Ajouter à l'inventaire</string>
|
||||||
<string name="character__inventory__inventory__dialog__count">Quantité</string>
|
<string name="character__inventory__inventory__dialog__count">Quantité</string>
|
||||||
<string name="character__inventory__inventory__dialog__count_action">Modifier</string>
|
<string name="character__inventory__inventory__dialog__count_action">Modifier</string>
|
||||||
<string name="character__inventory__inventory__dialog__throw_action">Jetter</string>
|
<string name="character__inventory__inventory__dialog__throw_action">Jeter</string>
|
||||||
<string name="character__inventory__inventory__dialog__equip_action">Equiper</string>
|
<string name="character__inventory__inventory__dialog__equip_action">Equiper</string>
|
||||||
<string name="character__inventory__inventory__dialog__consume_action">Utiliser</string>
|
<string name="character__inventory__inventory__dialog__consume_action">Utiliser</string>
|
||||||
<string name="character__inventory__description_empty__label">Cet objet n'a pas de description.</string>
|
<string name="character__inventory__description_empty__label">Cet objet n'a pas de description.</string>
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,6 @@ class InventoryDialogFactory {
|
||||||
)
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ADDABLE_TAG_ID = "META:ADDABLE"
|
const val ADDABLE_TAG_ID = "META:ADDABLE"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -44,11 +44,12 @@ 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.rememberSaturationFilter
|
import com.pixelized.desktop.lwa.utils.rememberSaturationFilter
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.character__inventory__equip__action
|
||||||
import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__action
|
import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__action
|
||||||
import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__consume_action
|
import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__consume_action
|
||||||
import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__count_action
|
import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__count_action
|
||||||
import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__equip_action
|
|
||||||
import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__throw_action
|
import lwacharactersheet.composeapp.generated.resources.character__inventory__inventory__dialog__throw_action
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.character__inventory__unequip__action
|
||||||
import lwacharactersheet.composeapp.generated.resources.ic_close_24dp
|
import lwacharactersheet.composeapp.generated.resources.ic_close_24dp
|
||||||
import org.jetbrains.compose.resources.painterResource
|
import org.jetbrains.compose.resources.painterResource
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
|
@ -66,6 +67,7 @@ data class ItemDetailDialogUio(
|
||||||
// options
|
// options
|
||||||
val countable: LwaTextFieldUio?,
|
val countable: LwaTextFieldUio?,
|
||||||
val consumable: Boolean,
|
val consumable: Boolean,
|
||||||
|
val equipped: Boolean,
|
||||||
val equipable: Boolean,
|
val equipable: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -213,9 +215,18 @@ fun ItemDetailDialog(
|
||||||
TextButton(
|
TextButton(
|
||||||
onClick = { onEquip(state) },
|
onClick = { onEquip(state) },
|
||||||
) {
|
) {
|
||||||
Text(
|
AnimatedContent(
|
||||||
text = stringResource(Res.string.character__inventory__inventory__dialog__equip_action),
|
targetState = state.equipped,
|
||||||
)
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
when (it) {
|
||||||
|
true -> Res.string.character__inventory__unequip__action
|
||||||
|
else -> Res.string.character__inventory__equip__action
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (state.consumable) {
|
if (state.consumable) {
|
||||||
|
|
|
||||||
|
|
@ -11,13 +11,14 @@ import java.text.DecimalFormat
|
||||||
|
|
||||||
class ItemDetailDialogFactory {
|
class ItemDetailDialogFactory {
|
||||||
|
|
||||||
private val floatChecker = Regex("""^\d*[.,]?\d*${'$'}""")
|
private val floatChecker = Regex("""^\d*,?\d*${'$'}""")
|
||||||
private val format = DecimalFormat("#.##")
|
private val format = DecimalFormat("#.##")
|
||||||
|
|
||||||
suspend fun convertToDialogUio(
|
suspend fun convertToDialogUio(
|
||||||
characterSheetId: String?,
|
characterSheetId: String?,
|
||||||
items: Map<String, Item>,
|
items: Map<String, Item>,
|
||||||
count: Float,
|
count: Float,
|
||||||
|
equipped: Boolean,
|
||||||
inventoryId: String?,
|
inventoryId: String?,
|
||||||
itemId: String?,
|
itemId: String?,
|
||||||
): ItemDetailDialogUio? {
|
): ItemDetailDialogUio? {
|
||||||
|
|
@ -38,6 +39,7 @@ class ItemDetailDialogFactory {
|
||||||
?.let { createFieldFlow(value = format.format(count)) }
|
?.let { createFieldFlow(value = format.format(count)) }
|
||||||
?.createTextField(label = getString(Res.string.character__inventory__inventory__dialog__count)),
|
?.createTextField(label = getString(Res.string.character__inventory__inventory__dialog__count)),
|
||||||
consumable = item.options.consumable,
|
consumable = item.options.consumable,
|
||||||
|
equipped = equipped,
|
||||||
equipable = item.options.equipable,
|
equipable = item.options.equipable,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ class ItemDetailDialogViewModel(
|
||||||
characterSheetId = ids?.characterSheetId,
|
characterSheetId = ids?.characterSheetId,
|
||||||
items = items,
|
items = items,
|
||||||
count = selectedInventoryItem?.count ?: 0f,
|
count = selectedInventoryItem?.count ?: 0f,
|
||||||
|
equipped = selectedInventoryItem?.equipped ?: false,
|
||||||
inventoryId = ids?.inventoryId,
|
inventoryId = ids?.inventoryId,
|
||||||
itemId = ids?.itemId,
|
itemId = ids?.itemId,
|
||||||
)
|
)
|
||||||
|
|
@ -83,7 +84,7 @@ class ItemDetailDialogViewModel(
|
||||||
suspend fun onAddInventoryItem(
|
suspend fun onAddInventoryItem(
|
||||||
characterSheetId: String,
|
characterSheetId: String,
|
||||||
itemId: String,
|
itemId: String,
|
||||||
) : Boolean {
|
): Boolean {
|
||||||
try {
|
try {
|
||||||
// create the inventory item on the server, get the newly create id from that.
|
// create the inventory item on the server, get the newly create id from that.
|
||||||
val inventoryId = inventoryRepository.createInventoryItem(
|
val inventoryId = inventoryRepository.createInventoryItem(
|
||||||
|
|
@ -143,7 +144,7 @@ class ItemDetailDialogViewModel(
|
||||||
suspend fun equipInventoryItem(
|
suspend fun equipInventoryItem(
|
||||||
characterSheetId: String,
|
characterSheetId: String,
|
||||||
inventoryId: String?,
|
inventoryId: String?,
|
||||||
) : Boolean {
|
): Boolean {
|
||||||
if (inventoryId == null) return false
|
if (inventoryId == null) return false
|
||||||
try {
|
try {
|
||||||
inventoryRepository.equipInventoryItem(
|
inventoryRepository.equipInventoryItem(
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,13 @@ class CharacterDetailPanelViewModel(
|
||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val characterSheetPanelFlow = MutableStateFlow<CharacterSheetPanel?>(null)
|
private val characterSheetPanelFlow = MutableStateFlow<CharacterSheetPanel?>(null)
|
||||||
|
private val addItemAction = characterInventoryFactory
|
||||||
|
.addItemActionFlow()
|
||||||
|
.stateIn(
|
||||||
|
scope = viewModelScope,
|
||||||
|
started = SharingStarted.Lazily,
|
||||||
|
initialValue = false,
|
||||||
|
)
|
||||||
|
|
||||||
val detail: StateFlow<CharacterDetailPanelUio> = characterSheetPanelFlow
|
val detail: StateFlow<CharacterDetailPanelUio> = characterSheetPanelFlow
|
||||||
.map { characterSheetPanel ->
|
.map { characterSheetPanel ->
|
||||||
|
|
@ -55,6 +62,7 @@ class CharacterDetailPanelViewModel(
|
||||||
inventory = characterInventoryFactory.convertToCharacterInventoryUioFlow(
|
inventory = characterInventoryFactory.convertToCharacterInventoryUioFlow(
|
||||||
characterSheetId = characterSheetId,
|
characterSheetId = characterSheetId,
|
||||||
scope = viewModelScope,
|
scope = viewModelScope,
|
||||||
|
addItemAction = addItemAction,
|
||||||
initialValue = ::emptyInventory,
|
initialValue = ::emptyInventory,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
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.calculateEndPadding
|
||||||
|
import androidx.compose.foundation.layout.calculateStartPadding
|
||||||
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.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
|
@ -24,9 +26,13 @@ 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
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
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.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.unit.Dp
|
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
|
||||||
|
|
@ -46,7 +52,7 @@ import com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item
|
||||||
import com.pixelized.desktop.lwa.ui.theme.color.component.LwaButtonColors
|
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.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.flow.StateFlow
|
||||||
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.character__inventory__add_to_inventory__action
|
import lwacharactersheet.composeapp.generated.resources.character__inventory__add_to_inventory__action
|
||||||
|
|
@ -58,6 +64,7 @@ import org.koin.compose.viewmodel.koinViewModel
|
||||||
@Stable
|
@Stable
|
||||||
data class CharacterDetailInventoryUio(
|
data class CharacterDetailInventoryUio(
|
||||||
val characterSheetId: String,
|
val characterSheetId: String,
|
||||||
|
val addItemAction: StateFlow<Boolean>,
|
||||||
val filter: LwaTextFieldUio,
|
val filter: LwaTextFieldUio,
|
||||||
val purse: PurseUio,
|
val purse: PurseUio,
|
||||||
val items: List<InventoryItemUio>,
|
val items: List<InventoryItemUio>,
|
||||||
|
|
@ -125,6 +132,14 @@ fun CharacterDetailInventory(
|
||||||
inventoryId = it.inventoryId,
|
inventoryId = it.inventoryId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onEquip = {
|
||||||
|
scope.launch {
|
||||||
|
itemDetailDialogViewModel.equipInventoryItem(
|
||||||
|
characterSheetId = it.characterSheetId,
|
||||||
|
inventoryId = it.inventoryId,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -248,14 +263,16 @@ private fun CharacterDetailInventoryContent(
|
||||||
onPurse: (String) -> Unit,
|
onPurse: (String) -> Unit,
|
||||||
onItem: (InventoryItemUio) -> Unit,
|
onItem: (InventoryItemUio) -> Unit,
|
||||||
onConsume: (InventoryItemUio) -> Unit,
|
onConsume: (InventoryItemUio) -> Unit,
|
||||||
|
onEquip: (InventoryItemUio) -> Unit,
|
||||||
onAddItem: (String) -> Unit,
|
onAddItem: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val addItemAction = inventory.addItemAction.collectAsState()
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
) {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.matchParentSize(),
|
modifier = Modifier.matchParentSize(),
|
||||||
contentPadding = paddings + PaddingValues(bottom = 56.dp),
|
contentPadding = paddings.plus(addItemAction, PaddingValues(bottom = 56.dp)),
|
||||||
verticalArrangement = Arrangement.spacedBy(space = spacing),
|
verticalArrangement = Arrangement.spacedBy(space = spacing),
|
||||||
) {
|
) {
|
||||||
item(
|
item(
|
||||||
|
|
@ -309,31 +326,61 @@ private fun CharacterDetailInventoryContent(
|
||||||
item = it,
|
item = it,
|
||||||
onClick = { onItem(it) },
|
onClick = { onItem(it) },
|
||||||
onConsume = { onConsume(it) },
|
onConsume = { onConsume(it) },
|
||||||
|
onEquip = { onEquip(it) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AnimatedVisibility(
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(alignment = Alignment.BottomEnd)
|
.align(alignment = Alignment.BottomEnd)
|
||||||
.padding(paddingValues = paddings),
|
.padding(paddingValues = paddings),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
visible = addItemAction.value,
|
||||||
|
enter = fadeIn(),
|
||||||
|
exit = fadeOut(),
|
||||||
) {
|
) {
|
||||||
Button(
|
Row(
|
||||||
colors = LwaButtonColors(),
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
elevation = ButtonDefaults.elevation(4.dp),
|
|
||||||
shape = CircleShape,
|
|
||||||
onClick = { onAddItem(inventory.characterSheetId) },
|
|
||||||
) {
|
) {
|
||||||
Text(
|
Button(
|
||||||
modifier = Modifier.padding(end = 4.dp),
|
colors = LwaButtonColors(),
|
||||||
text = stringResource(Res.string.character__inventory__add_to_inventory__action),
|
elevation = ButtonDefaults.elevation(4.dp),
|
||||||
)
|
shape = CircleShape,
|
||||||
Icon(
|
onClick = { onAddItem(inventory.characterSheetId) },
|
||||||
imageVector = Icons.Default.Add,
|
) {
|
||||||
contentDescription = null,
|
Text(
|
||||||
)
|
modifier = Modifier.padding(end = 4.dp),
|
||||||
|
text = stringResource(Res.string.character__inventory__add_to_inventory__action),
|
||||||
|
)
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Add,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
@Composable
|
||||||
|
fun PaddingValues.plus(
|
||||||
|
state: State<Boolean>,
|
||||||
|
other: PaddingValues,
|
||||||
|
): PaddingValues {
|
||||||
|
val direction = LocalLayoutDirection.current
|
||||||
|
val sum by remember(this, other, direction, state) {
|
||||||
|
derivedStateOf {
|
||||||
|
if (state.value) {
|
||||||
|
PaddingValues(
|
||||||
|
start = calculateStartPadding(direction) + other.calculateStartPadding(direction),
|
||||||
|
top = calculateTopPadding() + other.calculateTopPadding(),
|
||||||
|
end = calculateEndPadding(direction) + other.calculateEndPadding(direction),
|
||||||
|
bottom = calculateBottomPadding() + other.calculateBottomPadding(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,8 @@ 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.repository.tag.TagRepository
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.character.inventory.InventoryDialogFactory
|
||||||
import com.pixelized.desktop.lwa.ui.composable.textfield.LwaTextFieldUio
|
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.ui.screen.campaign.player.detail.inventory.item.PurseUio
|
||||||
|
|
@ -9,6 +11,7 @@ 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.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
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
|
||||||
|
|
@ -24,11 +27,19 @@ class CharacterDetailInventoryFactory(
|
||||||
private val inventoryRepository: InventoryRepository,
|
private val inventoryRepository: InventoryRepository,
|
||||||
private val itemRepository: ItemRepository,
|
private val itemRepository: ItemRepository,
|
||||||
) {
|
) {
|
||||||
|
fun addItemActionFlow(): Flow<Boolean> {
|
||||||
|
return itemRepository.itemFlow().map { entry ->
|
||||||
|
entry.values.any { item ->
|
||||||
|
item.tags.any { id -> id == ADDABLE_TAG_ID }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun convertToCharacterInventoryUioFlow(
|
suspend fun convertToCharacterInventoryUioFlow(
|
||||||
characterSheetId: String,
|
characterSheetId: String,
|
||||||
scope: CoroutineScope,
|
scope: CoroutineScope,
|
||||||
started: SharingStarted = SharingStarted.Eagerly,
|
started: SharingStarted = SharingStarted.Eagerly,
|
||||||
|
addItemAction: StateFlow<Boolean>,
|
||||||
initialValue: () -> CharacterDetailInventoryUio?,
|
initialValue: () -> CharacterDetailInventoryUio?,
|
||||||
): StateFlow<CharacterDetailInventoryUio?> {
|
): StateFlow<CharacterDetailInventoryUio?> {
|
||||||
val filterFlow = MutableStateFlow("")
|
val filterFlow = MutableStateFlow("")
|
||||||
|
|
@ -48,8 +59,9 @@ class CharacterDetailInventoryFactory(
|
||||||
convertToCharacterInventoryUio(
|
convertToCharacterInventoryUio(
|
||||||
characterSheetId = characterSheetId,
|
characterSheetId = characterSheetId,
|
||||||
filter = filterField,
|
filter = filterField,
|
||||||
purse = inventory?.purse,
|
addItemAction = addItemAction,
|
||||||
inventory = inventory?.items,
|
purse = inventory.purse,
|
||||||
|
inventory = inventory.items,
|
||||||
items = items.filterValues { it.metadata.label.unAccent().contains(filter, true) },
|
items = items.filterValues { it.metadata.label.unAccent().contains(filter, true) },
|
||||||
)
|
)
|
||||||
}.stateIn(
|
}.stateIn(
|
||||||
|
|
@ -62,6 +74,7 @@ class CharacterDetailInventoryFactory(
|
||||||
private suspend fun convertToCharacterInventoryUio(
|
private suspend fun convertToCharacterInventoryUio(
|
||||||
characterSheetId: String?,
|
characterSheetId: String?,
|
||||||
filter: LwaTextFieldUio,
|
filter: LwaTextFieldUio,
|
||||||
|
addItemAction: StateFlow<Boolean>,
|
||||||
purse: Inventory.Purse?,
|
purse: Inventory.Purse?,
|
||||||
inventory: List<Inventory.Item>?,
|
inventory: List<Inventory.Item>?,
|
||||||
items: Map<String, Item>,
|
items: Map<String, Item>,
|
||||||
|
|
@ -76,6 +89,7 @@ class CharacterDetailInventoryFactory(
|
||||||
copper = purse?.copper ?: 0,
|
copper = purse?.copper ?: 0,
|
||||||
),
|
),
|
||||||
filter = filter,
|
filter = filter,
|
||||||
|
addItemAction = addItemAction,
|
||||||
items = inventory
|
items = inventory
|
||||||
?.mapNotNull {
|
?.mapNotNull {
|
||||||
val item = items[it.itemId] ?: return@mapNotNull null
|
val item = items[it.itemId] ?: return@mapNotNull null
|
||||||
|
|
@ -87,6 +101,7 @@ class CharacterDetailInventoryFactory(
|
||||||
count = it.count,
|
count = it.count,
|
||||||
equipped = it.equipped,
|
equipped = it.equipped,
|
||||||
consumable = item.options.consumable,
|
consumable = item.options.consumable,
|
||||||
|
equipable = item.options.equipable,
|
||||||
tooltips = takeIf { item.metadata.description.isNotEmpty() }?.let {
|
tooltips = takeIf { item.metadata.description.isNotEmpty() }?.let {
|
||||||
InventoryItemUio.Tooltips(
|
InventoryItemUio.Tooltips(
|
||||||
label = item.metadata.label,
|
label = item.metadata.label,
|
||||||
|
|
@ -100,4 +115,8 @@ class CharacterDetailInventoryFactory(
|
||||||
?: emptyList()
|
?: emptyList()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val ADDABLE_TAG_ID = InventoryDialogFactory.ADDABLE_TAG_ID
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item
|
package com.pixelized.desktop.lwa.ui.screen.campaign.player.detail.inventory.item
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedContent
|
import androidx.compose.animation.AnimatedContent
|
||||||
|
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.slideInHorizontally
|
||||||
|
import androidx.compose.animation.slideOutHorizontally
|
||||||
import androidx.compose.animation.togetherWith
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
|
|
@ -12,6 +15,7 @@ import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
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.calculateEndPadding
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.offset
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
|
@ -23,12 +27,14 @@ import androidx.compose.material.TextButton
|
||||||
import androidx.compose.material.minimumInteractiveComponentSize
|
import androidx.compose.material.minimumInteractiveComponentSize
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.Stable
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
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.graphics.Color
|
||||||
import androidx.compose.ui.graphics.FilterQuality
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
|
|
@ -40,6 +46,8 @@ import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||||
import com.pixelized.desktop.lwa.utils.extention.ribbon
|
import com.pixelized.desktop.lwa.utils.extention.ribbon
|
||||||
import com.pixelized.desktop.lwa.utils.rememberSaturationFilter
|
import com.pixelized.desktop.lwa.utils.rememberSaturationFilter
|
||||||
import lwacharactersheet.composeapp.generated.resources.Res
|
import lwacharactersheet.composeapp.generated.resources.Res
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.character__inventory__equip__action
|
||||||
|
import lwacharactersheet.composeapp.generated.resources.character__inventory__unequip__action
|
||||||
import lwacharactersheet.composeapp.generated.resources.character__inventory__use__action
|
import lwacharactersheet.composeapp.generated.resources.character__inventory__use__action
|
||||||
import org.jetbrains.compose.resources.stringResource
|
import org.jetbrains.compose.resources.stringResource
|
||||||
|
|
||||||
|
|
@ -52,6 +60,7 @@ data class InventoryItemUio(
|
||||||
val count: Float,
|
val count: Float,
|
||||||
val equipped: Boolean,
|
val equipped: Boolean,
|
||||||
val consumable: Boolean,
|
val consumable: Boolean,
|
||||||
|
val equipable: Boolean,
|
||||||
val tooltips: Tooltips?,
|
val tooltips: Tooltips?,
|
||||||
) {
|
) {
|
||||||
@Stable
|
@Stable
|
||||||
|
|
@ -68,7 +77,10 @@ object GMCharacterPreviewDefault {
|
||||||
val paddings = PaddingValues(horizontal = 16.dp)
|
val paddings = PaddingValues(horizontal = 16.dp)
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
val spacing: Dp = 4.dp
|
val toolTipPaddings = PaddingValues(all = 16.dp)
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
val spacing: Dp = 8.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class)
|
||||||
|
|
@ -76,11 +88,20 @@ object GMCharacterPreviewDefault {
|
||||||
fun InventoryItem(
|
fun InventoryItem(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
padding: PaddingValues = GMCharacterPreviewDefault.paddings,
|
padding: PaddingValues = GMCharacterPreviewDefault.paddings,
|
||||||
|
toolTipPaddings: PaddingValues = GMCharacterPreviewDefault.toolTipPaddings,
|
||||||
spacing: Dp = GMCharacterPreviewDefault.spacing,
|
spacing: Dp = GMCharacterPreviewDefault.spacing,
|
||||||
item: InventoryItemUio,
|
item: InventoryItemUio,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onConsume: () -> 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) }
|
||||||
|
|
||||||
TooltipLayout2(
|
TooltipLayout2(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
delayMillis = 500,
|
delayMillis = 500,
|
||||||
|
|
@ -89,14 +110,14 @@ fun InventoryItem(
|
||||||
DecoratedBox {
|
DecoratedBox {
|
||||||
Surface {
|
Surface {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.padding(all = 16.dp)
|
modifier = Modifier.padding(paddingValues = toolTipPaddings)
|
||||||
) {
|
) {
|
||||||
takeIf { tooltips.image?.isNotEmpty() == true }?.let {
|
takeIf { tooltips.image?.isNotEmpty() == true }?.let {
|
||||||
DesaturatedAsyncImage(
|
DesaturatedAsyncImage(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(96.dp)
|
.size(size = 96.dp)
|
||||||
.align(alignment = Alignment.TopEnd)
|
.align(alignment = Alignment.TopEnd)
|
||||||
.offset(x = 8.dp, y = (-8).dp),
|
.offset(x = toolEnd, y = -toolTop),
|
||||||
colorFilter = rememberSaturationFilter(),
|
colorFilter = rememberSaturationFilter(),
|
||||||
model = tooltips.image,
|
model = tooltips.image,
|
||||||
contentScale = ContentScale.Crop,
|
contentScale = ContentScale.Crop,
|
||||||
|
|
@ -107,7 +128,7 @@ fun InventoryItem(
|
||||||
}
|
}
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp)
|
verticalArrangement = Arrangement.spacedBy(space = spacing)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
style = MaterialTheme.typography.body2,
|
style = MaterialTheme.typography.body2,
|
||||||
|
|
@ -144,10 +165,11 @@ fun InventoryItem(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
|
modifier = Modifier.weight(weight = 1f),
|
||||||
horizontalArrangement = Arrangement.spacedBy(space = spacing),
|
horizontalArrangement = Arrangement.spacedBy(space = spacing),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
modifier = Modifier.alignByBaseline(),
|
modifier = Modifier.alignByBaseline().weight(weight = 1f, fill = false),
|
||||||
style = MaterialTheme.lwa.typography.base.body1,
|
style = MaterialTheme.lwa.typography.base.body1,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
|
@ -157,7 +179,11 @@ fun InventoryItem(
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
modifier = Modifier.alignByBaseline(),
|
modifier = Modifier.alignByBaseline(),
|
||||||
targetState = item.count,
|
targetState = item.count,
|
||||||
transitionSpec = { fadeIn() togetherWith fadeOut() },
|
transitionSpec = {
|
||||||
|
val enter = fadeIn() + slideInHorizontally { 16 }
|
||||||
|
val exit = fadeOut() + slideOutHorizontally { -16 }
|
||||||
|
enter togetherWith exit using SizeTransform(clip = false)
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
when (it) {
|
when (it) {
|
||||||
0f, 1f -> Unit
|
0f, 1f -> Unit
|
||||||
|
|
@ -170,11 +196,34 @@ fun InventoryItem(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (item.consumable) {
|
Row(
|
||||||
TextButton(
|
modifier = Modifier.offset(x = end - spacing),
|
||||||
onClick = onConsume,
|
horizontalArrangement = Arrangement.spacedBy(space = spacing),
|
||||||
) {
|
) {
|
||||||
Text(text = stringResource(Res.string.character__inventory__use__action))
|
if (item.consumable) {
|
||||||
|
TextButton(
|
||||||
|
onClick = onConsume,
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(Res.string.character__inventory__use__action))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (item.equipable) {
|
||||||
|
TextButton(
|
||||||
|
onClick = onEquip,
|
||||||
|
) {
|
||||||
|
AnimatedContent(
|
||||||
|
targetState = item.equipped,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
when (it) {
|
||||||
|
true -> Res.string.character__inventory__unequip__action
|
||||||
|
else -> Res.string.character__inventory__equip__action
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue