Forbide multiple item adding.

This commit is contained in:
Andres Gomez, Thomas (ITDV RL) 2024-08-07 18:06:11 +02:00
parent 041505bb79
commit 248a51f396
20 changed files with 103 additions and 29 deletions

View file

@ -3,7 +3,7 @@ package com.pixelized.rplexicon.data.model
import android.net.Uri import android.net.Uri
import com.pixelized.rplexicon.data.model.roll.Throw import com.pixelized.rplexicon.data.model.roll.Throw
import com.pixelized.rplexicon.script.Script import com.pixelized.rplexicon.script.Script
import com.pixelized.rplexicon.utilitary.extentions.string.ImageCache.attackIcon import com.pixelized.rplexicon.utilitary.ImageCache.attackIcon
data class Attack( data class Attack(

View file

@ -2,7 +2,7 @@ package com.pixelized.rplexicon.data.model
import android.net.Uri import android.net.Uri
import com.pixelized.rplexicon.data.model.roll.Throw import com.pixelized.rplexicon.data.model.roll.Throw
import com.pixelized.rplexicon.utilitary.extentions.string.ImageCache.objectIcon import com.pixelized.rplexicon.utilitary.ImageCache.objectIcon
data class ObjectAction( data class ObjectAction(
val prefix: String?, val prefix: String?,

View file

@ -3,7 +3,7 @@ package com.pixelized.rplexicon.data.model
import android.net.Uri import android.net.Uri
import com.pixelized.rplexicon.data.model.roll.Throw import com.pixelized.rplexicon.data.model.roll.Throw
import com.pixelized.rplexicon.script.Script import com.pixelized.rplexicon.script.Script
import com.pixelized.rplexicon.utilitary.extentions.string.ImageCache.skillIcon import com.pixelized.rplexicon.utilitary.ImageCache.skillIcon
data class Skill( data class Skill(
val name: String, val name: String,

View file

@ -1,7 +1,7 @@
package com.pixelized.rplexicon.data.model package com.pixelized.rplexicon.data.model
import android.net.Uri import android.net.Uri
import com.pixelized.rplexicon.utilitary.extentions.string.ImageCache.spellIcon import com.pixelized.rplexicon.utilitary.ImageCache.spellIcon
data class Spell( data class Spell(
val name: String, val name: String,

View file

@ -5,7 +5,7 @@ import com.pixelized.rplexicon.data.model.Property
import com.pixelized.rplexicon.data.model.roll.Dice import com.pixelized.rplexicon.data.model.roll.Dice
import com.pixelized.rplexicon.data.model.roll.Flat import com.pixelized.rplexicon.data.model.roll.Flat
import com.pixelized.rplexicon.script.Script import com.pixelized.rplexicon.script.Script
import com.pixelized.rplexicon.utilitary.extentions.string.ImageCache.alterationIcon import com.pixelized.rplexicon.utilitary.ImageCache.alterationIcon
data class Alteration( data class Alteration(
val name: String, val name: String,

View file

@ -4,7 +4,7 @@ import com.pixelized.rplexicon.data.model.item.InventoryPath
import com.pixelized.rplexicon.data.model.item.Item import com.pixelized.rplexicon.data.model.item.Item
import com.pixelized.rplexicon.data.network.ItemDto import com.pixelized.rplexicon.data.network.ItemDto
import com.pixelized.rplexicon.ui.screens.character.pages.inventory.InventoryItemUio import com.pixelized.rplexicon.ui.screens.character.pages.inventory.InventoryItemUio
import com.pixelized.rplexicon.utilitary.extentions.string.ImageCache import com.pixelized.rplexicon.utilitary.ImageCache
import javax.inject.Inject import javax.inject.Inject
class InventoryItemUioFactory @Inject constructor() { class InventoryItemUioFactory @Inject constructor() {

View file

@ -3,9 +3,10 @@ package com.pixelized.rplexicon.ui.screens.character.factory
import android.content.Context import android.content.Context
import com.pixelized.rplexicon.R import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.data.model.item.Item import com.pixelized.rplexicon.data.model.item.Item
import com.pixelized.rplexicon.data.network.ItemDto
import com.pixelized.rplexicon.ui.screens.character.pages.inventory.item.ItemCategoryUio import com.pixelized.rplexicon.ui.screens.character.pages.inventory.item.ItemCategoryUio
import com.pixelized.rplexicon.ui.screens.character.pages.inventory.item.ItemUio import com.pixelized.rplexicon.ui.screens.character.pages.inventory.item.ItemUio
import com.pixelized.rplexicon.utilitary.extentions.string.ImageCache import com.pixelized.rplexicon.utilitary.ImageCache
import javax.inject.Inject import javax.inject.Inject
class ItemElementUioFactory @Inject constructor() { class ItemElementUioFactory @Inject constructor() {
@ -13,6 +14,7 @@ class ItemElementUioFactory @Inject constructor() {
fun toUio( fun toUio(
context: Context, context: Context,
items: List<Item>, items: List<Item>,
fire: List<ItemDto>,
): List<ItemCategoryUio> { ): List<ItemCategoryUio> {
return items return items
.groupBy { it.type } .groupBy { it.type }
@ -21,14 +23,27 @@ class ItemElementUioFactory @Inject constructor() {
title = group.key title = group.key
?: context.getString(R.string.character_sheet__item_list__uncategorized), ?: context.getString(R.string.character_sheet__item_list__uncategorized),
items = group.value.map { item -> items = group.value.map { item ->
val fireItem = fire.find(id = item.id)
ItemUio( ItemUio(
id = item.id, id = item.id,
name = item.fullName, name = item.fullName,
context = item.context, context = item.context,
icon = ImageCache.cache(uri = item.icon), icon = ImageCache.cache(uri = item.icon),
enabled = (fireItem?.amount ?: 0) < 1,
quantity = fireItem?.amount?.takeIf { it > 0 }?.let { "$it" },
) )
} }
) )
} }
} }
fun List<ItemDto>.find(id: String): ItemDto? {
return this.firstNotNullOfOrNull {
if (it.id == id) {
it
} else {
it.children.find(id = id)
}
}
}
} }

View file

@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.IntrinsicSize
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.fillMaxSize
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
@ -19,6 +18,13 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable import androidx.compose.runtime.Stable
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.DrawModifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.ColorMatrix
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
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.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
@ -26,6 +32,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.pixelized.rplexicon.R import com.pixelized.rplexicon.R
import com.pixelized.rplexicon.data.model.item.InventoryPath
import com.pixelized.rplexicon.ui.composable.images.AsyncImage import com.pixelized.rplexicon.ui.composable.images.AsyncImage
import com.pixelized.rplexicon.ui.theme.LexiconTheme import com.pixelized.rplexicon.ui.theme.LexiconTheme
@ -35,6 +42,8 @@ data class ItemUio(
val name: String, val name: String,
val context: String?, val context: String?,
val icon: Any?, val icon: Any?,
val enabled: Boolean,
val quantity: String?,
) )
@Composable @Composable
@ -46,7 +55,8 @@ fun Item(
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
.clickable(enabled = onClick != null) { onClick?.invoke() } .greyScale(enabled = item.enabled.not())
.clickable(enabled = onClick != null && item.enabled) { onClick?.invoke() }
.minimumInteractiveComponentSize() .minimumInteractiveComponentSize()
.height(intrinsicSize = IntrinsicSize.Min) .height(intrinsicSize = IntrinsicSize.Min)
.padding(paddingValues) .padding(paddingValues)
@ -59,7 +69,7 @@ fun Item(
model = item.icon, model = item.icon,
) )
Column( Column(
modifier = Modifier.fillMaxSize(), modifier = Modifier.weight(weight = 1f),
verticalArrangement = Arrangement.spacedBy( verticalArrangement = Arrangement.spacedBy(
space = 4.dp, space = 4.dp,
alignment = Alignment.CenterVertically alignment = Alignment.CenterVertically
@ -82,6 +92,13 @@ fun Item(
) )
} }
} }
Text(
style = MaterialTheme.typography.bodyMedium,
fontWeight = FontWeight.Bold,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
text = item.quantity?.let { "$it" } ?: "",
)
} }
} }
@ -98,6 +115,23 @@ private fun ItemPreview(
} }
} }
class GreyScaleModifier : DrawModifier {
override fun ContentDrawScope.draw() {
val saturationMatrix = ColorMatrix().apply { this.setToSaturation(0f) }
val saturationFilter = ColorFilter.colorMatrix(saturationMatrix)
val paint = Paint().apply {
colorFilter = saturationFilter
}
drawIntoCanvas {
it.saveLayer(Rect(0f, 0f, size.width, size.height), paint)
drawContent()
it.restore()
}
}
}
fun Modifier.greyScale(enabled: Boolean) = if (enabled) this.then(GreyScaleModifier()) else this
private class ItemProvider : PreviewParameterProvider<ItemUio> { private class ItemProvider : PreviewParameterProvider<ItemUio> {
override val values: Sequence<ItemUio> = sequenceOf( override val values: Sequence<ItemUio> = sequenceOf(
ItemUio( ItemUio(
@ -105,12 +139,16 @@ private class ItemProvider : PreviewParameterProvider<ItemUio> {
name = "Bourse", name = "Bourse",
context = "Un petite bourse.", context = "Un petite bourse.",
icon = R.drawable.icbg_pouch_a_unfaded, icon = R.drawable.icbg_pouch_a_unfaded,
enabled = true,
quantity = null,
), ),
ItemUio( ItemUio(
id = "2ecf41c2-06b1-4f2d-a6d9-b6adcaf05aba", id = "2ecf41c2-06b1-4f2d-a6d9-b6adcaf05aba",
name = "Sac à dos", name = "Sac à dos",
context = null, context = null,
icon = R.drawable.icbg_backpack_b_unfaded, icon = R.drawable.icbg_backpack_b_unfaded,
enabled = false,
quantity = "1",
), ),
) )
} }

View file

@ -294,24 +294,32 @@ private fun ItemLisPreview() {
name = "Bourse", name = "Bourse",
context = "Une petite bourse en cuir.", context = "Une petite bourse en cuir.",
icon = R.drawable.icbg_leather_pouch_a_unfaded, icon = R.drawable.icbg_leather_pouch_a_unfaded,
enabled = false,
quantity = "1",
), ),
ItemUio( ItemUio(
id = "7d27561b-f2f4-4899-a2fc-df3501b1b66b", id = "7d27561b-f2f4-4899-a2fc-df3501b1b66b",
name = "Bourse", name = "Bourse",
context = "Une petite bourse.", context = "Une petite bourse.",
icon = R.drawable.icbg_pouch_a_unfaded, icon = R.drawable.icbg_pouch_a_unfaded,
enabled = true,
quantity = null,
), ),
ItemUio( ItemUio(
id = "2ecf41c2-06b1-4f2d-a6d9-b6adcaf05aba", id = "2ecf41c2-06b1-4f2d-a6d9-b6adcaf05aba",
name = "Sac à dos", name = "Sac à dos",
context = "Sac à dos pour aventurier.", context = "Sac à dos pour aventurier.",
icon = R.drawable.icbg_backpack_a_unfaded, icon = R.drawable.icbg_backpack_a_unfaded,
enabled = true,
quantity = null,
), ),
ItemUio( ItemUio(
id = "43424bbc-0117-44f8-b512-6d469a05e6c2", id = "43424bbc-0117-44f8-b512-6d469a05e6c2",
name = "Sac à dos", name = "Sac à dos",
context = "Sac à dos pour aventurier.", context = "Sac à dos pour aventurier.",
icon = R.drawable.icbg_backpack_b_unfaded, icon = R.drawable.icbg_backpack_b_unfaded,
enabled = true,
quantity = null,
), ),
), ),
), ),
@ -323,12 +331,16 @@ private fun ItemLisPreview() {
name = "Parchemin d'Arme spirituelle", name = "Parchemin d'Arme spirituelle",
context = null, context = null,
icon = R.drawable.icbg_book_signedtradebisa_unfaded, icon = R.drawable.icbg_book_signedtradebisa_unfaded,
enabled = true,
quantity = null,
), ),
ItemUio( ItemUio(
id = "eda09856-5a91-4411-ac75-248a16ce1060", id = "eda09856-5a91-4411-ac75-248a16ce1060",
name = "Parchemin de Bénédiction", name = "Parchemin de Bénédiction",
context = null, context = null,
icon = R.drawable.icbg_scroll_of_bless_unfaded, icon = R.drawable.icbg_scroll_of_bless_unfaded,
enabled = true,
quantity = null,
), ),
) )
), ),

View file

@ -7,23 +7,29 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.pixelized.rplexicon.data.model.item.Item import com.pixelized.rplexicon.data.model.item.InventoryPath
import com.pixelized.rplexicon.data.model.item.InventoryPath.Companion.ROOT
import com.pixelized.rplexicon.data.repository.character.ItemsRepository import com.pixelized.rplexicon.data.repository.character.ItemsRepository
import com.pixelized.rplexicon.data.repository.firebase.InventoryFireRepository
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
import com.pixelized.rplexicon.ui.screens.character.factory.ItemElementUioFactory import com.pixelized.rplexicon.ui.screens.character.factory.ItemElementUioFactory
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class ItemListViewModel @Inject constructor( class ItemListViewModel @Inject constructor(
private val itemsRepository: ItemsRepository, private val itemsRepository: ItemsRepository,
private val fireRepository: InventoryFireRepository,
private val factory: ItemElementUioFactory, private val factory: ItemElementUioFactory,
savedStateHandle: SavedStateHandle,
) : ViewModel() { ) : ViewModel() {
private val character = savedStateHandle.characterSheetArgument.name
private val filter = MutableStateFlow("") private val filter = MutableStateFlow("")
@ -43,21 +49,23 @@ class ItemListViewModel @Inject constructor(
@Stable @Stable
get() { get() {
val context = LocalContext.current val context = LocalContext.current
return itemsRepository.data.combine(filter) { items, filter -> items to filter } return combine(
.map { (items: Map<String, Item>, filter: String) -> filter,
items.values itemsRepository.data,
.filter { fireRepository.getInventory(character = character, path = ROOT),
val name = it.fullName.contains(other = filter, ignoreCase = true) ) { filter, items, fires ->
val type = it.type?.contains(other = filter, ignoreCase = true) == true val filteredItems = items.values
name || type .filter {
} val name = it.fullName.contains(other = filter, ignoreCase = true)
.sortedWith(compareBy(Collator.getInstance()) { it.fullName }) val type = it.type?.contains(other = filter, ignoreCase = true) == true
.sortedBy { it.type } name || type
} }
.map { items: List<Item> -> .sortedWith(compareBy(Collator.getInstance()) { it.fullName })
factory.toUio(context = context, items = items) .sortedBy { it.type }
} factory.toUio(context = context, items = filteredItems, fire = fires)
.collectAsState(initial = emptyList()) }.collectAsState(
initial = emptyList()
)
} }
fun updateItemList() { fun updateItemList() {

View file

@ -1,4 +1,4 @@
package com.pixelized.rplexicon.utilitary.extentions.string package com.pixelized.rplexicon.utilitary
import android.net.Uri import android.net.Uri
import android.util.Log import android.util.Log
@ -90,6 +90,7 @@ object ImageCache {
"https://drive.google.com/uc?export=view&id=1AeSHg792EwVbkjCNjJaqzC4v0uNj9NRn" to R.drawable.ic_drive_fire_starter, "https://drive.google.com/uc?export=view&id=1AeSHg792EwVbkjCNjJaqzC4v0uNj9NRn" to R.drawable.ic_drive_fire_starter,
"https://drive.google.com/uc?export=view&id=1Dc0hBGXTNP8dnYqHJlSsK1WgWAsWtCV9" to R.drawable.ic_drive_lantern_of_revealing, "https://drive.google.com/uc?export=view&id=1Dc0hBGXTNP8dnYqHJlSsK1WgWAsWtCV9" to R.drawable.ic_drive_lantern_of_revealing,
"https://drive.google.com/uc?export=view&id=1KPlgQK1C3lfZn3ZHTHd-dqiSINjQpnH9" to R.drawable.ic_drive_ring_of_kazan, "https://drive.google.com/uc?export=view&id=1KPlgQK1C3lfZn3ZHTHd-dqiSINjQpnH9" to R.drawable.ic_drive_ring_of_kazan,
"https://drive.google.com/uc?export=view&id=1YYgZ2SlSn6TkRiphpIf62KgwTZWQZHQJ" to R.drawable.ic_drive_tome_of_strahd,
) )
private val alterations = hashMapOf( private val alterations = hashMapOf(
@ -358,7 +359,7 @@ object ImageCache {
fun cache(uri: Uri?): Any = when (uri) { fun cache(uri: Uri?): Any = when (uri) {
null -> R.drawable.icbg_generic_darkness_icon null -> R.drawable.icbg_generic_darkness_icon
else -> this.uri[uri.toString()] ?: kotlin.run { else -> ImageCache.uri[uri.toString()] ?: kotlin.run {
Log.v("ImageCache", "$uri") Log.v("ImageCache", "$uri")
uri uri
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB