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 com.pixelized.rplexicon.data.model.roll.Throw
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(

View file

@ -2,7 +2,7 @@ package com.pixelized.rplexicon.data.model
import android.net.Uri
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(
val prefix: String?,

View file

@ -3,7 +3,7 @@ package com.pixelized.rplexicon.data.model
import android.net.Uri
import com.pixelized.rplexicon.data.model.roll.Throw
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(
val name: String,

View file

@ -1,7 +1,7 @@
package com.pixelized.rplexicon.data.model
import android.net.Uri
import com.pixelized.rplexicon.utilitary.extentions.string.ImageCache.spellIcon
import com.pixelized.rplexicon.utilitary.ImageCache.spellIcon
data class Spell(
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.Flat
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(
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.network.ItemDto
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
class InventoryItemUioFactory @Inject constructor() {

View file

@ -3,9 +3,10 @@ package com.pixelized.rplexicon.ui.screens.character.factory
import android.content.Context
import com.pixelized.rplexicon.R
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.ItemUio
import com.pixelized.rplexicon.utilitary.extentions.string.ImageCache
import com.pixelized.rplexicon.utilitary.ImageCache
import javax.inject.Inject
class ItemElementUioFactory @Inject constructor() {
@ -13,6 +14,7 @@ class ItemElementUioFactory @Inject constructor() {
fun toUio(
context: Context,
items: List<Item>,
fire: List<ItemDto>,
): List<ItemCategoryUio> {
return items
.groupBy { it.type }
@ -21,14 +23,27 @@ class ItemElementUioFactory @Inject constructor() {
title = group.key
?: context.getString(R.string.character_sheet__item_list__uncategorized),
items = group.value.map { item ->
val fireItem = fire.find(id = item.id)
ItemUio(
id = item.id,
name = item.fullName,
context = item.context,
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.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
@ -19,6 +18,13 @@ 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.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.style.TextOverflow
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.unit.dp
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.theme.LexiconTheme
@ -35,6 +42,8 @@ data class ItemUio(
val name: String,
val context: String?,
val icon: Any?,
val enabled: Boolean,
val quantity: String?,
)
@Composable
@ -46,7 +55,8 @@ fun Item(
) {
Row(
modifier = Modifier
.clickable(enabled = onClick != null) { onClick?.invoke() }
.greyScale(enabled = item.enabled.not())
.clickable(enabled = onClick != null && item.enabled) { onClick?.invoke() }
.minimumInteractiveComponentSize()
.height(intrinsicSize = IntrinsicSize.Min)
.padding(paddingValues)
@ -59,7 +69,7 @@ fun Item(
model = item.icon,
)
Column(
modifier = Modifier.fillMaxSize(),
modifier = Modifier.weight(weight = 1f),
verticalArrangement = Arrangement.spacedBy(
space = 4.dp,
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> {
override val values: Sequence<ItemUio> = sequenceOf(
ItemUio(
@ -105,12 +139,16 @@ private class ItemProvider : PreviewParameterProvider<ItemUio> {
name = "Bourse",
context = "Un petite bourse.",
icon = R.drawable.icbg_pouch_a_unfaded,
enabled = true,
quantity = null,
),
ItemUio(
id = "2ecf41c2-06b1-4f2d-a6d9-b6adcaf05aba",
name = "Sac à dos",
context = null,
icon = R.drawable.icbg_backpack_b_unfaded,
enabled = false,
quantity = "1",
),
)
}

View file

@ -294,24 +294,32 @@ private fun ItemLisPreview() {
name = "Bourse",
context = "Une petite bourse en cuir.",
icon = R.drawable.icbg_leather_pouch_a_unfaded,
enabled = false,
quantity = "1",
),
ItemUio(
id = "7d27561b-f2f4-4899-a2fc-df3501b1b66b",
name = "Bourse",
context = "Une petite bourse.",
icon = R.drawable.icbg_pouch_a_unfaded,
enabled = true,
quantity = null,
),
ItemUio(
id = "2ecf41c2-06b1-4f2d-a6d9-b6adcaf05aba",
name = "Sac à dos",
context = "Sac à dos pour aventurier.",
icon = R.drawable.icbg_backpack_a_unfaded,
enabled = true,
quantity = null,
),
ItemUio(
id = "43424bbc-0117-44f8-b512-6d469a05e6c2",
name = "Sac à dos",
context = "Sac à dos pour aventurier.",
icon = R.drawable.icbg_backpack_b_unfaded,
enabled = true,
quantity = null,
),
),
),
@ -323,12 +331,16 @@ private fun ItemLisPreview() {
name = "Parchemin d'Arme spirituelle",
context = null,
icon = R.drawable.icbg_book_signedtradebisa_unfaded,
enabled = true,
quantity = null,
),
ItemUio(
id = "eda09856-5a91-4411-ac75-248a16ce1060",
name = "Parchemin de Bénédiction",
context = null,
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.mutableStateOf
import androidx.compose.ui.platform.LocalContext
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
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.firebase.InventoryFireRepository
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
import com.pixelized.rplexicon.ui.screens.character.factory.ItemElementUioFactory
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class ItemListViewModel @Inject constructor(
private val itemsRepository: ItemsRepository,
private val fireRepository: InventoryFireRepository,
private val factory: ItemElementUioFactory,
savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val character = savedStateHandle.characterSheetArgument.name
private val filter = MutableStateFlow("")
@ -43,21 +49,23 @@ class ItemListViewModel @Inject constructor(
@Stable
get() {
val context = LocalContext.current
return itemsRepository.data.combine(filter) { items, filter -> items to filter }
.map { (items: Map<String, Item>, filter: String) ->
items.values
.filter {
val name = it.fullName.contains(other = filter, ignoreCase = true)
val type = it.type?.contains(other = filter, ignoreCase = true) == true
name || type
}
.sortedWith(compareBy(Collator.getInstance()) { it.fullName })
.sortedBy { it.type }
}
.map { items: List<Item> ->
factory.toUio(context = context, items = items)
}
.collectAsState(initial = emptyList())
return combine(
filter,
itemsRepository.data,
fireRepository.getInventory(character = character, path = ROOT),
) { filter, items, fires ->
val filteredItems = items.values
.filter {
val name = it.fullName.contains(other = filter, ignoreCase = true)
val type = it.type?.contains(other = filter, ignoreCase = true) == true
name || type
}
.sortedWith(compareBy(Collator.getInstance()) { it.fullName })
.sortedBy { it.type }
factory.toUio(context = context, items = filteredItems, fire = fires)
}.collectAsState(
initial = emptyList()
)
}
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.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=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=1YYgZ2SlSn6TkRiphpIf62KgwTZWQZHQJ" to R.drawable.ic_drive_tome_of_strahd,
)
private val alterations = hashMapOf(
@ -358,7 +359,7 @@ object ImageCache {
fun cache(uri: Uri?): Any = when (uri) {
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")
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