Add Tree like structure to the inventory.
This commit is contained in:
parent
daea5fd6dc
commit
a55e2c8162
8 changed files with 158 additions and 72 deletions
|
|
@ -11,7 +11,7 @@ data class Inventory(
|
|||
)
|
||||
|
||||
fun find(container: String): Item.Builder? {
|
||||
return items.firstOrNull { it.find(name = container) != null }
|
||||
return items.localFind { it.find(name = container) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,9 +34,20 @@ data class Inventory(
|
|||
fun find(name: String): Builder? {
|
||||
return when (this.name) {
|
||||
name -> this
|
||||
else -> items.firstOrNull { it.find(name = name) != null }
|
||||
else -> items.localFind { it.find(name = name) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <T> Iterable<T>.localFind(predicate: (T) -> T?): T? {
|
||||
var single: T? = null
|
||||
for (element in this) {
|
||||
single = predicate(element)
|
||||
if (single != null) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return single
|
||||
}
|
||||
|
|
@ -56,6 +56,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.pixelized.rplexicon.LocalRollOverlay
|
||||
import com.pixelized.rplexicon.LocalSnack
|
||||
|
|
@ -81,6 +82,7 @@ import com.pixelized.rplexicon.ui.screens.character.pages.proficiency.Proficienc
|
|||
import com.pixelized.rplexicon.ui.screens.character.pages.proficiency.ProficiencyPreview
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.proficiency.ProficiencyViewModel
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.extentions.lexiconShadow
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(
|
||||
|
|
@ -226,7 +228,6 @@ private fun CharacterSheetContent(
|
|||
contentWindowInsets = NO_WINDOW_INSETS,
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
modifier = Modifier.shadow(elevation = 4.dp),
|
||||
navigationIcon = {
|
||||
IconButton(onClick = onBack) {
|
||||
Icon(
|
||||
|
|
@ -278,6 +279,9 @@ private fun CharacterSheetContent(
|
|||
) {
|
||||
Column {
|
||||
PagerHeader(
|
||||
modifier = Modifier
|
||||
.zIndex(1f)
|
||||
.lexiconShadow(),
|
||||
pagerState = pagerState,
|
||||
onTab = onTab,
|
||||
)
|
||||
|
|
@ -310,12 +314,15 @@ private fun CharacterSheetContent(
|
|||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun PagerHeader(
|
||||
modifier: Modifier = Modifier,
|
||||
pagerState: PagerState,
|
||||
tabs: List<String> = headers(),
|
||||
onTab: (Int) -> Unit,
|
||||
) {
|
||||
ScrollableTabRow(
|
||||
modifier = modifier,
|
||||
selectedTabIndex = pagerState.currentPage,
|
||||
divider = { },
|
||||
) {
|
||||
tabs.forEachIndexed { index, tab ->
|
||||
Tab(
|
||||
|
|
@ -364,7 +371,7 @@ private fun CharacterScreenPreview(
|
|||
CharacterSheetContent(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
sheetState = sheetState,
|
||||
pagerState = rememberPagerState(initialPage = preview) { 2 },
|
||||
pagerState = rememberPagerState(initialPage = preview) { 4 },
|
||||
refreshState = rememberPullRefreshState(refreshing = false, onRefresh = { }),
|
||||
name = "Brulkhai",
|
||||
onBack = { },
|
||||
|
|
|
|||
|
|
@ -2,28 +2,37 @@ package com.pixelized.rplexicon.ui.screens.character.composable.actions
|
|||
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_NO
|
||||
import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.Divider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.preview.rememberInventoryListState
|
||||
import com.pixelized.rplexicon.ui.theme.LexiconTheme
|
||||
import com.pixelized.rplexicon.utilitary.rememberTextSize
|
||||
|
||||
@Stable
|
||||
data class InventoryItemUio(
|
||||
val name: String,
|
||||
val amount: String? = null,
|
||||
val items: List<InventoryItemUio> = emptyList(),
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalLayoutApi::class)
|
||||
|
|
@ -33,30 +42,63 @@ fun InventoryItem(
|
|||
padding: PaddingValues = PaddingValues(horizontal = 16.dp, vertical = 2.dp),
|
||||
item: InventoryItemUio,
|
||||
) {
|
||||
FlowRow(
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues = padding)
|
||||
.then(other = modifier),
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
fontWeight = FontWeight.Bold,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = item.name,
|
||||
)
|
||||
item.amount?.let {
|
||||
FlowRow {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
fontWeight = FontWeight.Medium,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
text = " : ",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
fontWeight = FontWeight.Light,
|
||||
fontWeight = FontWeight.Bold,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = it
|
||||
text = item.name,
|
||||
)
|
||||
item.amount?.let {
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
fontWeight = FontWeight.Medium,
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
text = " : ",
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.alignByBaseline(),
|
||||
fontWeight = FontWeight.Light,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
text = it
|
||||
)
|
||||
}
|
||||
}
|
||||
val lastIndex = remember(item.items.size) { item.items.lastIndex }
|
||||
item.items.forEachIndexed { index, item ->
|
||||
Row(
|
||||
modifier = Modifier.height(intrinsicSize = IntrinsicSize.Min),
|
||||
) {
|
||||
val size = rememberTextSize(style = MaterialTheme.typography.bodyMedium)
|
||||
if (index == lastIndex) {
|
||||
Divider(
|
||||
modifier = Modifier
|
||||
.height(height = 3.dp + size.height / 2)
|
||||
.width(1.dp)
|
||||
)
|
||||
} else {
|
||||
Divider(
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.width(1.dp)
|
||||
)
|
||||
}
|
||||
Divider(
|
||||
modifier = Modifier
|
||||
.padding(top = 2.dp + size.height / 2)
|
||||
.height(1.dp)
|
||||
.width(8.dp)
|
||||
)
|
||||
InventoryItem(
|
||||
padding = PaddingValues(start = 7.dp, top = 2.dp, bottom = 2.dp),
|
||||
item = item,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,25 +106,17 @@ fun InventoryItem(
|
|||
@Composable
|
||||
@Preview(uiMode = UI_MODE_NIGHT_NO)
|
||||
@Preview(uiMode = UI_MODE_NIGHT_YES)
|
||||
private fun InventoryItemPreview(
|
||||
@PreviewParameter(InventoryItemPreviewProvider::class) preview: InventoryItemUio,
|
||||
) {
|
||||
private fun InventoryItemPreview() {
|
||||
LexiconTheme {
|
||||
Surface {
|
||||
InventoryItem(item = preview)
|
||||
Column {
|
||||
val items = rememberInventoryListState()
|
||||
items.value.forEach {
|
||||
InventoryItem(
|
||||
item = it,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class InventoryItemPreviewProvider : PreviewParameterProvider<InventoryItemUio> {
|
||||
override val values: Sequence<InventoryItemUio> = sequenceOf(
|
||||
InventoryItemUio(
|
||||
name = "- Cordes",
|
||||
amount = "15 mètres",
|
||||
),
|
||||
InventoryItemUio(
|
||||
name = "- Piège de chasse",
|
||||
amount = null,
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
@ -5,8 +5,6 @@ import androidx.compose.runtime.Stable
|
|||
import androidx.compose.runtime.State
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import com.pixelized.rplexicon.R
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.EquipmentItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.InventoryItemUio
|
||||
|
||||
@Composable
|
||||
|
|
@ -15,18 +13,26 @@ fun rememberInventoryListState(): State<List<InventoryItemUio>> {
|
|||
return remember {
|
||||
mutableStateOf(
|
||||
listOf(
|
||||
InventoryItemUio(name = "Bourse"),
|
||||
InventoryItemUio(name = "- Or", amount = "21"),
|
||||
InventoryItemUio(name = "Sac à dos"),
|
||||
InventoryItemUio(name = "- Sac de couchage"),
|
||||
InventoryItemUio(name = "- Kit de cuisine"),
|
||||
InventoryItemUio(name = "- Boite d'allume-feu"),
|
||||
InventoryItemUio(name = "- Torches", amount = "10"),
|
||||
InventoryItemUio(name = "- Rations journalières", amount = "10"),
|
||||
InventoryItemUio(name = "- Outre d'eau"),
|
||||
InventoryItemUio(name = "- Cordes", amount = "15 mètres"),
|
||||
InventoryItemUio(name = "- Piège de chasse"),
|
||||
InventoryItemUio(name = "- Bâton de marche"),
|
||||
InventoryItemUio(
|
||||
name = "Bourse",
|
||||
items = listOf(
|
||||
InventoryItemUio(name = "Or", amount = "21"),
|
||||
),
|
||||
),
|
||||
InventoryItemUio(
|
||||
name = "Sac à dos",
|
||||
items = listOf(
|
||||
InventoryItemUio(name = "Sac de couchage"),
|
||||
InventoryItemUio(name = "Kit de cuisine"),
|
||||
InventoryItemUio(name = "Boite d'allume-feu"),
|
||||
InventoryItemUio(name = "Torches", amount = "10"),
|
||||
InventoryItemUio(name = "Rations journalières", amount = "10"),
|
||||
InventoryItemUio(name = "Outre d'eau"),
|
||||
InventoryItemUio(name = "Cordes", amount = "15 mètres"),
|
||||
InventoryItemUio(name = "Piège de chasse"),
|
||||
InventoryItemUio(name = "Bâton de marche"),
|
||||
),
|
||||
),
|
||||
InventoryItemUio(name = "Dague"),
|
||||
InventoryItemUio(name = "Javelot", amount = "4"),
|
||||
InventoryItemUio(name = "Cape de protection"),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
package com.pixelized.rplexicon.ui.screens.character.factory
|
||||
|
||||
import com.pixelized.rplexicon.model.Inventory
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.InventoryItemUio
|
||||
import javax.inject.Inject
|
||||
|
||||
class ItemUioFactory @Inject constructor() {
|
||||
|
||||
fun toUio(item: Inventory.Item): InventoryItemUio {
|
||||
return InventoryItemUio(
|
||||
name = item.name,
|
||||
amount = item.amount,
|
||||
items = item.items.map { toUio(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import android.content.res.Configuration.UI_MODE_NIGHT_YES
|
|||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
|
|
@ -94,12 +95,6 @@ private fun InventoryPageContent(
|
|||
}
|
||||
items(items = inventory.value) {
|
||||
InventoryItem(
|
||||
modifier = Modifier.padding(
|
||||
top = when (it.name.contains("-")) {
|
||||
true -> 0.dp
|
||||
else -> 4.dp
|
||||
}
|
||||
),
|
||||
item = it,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import com.pixelized.rplexicon.repository.data.character.InventoryRepository
|
|||
import com.pixelized.rplexicon.ui.navigation.screens.characterSheetArgument
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.EquipmentItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.composable.actions.InventoryItemUio
|
||||
import com.pixelized.rplexicon.ui.screens.character.factory.ItemUioFactory
|
||||
import com.pixelized.rplexicon.ui.screens.character.pages.actions.SkillDetailUio
|
||||
import com.pixelized.rplexicon.utilitary.extentions.context
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
|
@ -28,6 +29,7 @@ class InventoryViewModel @Inject constructor(
|
|||
private val inventoryRepository: InventoryRepository,
|
||||
private val equipmentRepository: EquipmentRepository,
|
||||
private val descriptionRepository: DescriptionRepository,
|
||||
private val itemFactory: ItemUioFactory,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
application: Application
|
||||
) : AndroidViewModel(application) {
|
||||
|
|
@ -48,15 +50,10 @@ class InventoryViewModel @Inject constructor(
|
|||
init {
|
||||
viewModelScope.launch {
|
||||
launch(Dispatchers.IO) {
|
||||
inventoryRepository.data.collect {
|
||||
val items = it[character]?.items?.map { item ->
|
||||
InventoryItemUio(
|
||||
name = item.name,
|
||||
amount = item.amount,
|
||||
)
|
||||
} ?: emptyList()
|
||||
inventoryRepository.data.collect { inventories ->
|
||||
val items = inventories[character]?.items?.map { itemFactory.toUio(it) }
|
||||
withContext(Dispatchers.Main) {
|
||||
_inventory.value = items
|
||||
_inventory.value = items ?: emptyList()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -88,7 +85,7 @@ class InventoryViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun showSkillDetailDialog(item: String) {
|
||||
val description = descriptionRepository.find(name = item)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,14 +2,11 @@ package com.pixelized.rplexicon.utilitary.extentions
|
|||
|
||||
import androidx.compose.animation.core.FiniteAnimationSpec
|
||||
import androidx.compose.animation.core.Transition
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.animateOffsetAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.gestures.detectTransformGestures
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.isSystemInDarkTheme
|
||||
|
|
@ -18,6 +15,7 @@ import androidx.compose.foundation.layout.heightIn
|
|||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.material3.DividerDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.surfaceColorAtElevation
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -31,6 +29,9 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.composed
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
|
|
@ -151,4 +152,23 @@ fun Modifier.ddBorder(
|
|||
.clip(
|
||||
shape = inner,
|
||||
)
|
||||
}
|
||||
|
||||
fun Modifier.lexiconShadow() = composed {
|
||||
if (isSystemInDarkTheme()) {
|
||||
val color = DividerDefaults.color
|
||||
drawWithContent {
|
||||
drawContent()
|
||||
val thickness = DividerDefaults.Thickness.toPx()
|
||||
val y = size.height
|
||||
drawLine(
|
||||
color = color,
|
||||
start = Offset(0f, y),
|
||||
end = Offset(size.width, y),
|
||||
strokeWidth = thickness
|
||||
)
|
||||
}
|
||||
} else {
|
||||
shadow(elevation = 4.dp)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue