Add inventory item detail detail (basic)
This commit is contained in:
parent
05a376aea8
commit
c94c820efb
28 changed files with 490 additions and 77 deletions
|
|
@ -61,7 +61,6 @@ class DataSyncViewModel(
|
||||||
networkRepository.status
|
networkRepository.status
|
||||||
.filter { status -> status == NetworkRepository.Status.CONNECTED }
|
.filter { status -> status == NetworkRepository.Status.CONNECTED }
|
||||||
.flatMapLatest { campaignRepository.campaignFlow().map { it.instances } }
|
.flatMapLatest { campaignRepository.campaignFlow().map { it.instances } }
|
||||||
.distinctUntilChanged()
|
|
||||||
.onEach { instances ->
|
.onEach { instances ->
|
||||||
instances.forEach { characterSheetId ->
|
instances.forEach { characterSheetId ->
|
||||||
characterRepository.updateCharacterSheet(
|
characterRepository.updateCharacterSheet(
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@ import com.pixelized.desktop.lwa.ui.composable.character.characteristic.Characte
|
||||||
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogViewModel
|
import com.pixelized.desktop.lwa.ui.composable.character.characteristic.CharacterSheetCharacteristicDialogViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedDialogFactory
|
import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedDialogFactory
|
||||||
import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedDialogViewModel
|
import com.pixelized.desktop.lwa.ui.composable.character.diminished.CharacterSheetDiminishedDialogViewModel
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.character.inventory.InventoryDialogFactory
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.character.inventory.InventoryDialogViewModel
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialogFactory
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialogViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogFactory
|
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogFactory
|
||||||
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogViewModel
|
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.overlay.portrait.PortraitOverlayViewModel
|
import com.pixelized.desktop.lwa.ui.overlay.portrait.PortraitOverlayViewModel
|
||||||
|
|
@ -149,6 +153,8 @@ val factoryDependencies
|
||||||
factoryOf(::CharacterSheetCharacteristicDialogFactory)
|
factoryOf(::CharacterSheetCharacteristicDialogFactory)
|
||||||
factoryOf(::CharacterSheetDiminishedDialogFactory)
|
factoryOf(::CharacterSheetDiminishedDialogFactory)
|
||||||
factoryOf(::CharacterSheetAlterationDialogFactory)
|
factoryOf(::CharacterSheetAlterationDialogFactory)
|
||||||
|
factoryOf(::InventoryDialogFactory)
|
||||||
|
factoryOf(::ItemDetailDialogFactory)
|
||||||
factoryOf(::PurseDialogFactory)
|
factoryOf(::PurseDialogFactory)
|
||||||
factoryOf(::TextMessageFactory)
|
factoryOf(::TextMessageFactory)
|
||||||
factoryOf(::LevelUpFactory)
|
factoryOf(::LevelUpFactory)
|
||||||
|
|
@ -175,6 +181,8 @@ val viewModelDependencies
|
||||||
viewModelOf(::CharacterSheetDiminishedDialogViewModel)
|
viewModelOf(::CharacterSheetDiminishedDialogViewModel)
|
||||||
viewModelOf(::CharacterSheetCharacteristicDialogViewModel)
|
viewModelOf(::CharacterSheetCharacteristicDialogViewModel)
|
||||||
viewModelOf(::CharacterSheetAlterationDialogViewModel)
|
viewModelOf(::CharacterSheetAlterationDialogViewModel)
|
||||||
|
viewModelOf(::InventoryDialogViewModel)
|
||||||
|
viewModelOf(::ItemDetailDialogViewModel)
|
||||||
viewModelOf(::PurseDialogViewModel)
|
viewModelOf(::PurseDialogViewModel)
|
||||||
viewModelOf(::CampaignChatViewModel)
|
viewModelOf(::CampaignChatViewModel)
|
||||||
viewModelOf(::SettingsViewModel)
|
viewModelOf(::SettingsViewModel)
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ import androidx.compose.foundation.layout.BoxScope
|
||||||
import androidx.compose.runtime.Composable
|
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.mutableStateOf
|
import androidx.compose.runtime.derivedStateOf
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.BlurredEdgeTreatment
|
import androidx.compose.ui.draw.BlurredEdgeTreatment
|
||||||
|
|
@ -18,6 +19,7 @@ import androidx.compose.ui.graphics.Color
|
||||||
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.ui.theme.color.LwaColorPalette
|
import com.pixelized.desktop.lwa.ui.theme.color.LwaColorPalette
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
class BlurContentController(
|
class BlurContentController(
|
||||||
|
|
@ -25,15 +27,15 @@ class BlurContentController(
|
||||||
val blurredRadius: Dp = 8.dp,
|
val blurredRadius: Dp = 8.dp,
|
||||||
val scrimColor: Color = LwaColorPalette.DefaultScrimColor,
|
val scrimColor: Color = LwaColorPalette.DefaultScrimColor,
|
||||||
) {
|
) {
|
||||||
private val _blurred = mutableStateOf(blurred)
|
private val layer = mutableIntStateOf(if (blurred) 1 else 0)
|
||||||
val isBlurred: State<Boolean> get() = _blurred
|
val isBlurred: State<Boolean> = derivedStateOf { layer.value != 0 }
|
||||||
|
|
||||||
fun show() {
|
fun show() {
|
||||||
_blurred.value = true
|
layer.value += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hide() {
|
fun hide() {
|
||||||
_blurred.value = false
|
layer.value = max(layer.value - 1, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.composable.character.inventory
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun InventoryDialog() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.composable.character.inventory
|
||||||
|
|
||||||
|
class InventoryDialogFactory {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.composable.character.inventory
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
||||||
|
class InventoryDialogViewModel: ViewModel() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,128 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.composable.character.item
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Surface
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.Stable
|
||||||
|
import androidx.compose.runtime.State
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.decoratedBox.DecoratedBox
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.image.DesaturatedAsyncImage
|
||||||
|
import com.pixelized.desktop.lwa.utils.extention.onPreviewEscape
|
||||||
|
import com.pixelized.desktop.lwa.utils.rememberSaturationFilter
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
data class ItemDetailDialogUio(
|
||||||
|
val itemId: String,
|
||||||
|
val label: String,
|
||||||
|
val description: String,
|
||||||
|
val image: String?,
|
||||||
|
val option: OptionUio,
|
||||||
|
) {
|
||||||
|
@Stable
|
||||||
|
data class OptionUio(
|
||||||
|
val equipable: Boolean,
|
||||||
|
val consumable: Boolean,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
object ItemDetailDialogDefault {
|
||||||
|
@Stable
|
||||||
|
val paddings = PaddingValues(all = 16.dp)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ItemDetailDialog(
|
||||||
|
dialog: State<ItemDetailDialogUio?>,
|
||||||
|
paddings: PaddingValues = ItemDetailDialogDefault.paddings,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
) {
|
||||||
|
dialog.value?.let {
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
content = {
|
||||||
|
ItemDetailDialogContent(
|
||||||
|
dialog = it,
|
||||||
|
paddings = paddings,
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ItemDetailDialogContent(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
paddings: PaddingValues,
|
||||||
|
dialog: ItemDetailDialogUio,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable(
|
||||||
|
interactionSource = remember { MutableInteractionSource() },
|
||||||
|
indication = null,
|
||||||
|
onClick = onDismissRequest,
|
||||||
|
)
|
||||||
|
.onPreviewEscape(
|
||||||
|
escape = onDismissRequest,
|
||||||
|
enter = onDismissRequest,
|
||||||
|
)
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(all = 32.dp),
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
) {
|
||||||
|
DecoratedBox {
|
||||||
|
Surface {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(paddingValues = paddings)
|
||||||
|
) {
|
||||||
|
DesaturatedAsyncImage(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(64.dp * 2)
|
||||||
|
.align(alignment = Alignment.TopEnd),
|
||||||
|
colorFilter = rememberSaturationFilter(),
|
||||||
|
model = dialog.image,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
alignment = Alignment.TopCenter,
|
||||||
|
filterQuality = FilterQuality.High,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier = modifier,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(space = 8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
style = MaterialTheme.typography.h5,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
text = dialog.label,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
style = MaterialTheme.typography.body1,
|
||||||
|
text = dialog.description,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.composable.character.item
|
||||||
|
|
||||||
|
import com.pixelized.shared.lwa.model.item.Item
|
||||||
|
|
||||||
|
class ItemDetailDialogFactory {
|
||||||
|
|
||||||
|
fun convertToDialogUio(
|
||||||
|
items: Map<String, Item>,
|
||||||
|
itemId: String?,
|
||||||
|
): ItemDetailDialogUio? {
|
||||||
|
val item = itemId.let(items::get) ?: return null
|
||||||
|
|
||||||
|
return ItemDetailDialogUio(
|
||||||
|
itemId = item.id,
|
||||||
|
label = item.metadata.label,
|
||||||
|
description = item.metadata.description,
|
||||||
|
image = item.metadata.image,
|
||||||
|
option = ItemDetailDialogUio.OptionUio(
|
||||||
|
equipable = item.options.equipable,
|
||||||
|
consumable = item.options.consumable,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.composable.character.item
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.pixelized.desktop.lwa.repository.item.ItemRepository
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.SharingStarted
|
||||||
|
import kotlinx.coroutines.flow.combine
|
||||||
|
import kotlinx.coroutines.flow.stateIn
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
|
||||||
|
class ItemDetailDialogViewModel(
|
||||||
|
itemRepository: ItemRepository,
|
||||||
|
factory: ItemDetailDialogFactory,
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
private val selectedItemId = MutableStateFlow<String?>(null)
|
||||||
|
val itemDialog = combine(
|
||||||
|
itemRepository.itemFlow, selectedItemId,
|
||||||
|
transform = { items, itemId -> factory.convertToDialogUio(items, itemId) }
|
||||||
|
).stateIn(
|
||||||
|
scope = viewModelScope,
|
||||||
|
started = SharingStarted.Lazily,
|
||||||
|
initialValue = null
|
||||||
|
)
|
||||||
|
|
||||||
|
fun showItemDialog(itemId: String?) {
|
||||||
|
selectedItemId.update { itemId }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun hideItemDialog() {
|
||||||
|
selectedItemId.update { null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -92,7 +92,8 @@ fun PurseDialog(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PurseContent(
|
private fun PurseContent(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
dialog: PurseDialogUio,
|
dialog: PurseDialogUio,
|
||||||
onConfirm: (PurseDialogUio) -> Unit,
|
onConfirm: (PurseDialogUio) -> Unit,
|
||||||
onSwapSign: (PurseDialogUio) -> Unit,
|
onSwapSign: (PurseDialogUio) -> Unit,
|
||||||
|
|
@ -119,7 +120,7 @@ fun PurseContent(
|
||||||
DecoratedBox {
|
DecoratedBox {
|
||||||
Surface {
|
Surface {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.padding(horizontal = 8.dp),
|
modifier = modifier.padding(horizontal = 8.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
|
verticalArrangement = Arrangement.spacedBy(space = 8.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
package com.pixelized.desktop.lwa.ui.composable.image
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.graphics.DefaultAlpha
|
||||||
|
import androidx.compose.ui.graphics.FilterQuality
|
||||||
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import coil3.compose.AsyncImage
|
||||||
|
import coil3.compose.AsyncImagePainter.Companion.DefaultTransform
|
||||||
|
import coil3.compose.AsyncImagePainter.State
|
||||||
|
import com.pixelized.desktop.lwa.utils.rememberBackgroundGradient
|
||||||
|
import com.pixelized.desktop.lwa.utils.rememberSaturationFilter
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DesaturatedAsyncImage(
|
||||||
|
model: Any?,
|
||||||
|
contentDescription: String?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
transform: (State) -> State = DefaultTransform,
|
||||||
|
onState: ((State) -> Unit)? = null,
|
||||||
|
alignment: Alignment = Alignment.Center,
|
||||||
|
contentScale: ContentScale = ContentScale.Fit,
|
||||||
|
alpha: Float = DefaultAlpha,
|
||||||
|
overlay: Brush? = rememberBackgroundGradient(),
|
||||||
|
colorFilter: ColorFilter? = rememberSaturationFilter(saturation = 0f),
|
||||||
|
filterQuality: FilterQuality = FilterQuality.Low,
|
||||||
|
clipToBounds: Boolean = true,
|
||||||
|
) {
|
||||||
|
Box(modifier = modifier) {
|
||||||
|
AsyncImage(
|
||||||
|
model = model,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
modifier = Modifier.matchParentSize(),
|
||||||
|
transform = transform,
|
||||||
|
onState = onState,
|
||||||
|
alignment = alignment,
|
||||||
|
contentScale = contentScale,
|
||||||
|
alpha = alpha,
|
||||||
|
colorFilter = colorFilter,
|
||||||
|
filterQuality = filterQuality,
|
||||||
|
clipToBounds = clipToBounds,
|
||||||
|
)
|
||||||
|
if (overlay != null) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.matchParentSize()
|
||||||
|
.background(brush = overlay)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,6 @@ import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
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.layout.width
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
|
|
@ -31,6 +30,8 @@ import androidx.compose.ui.Modifier
|
||||||
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
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialog
|
||||||
|
import com.pixelized.desktop.lwa.ui.composable.character.item.ItemDetailDialogViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialog
|
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialog
|
||||||
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogViewModel
|
import com.pixelized.desktop.lwa.ui.composable.character.purse.PurseDialogViewModel
|
||||||
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler
|
import com.pixelized.desktop.lwa.ui.composable.error.ErrorSnackHandler
|
||||||
|
|
@ -80,6 +81,7 @@ fun CharacterDetailInventory(
|
||||||
paddings: PaddingValues = CharacterDetailInventoryDefault.padding,
|
paddings: PaddingValues = CharacterDetailInventoryDefault.padding,
|
||||||
spacing: Dp = CharacterDetailInventoryDefault.spacing,
|
spacing: Dp = CharacterDetailInventoryDefault.spacing,
|
||||||
purseViewModel: PurseDialogViewModel = koinViewModel(),
|
purseViewModel: PurseDialogViewModel = koinViewModel(),
|
||||||
|
itemDetailDialogViewModel: ItemDetailDialogViewModel = koinViewModel(),
|
||||||
inventory: State<CharacterDetailInventoryUio?>,
|
inventory: State<CharacterDetailInventoryUio?>,
|
||||||
) {
|
) {
|
||||||
val blur = LocalBlurController.current
|
val blur = LocalBlurController.current
|
||||||
|
|
@ -96,6 +98,10 @@ fun CharacterDetailInventory(
|
||||||
onPurse = {
|
onPurse = {
|
||||||
blur.show()
|
blur.show()
|
||||||
purseViewModel.showPurseDialog(characterSheetId = it)
|
purseViewModel.showPurseDialog(characterSheetId = it)
|
||||||
|
},
|
||||||
|
onItem = {
|
||||||
|
blur.show()
|
||||||
|
itemDetailDialogViewModel.showItemDialog(itemId = it.itemId)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -119,6 +125,14 @@ fun CharacterDetailInventory(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ItemDetailDialog(
|
||||||
|
dialog = itemDetailDialogViewModel.itemDialog.collectAsState(),
|
||||||
|
onDismissRequest = {
|
||||||
|
blur.hide()
|
||||||
|
itemDetailDialogViewModel.hideItemDialog()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
ErrorSnackHandler(
|
ErrorSnackHandler(
|
||||||
error = purseViewModel.error,
|
error = purseViewModel.error,
|
||||||
)
|
)
|
||||||
|
|
@ -131,6 +145,7 @@ private fun CharacterDetailInventoryContent(
|
||||||
spacing: Dp,
|
spacing: Dp,
|
||||||
inventory: CharacterDetailInventoryUio,
|
inventory: CharacterDetailInventoryUio,
|
||||||
onPurse: (String) -> Unit,
|
onPurse: (String) -> Unit,
|
||||||
|
onItem: (InventoryItemUio) -> Unit,
|
||||||
) {
|
) {
|
||||||
Box(
|
Box(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
|
|
@ -191,7 +206,7 @@ private fun CharacterDetailInventoryContent(
|
||||||
.animateItem()
|
.animateItem()
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
item = it,
|
item = it,
|
||||||
onClick = { },
|
onClick = { onItem(it) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ class CharacterDetailInventoryFactory(
|
||||||
filter = filterField,
|
filter = filterField,
|
||||||
purse = inventory?.purse,
|
purse = inventory?.purse,
|
||||||
inventory = inventory?.items,
|
inventory = inventory?.items,
|
||||||
items = items.filterValues { it.metadata.name.unAccent().contains(filter, true) },
|
items = items.filterValues { it.metadata.label.unAccent().contains(filter, true) },
|
||||||
)
|
)
|
||||||
}.stateIn(
|
}.stateIn(
|
||||||
scope = scope,
|
scope = scope,
|
||||||
|
|
@ -78,10 +78,12 @@ class CharacterDetailInventoryFactory(
|
||||||
filter = filter,
|
filter = filter,
|
||||||
items = inventory
|
items = inventory
|
||||||
?.mapNotNull {
|
?.mapNotNull {
|
||||||
val label = items[it.itemId]?.metadata?.name ?: return@mapNotNull null
|
val item = items[it.itemId] ?: return@mapNotNull null
|
||||||
InventoryItemUio(
|
InventoryItemUio(
|
||||||
inventoryId = it.inventoryId,
|
inventoryId = it.inventoryId,
|
||||||
label = label,
|
itemId = it.itemId,
|
||||||
|
label = item.metadata.label,
|
||||||
|
count = it.count,
|
||||||
equipped = it.equipped,
|
equipped = it.equipped,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,16 @@
|
||||||
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.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.SizeTransform
|
||||||
|
import androidx.compose.animation.fadeIn
|
||||||
|
import androidx.compose.animation.fadeOut
|
||||||
|
import androidx.compose.animation.slideInVertically
|
||||||
|
import androidx.compose.animation.slideOutVertically
|
||||||
|
import androidx.compose.animation.togetherWith
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
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.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
|
@ -10,9 +19,13 @@ import androidx.compose.material.Text
|
||||||
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.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.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.pixelized.desktop.lwa.ui.theme.lwa
|
import com.pixelized.desktop.lwa.ui.theme.lwa
|
||||||
import com.pixelized.desktop.lwa.utils.extention.ribbon
|
import com.pixelized.desktop.lwa.utils.extention.ribbon
|
||||||
|
|
@ -20,20 +33,26 @@ import com.pixelized.desktop.lwa.utils.extention.ribbon
|
||||||
@Stable
|
@Stable
|
||||||
data class InventoryItemUio(
|
data class InventoryItemUio(
|
||||||
val inventoryId: String,
|
val inventoryId: String,
|
||||||
|
val itemId: String,
|
||||||
val label: String,
|
val label: String,
|
||||||
|
val count: Int,
|
||||||
val equipped: Boolean,
|
val equipped: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
object GMCharacterPreviewDefault {
|
object GMCharacterPreviewDefault {
|
||||||
@Stable
|
@Stable
|
||||||
val paddings = PaddingValues(horizontal = 16.dp)
|
val paddings = PaddingValues(horizontal = 16.dp, vertical = 4.dp)
|
||||||
|
|
||||||
|
@Stable
|
||||||
|
val spacing: Dp = 4.dp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun InventoryItem(
|
fun InventoryItem(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
padding: PaddingValues = GMCharacterPreviewDefault.paddings,
|
padding: PaddingValues = GMCharacterPreviewDefault.paddings,
|
||||||
|
spacing: Dp = GMCharacterPreviewDefault.spacing,
|
||||||
item: InventoryItemUio,
|
item: InventoryItemUio,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
) {
|
) {
|
||||||
|
|
@ -51,10 +70,39 @@ fun InventoryItem(
|
||||||
.minimumInteractiveComponentSize()
|
.minimumInteractiveComponentSize()
|
||||||
.padding(paddingValues = padding)
|
.padding(paddingValues = padding)
|
||||||
.then(other = modifier),
|
.then(other = modifier),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(space = spacing),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
|
modifier = Modifier.alignByBaseline(),
|
||||||
style = MaterialTheme.lwa.typography.base.body1,
|
style = MaterialTheme.lwa.typography.base.body1,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 1,
|
||||||
text = item.label,
|
text = item.label,
|
||||||
)
|
)
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = item.count > 1,
|
||||||
|
enter = fadeIn(),
|
||||||
|
exit = fadeOut(),
|
||||||
|
) {
|
||||||
|
AnimatedContent(
|
||||||
|
targetState = item.count,
|
||||||
|
transitionSpec = {
|
||||||
|
val prod = if (initialState < targetState) 1 else -1
|
||||||
|
val enter = fadeIn() + slideInVertically { -8 * prod }
|
||||||
|
val exit = fadeOut() + slideOutVertically { 8 * prod }
|
||||||
|
enter togetherWith exit using SizeTransform(clip = false)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.alignByBaseline(),
|
||||||
|
style = MaterialTheme.lwa.typography.base.body1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 1,
|
||||||
|
text = "x${it}",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,7 +2,9 @@ package com.pixelized.desktop.lwa.ui.screen.gamemaster.common.tag
|
||||||
|
|
||||||
import androidx.compose.animation.animateColorAsState
|
import androidx.compose.animation.animateColorAsState
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.Button
|
import androidx.compose.material.Button
|
||||||
|
|
@ -25,6 +27,7 @@ data class GMTagUio(
|
||||||
val id: String,
|
val id: String,
|
||||||
val label: String,
|
val label: String,
|
||||||
val highlight: Boolean,
|
val highlight: Boolean,
|
||||||
|
val meta: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
|
|
@ -52,16 +55,31 @@ fun GMTag(
|
||||||
shape = shape,
|
shape = shape,
|
||||||
elevation = elevation,
|
elevation = elevation,
|
||||||
) {
|
) {
|
||||||
Text(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clickable(enabled = onTag != null) { onTag?.invoke() }
|
.clickable(enabled = onTag != null) { onTag?.invoke() }
|
||||||
.padding(paddingValues = padding),
|
.padding(paddingValues = padding),
|
||||||
style = MaterialTheme.lwa.typography.base.caption,
|
horizontalArrangement = Arrangement.spacedBy(space = 1.dp),
|
||||||
color = animatedColor.value,
|
) {
|
||||||
overflow = TextOverflow.Ellipsis,
|
if (tag.meta) {
|
||||||
maxLines = 1,
|
Text(
|
||||||
text = tag.label,
|
modifier = Modifier.alignByBaseline(),
|
||||||
)
|
style = MaterialTheme.lwa.typography.base.caption,
|
||||||
|
color = animatedColor.value,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 1,
|
||||||
|
text = "⬫",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.alignByBaseline(),
|
||||||
|
style = MaterialTheme.lwa.typography.base.caption,
|
||||||
|
color = animatedColor.value,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 1,
|
||||||
|
text = tag.label,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -87,12 +105,26 @@ fun GMTagButton(
|
||||||
enabled = onTag != null,
|
enabled = onTag != null,
|
||||||
onClick = { onTag?.invoke() },
|
onClick = { onTag?.invoke() },
|
||||||
) {
|
) {
|
||||||
Text(
|
Row(
|
||||||
modifier = Modifier.padding(paddingValues = padding),
|
modifier = Modifier.padding(paddingValues = padding),
|
||||||
color = animatedColor.value,
|
horizontalArrangement = Arrangement.spacedBy(space = 1.dp),
|
||||||
overflow = TextOverflow.Ellipsis,
|
) {
|
||||||
maxLines = 1,
|
if (tag.meta) {
|
||||||
text = tag.label,
|
Text(
|
||||||
)
|
modifier = Modifier.alignByBaseline(),
|
||||||
|
color = animatedColor.value,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 1,
|
||||||
|
text = "⬫",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.alignByBaseline(),
|
||||||
|
color = animatedColor.value,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
maxLines = 1,
|
||||||
|
text = tag.label,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -15,6 +15,7 @@ class GMTagFactory {
|
||||||
id = tag.id,
|
id = tag.id,
|
||||||
label = tag.label,
|
label = tag.label,
|
||||||
highlight = selectedTagIds.contains(tag.id),
|
highlight = selectedTagIds.contains(tag.id),
|
||||||
|
meta = tag.meta,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.sortedWith(
|
.sortedWith(
|
||||||
|
|
@ -32,6 +33,7 @@ class GMTagFactory {
|
||||||
id = tag.id,
|
id = tag.id,
|
||||||
label = tag.label,
|
label = tag.label,
|
||||||
highlight = tag.id == selectedTagId,
|
highlight = tag.id == selectedTagId,
|
||||||
|
meta = tag.meta,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.sortedWith(
|
.sortedWith(
|
||||||
|
|
@ -47,6 +49,7 @@ class GMTagFactory {
|
||||||
id = tag.id,
|
id = tag.id,
|
||||||
label = tag.label,
|
label = tag.label,
|
||||||
highlight = tag.id == selectedTagId,
|
highlight = tag.id == selectedTagId,
|
||||||
|
meta = tag.meta,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -23,14 +23,14 @@ class GMItemEditFactory(
|
||||||
item: Item?,
|
item: Item?,
|
||||||
tags: Collection<Tag>,
|
tags: Collection<Tag>,
|
||||||
): GMItemEditPageUio {
|
): GMItemEditPageUio {
|
||||||
val idFlow = MutableStateFlow(item?.id ?: "")
|
val idFlow = createFlows(initialValue = item?.id ?: "")
|
||||||
val labelFlow = MutableStateFlow(item?.metadata?.name ?: "")
|
val labelFlow = createFlows(initialValue = item?.metadata?.label ?: "")
|
||||||
val descriptionFlow = MutableStateFlow(item?.metadata?.description ?: "")
|
val descriptionFlow = createFlows(initialValue = item?.metadata?.description ?: "")
|
||||||
val imageFlow = MutableStateFlow(item?.metadata?.image ?: "")
|
val imageFlow = createFlows(initialValue = item?.metadata?.image ?: "")
|
||||||
val thumbnailFlow = MutableStateFlow(item?.metadata?.thumbnail ?: "")
|
val thumbnailFlow = createFlows(initialValue = item?.metadata?.thumbnail ?: "")
|
||||||
val stackableFlow = MutableStateFlow(item?.options?.stackable ?: false)
|
val stackableFlow = MutableStateFlow(value = item?.options?.stackable ?: false)
|
||||||
val equipableFlow = MutableStateFlow(item?.options?.equipable ?: false)
|
val equipableFlow = MutableStateFlow(value = item?.options?.equipable ?: false)
|
||||||
val consumableFlow = MutableStateFlow(item?.options?.consumable ?: false)
|
val consumableFlow = MutableStateFlow(value = item?.options?.consumable ?: false)
|
||||||
|
|
||||||
val tagFlow = MutableStateFlow(
|
val tagFlow = MutableStateFlow(
|
||||||
tagFactory.convertToGMTagItemUio(
|
tagFactory.convertToGMTagItemUio(
|
||||||
|
|
@ -40,45 +40,21 @@ class GMItemEditFactory(
|
||||||
)
|
)
|
||||||
|
|
||||||
return GMItemEditPageUio(
|
return GMItemEditPageUio(
|
||||||
id = LwaTextFieldUio(
|
id = idFlow.createLwaTextField(
|
||||||
enable = originId == null,
|
enable = originId == null,
|
||||||
isError = MutableStateFlow(false),
|
|
||||||
label = getString(Res.string.game_master__item__edit_id),
|
label = getString(Res.string.game_master__item__edit_id),
|
||||||
valueFlow = idFlow,
|
|
||||||
placeHolder = null,
|
|
||||||
onValueChange = { idFlow.value = it },
|
|
||||||
),
|
),
|
||||||
label = LwaTextFieldUio(
|
label = labelFlow.createLwaTextField(
|
||||||
enable = true,
|
|
||||||
isError = MutableStateFlow(false),
|
|
||||||
label = getString(Res.string.game_master__item__edit_label),
|
label = getString(Res.string.game_master__item__edit_label),
|
||||||
valueFlow = labelFlow,
|
|
||||||
placeHolder = null,
|
|
||||||
onValueChange = { labelFlow.value = it },
|
|
||||||
),
|
),
|
||||||
description = LwaTextFieldUio(
|
description = descriptionFlow.createLwaTextField(
|
||||||
enable = true,
|
|
||||||
isError = MutableStateFlow(false),
|
|
||||||
label = getString(Res.string.game_master__item__edit_description),
|
label = getString(Res.string.game_master__item__edit_description),
|
||||||
valueFlow = descriptionFlow,
|
|
||||||
placeHolder = null,
|
|
||||||
onValueChange = { descriptionFlow.value = it },
|
|
||||||
),
|
),
|
||||||
image = LwaTextFieldUio(
|
image = imageFlow.createLwaTextField(
|
||||||
enable = true,
|
|
||||||
isError = MutableStateFlow(false),
|
|
||||||
label = getString(Res.string.game_master__item__edit_image),
|
label = getString(Res.string.game_master__item__edit_image),
|
||||||
valueFlow = imageFlow,
|
|
||||||
placeHolder = null,
|
|
||||||
onValueChange = { descriptionFlow.value = it },
|
|
||||||
),
|
),
|
||||||
thumbnail = LwaTextFieldUio(
|
thumbnail = thumbnailFlow.createLwaTextField(
|
||||||
enable = true,
|
|
||||||
isError = MutableStateFlow(false),
|
|
||||||
label = getString(Res.string.game_master__item__edit_thumbnail),
|
label = getString(Res.string.game_master__item__edit_thumbnail),
|
||||||
valueFlow = thumbnailFlow,
|
|
||||||
placeHolder = null,
|
|
||||||
onValueChange = { descriptionFlow.value = it },
|
|
||||||
),
|
),
|
||||||
equipable = LwaCheckBoxUio(
|
equipable = LwaCheckBoxUio(
|
||||||
checked = equipableFlow,
|
checked = equipableFlow,
|
||||||
|
|
@ -104,7 +80,7 @@ class GMItemEditFactory(
|
||||||
return Item(
|
return Item(
|
||||||
id = form.id.valueFlow.value,
|
id = form.id.valueFlow.value,
|
||||||
metadata = Item.MetaData(
|
metadata = Item.MetaData(
|
||||||
name = form.label.valueFlow.value,
|
label = form.label.valueFlow.value,
|
||||||
description = form.description.valueFlow.value,
|
description = form.description.valueFlow.value,
|
||||||
image = form.image.valueFlow.value,
|
image = form.image.valueFlow.value,
|
||||||
thumbnail = form.thumbnail.valueFlow.value,
|
thumbnail = form.thumbnail.valueFlow.value,
|
||||||
|
|
@ -120,4 +96,25 @@ class GMItemEditFactory(
|
||||||
alterations = emptyList(), // TODO,
|
alterations = emptyList(), // TODO,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createFlows(
|
||||||
|
initialValue: String = "",
|
||||||
|
initialError: Boolean = false,
|
||||||
|
): Pair<MutableStateFlow<String>, MutableStateFlow<Boolean>> {
|
||||||
|
return MutableStateFlow(value = initialValue) to MutableStateFlow(value = initialError)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Pair<MutableStateFlow<String>, MutableStateFlow<Boolean>>.createLwaTextField(
|
||||||
|
enable: Boolean = true,
|
||||||
|
label: String,
|
||||||
|
): LwaTextFieldUio {
|
||||||
|
return LwaTextFieldUio(
|
||||||
|
enable = enable,
|
||||||
|
isError = second,
|
||||||
|
label = label,
|
||||||
|
valueFlow = first,
|
||||||
|
placeHolder = null,
|
||||||
|
onValueChange = { first.value = it },
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -245,7 +245,7 @@ private fun GMItemEditContent(
|
||||||
.animateItem()
|
.animateItem()
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
field = it.image,
|
field = it.image,
|
||||||
singleLine = false,
|
singleLine = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item(
|
item(
|
||||||
|
|
@ -256,7 +256,7 @@ private fun GMItemEditContent(
|
||||||
.animateItem()
|
.animateItem()
|
||||||
.fillMaxWidth(),
|
.fillMaxWidth(),
|
||||||
field = it.thumbnail,
|
field = it.thumbnail,
|
||||||
singleLine = false,
|
singleLine = true,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
item(
|
item(
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ class GMItemFactory(
|
||||||
selectedTagId: String?,
|
selectedTagId: String?,
|
||||||
): List<Item> {
|
): List<Item> {
|
||||||
return items.filter {
|
return items.filter {
|
||||||
val matchName = it.metadata.name.unAccent().contains(
|
val matchName = it.metadata.label.unAccent().contains(
|
||||||
other = unAccentFilter,
|
other = unAccentFilter,
|
||||||
ignoreCase = true
|
ignoreCase = true
|
||||||
)
|
)
|
||||||
|
|
@ -35,7 +35,7 @@ class GMItemFactory(
|
||||||
.map { item ->
|
.map { item ->
|
||||||
GMItemUio(
|
GMItemUio(
|
||||||
itemId = item.id,
|
itemId = item.id,
|
||||||
label = item.metadata.name,
|
label = item.metadata.label,
|
||||||
tags = item.tags.mapNotNull {
|
tags = item.tags.mapNotNull {
|
||||||
tags[it]?.let { tag ->
|
tags[it]?.let { tag ->
|
||||||
tagFactory.convertToGMTagItemUio(
|
tagFactory.convertToGMTagItemUio(
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.DpSize
|
import androidx.compose.ui.unit.DpSize
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
|
||||||
|
@Stable
|
||||||
data class LwaSize(
|
data class LwaSize(
|
||||||
val portrait: Portrait,
|
val portrait: Portrait,
|
||||||
val sheet: Sheet,
|
val sheet: Sheet,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,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.ui.graphics.Brush
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberBackgroundGradient(
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.pixelized.desktop.lwa.utils
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.graphics.ColorMatrix
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun rememberSaturationFilter(
|
||||||
|
saturation: Float = 0f,
|
||||||
|
): ColorFilter {
|
||||||
|
return remember(saturation) {
|
||||||
|
ColorFilter.colorMatrix(
|
||||||
|
ColorMatrix().also { it.setToSaturation(saturation) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -80,7 +80,7 @@ class ItemStore(
|
||||||
throw JsonConversionException(root = exception)
|
throw JsonConversionException(root = exception)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?.sortedWith(compareBy(Collator.getInstance()) { it.metadata.name })
|
?.sortedWith(compareBy(Collator.getInstance()) { it.metadata.label })
|
||||||
?: emptyList()
|
?: emptyList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -113,7 +113,7 @@ class ItemStore(
|
||||||
code = APIResponse.ErrorCode.ItemId,
|
code = APIResponse.ErrorCode.ItemId,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (item.metadata.name.isEmpty()) {
|
if (item.metadata.label.isEmpty()) {
|
||||||
throw BusinessException(
|
throw BusinessException(
|
||||||
message = "Item 'name' is a mandatory field.",
|
message = "Item 'name' is a mandatory field.",
|
||||||
code = APIResponse.ErrorCode.ItemName,
|
code = APIResponse.ErrorCode.ItemName,
|
||||||
|
|
@ -146,7 +146,7 @@ class ItemStore(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.sortedWith(compareBy(Collator.getInstance()) {
|
.sortedWith(compareBy(Collator.getInstance()) {
|
||||||
it.metadata.name
|
it.metadata.label
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ class ItemStore(
|
||||||
item.removeIf { it.id == id }
|
item.removeIf { it.id == id }
|
||||||
}
|
}
|
||||||
.sortedWith(compareBy(Collator.getInstance()) {
|
.sortedWith(compareBy(Collator.getInstance()) {
|
||||||
it.metadata.name
|
it.metadata.label
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ data class Item(
|
||||||
val alterations: List<String>,
|
val alterations: List<String>,
|
||||||
) {
|
) {
|
||||||
data class MetaData(
|
data class MetaData(
|
||||||
val name: String,
|
val label: String,
|
||||||
val description: String,
|
val description: String,
|
||||||
val thumbnail: String?,
|
val thumbnail: String?,
|
||||||
val image: String?,
|
val image: String?,
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ class ItemJsonFactoryV1 {
|
||||||
return Item(
|
return Item(
|
||||||
id = json.id,
|
id = json.id,
|
||||||
metadata = Item.MetaData(
|
metadata = Item.MetaData(
|
||||||
name = json.metadata.name,
|
label = json.metadata.name,
|
||||||
description = json.metadata.description,
|
description = json.metadata.description,
|
||||||
image = json.metadata.image,
|
image = json.metadata.image,
|
||||||
thumbnail = json.metadata.thumbnail,
|
thumbnail = json.metadata.thumbnail,
|
||||||
|
|
@ -28,7 +28,7 @@ class ItemJsonFactoryV1 {
|
||||||
return ItemJsonV1(
|
return ItemJsonV1(
|
||||||
id = item.id,
|
id = item.id,
|
||||||
metadata = ItemJsonV1.ItemMetadataJsonV1(
|
metadata = ItemJsonV1.ItemMetadataJsonV1(
|
||||||
name = item.metadata.name,
|
name = item.metadata.label,
|
||||||
description = item.metadata.description,
|
description = item.metadata.description,
|
||||||
image = item.metadata.image,
|
image = item.metadata.image,
|
||||||
thumbnail = item.metadata.thumbnail,
|
thumbnail = item.metadata.thumbnail,
|
||||||
|
|
|
||||||
|
|
@ -3,4 +3,5 @@ package com.pixelized.shared.lwa.model.tag
|
||||||
data class Tag(
|
data class Tag(
|
||||||
val id: String,
|
val id: String,
|
||||||
val label: String,
|
val label: String,
|
||||||
|
val meta: Boolean,
|
||||||
)
|
)
|
||||||
|
|
@ -9,6 +9,7 @@ class TagJsonFactory {
|
||||||
is TagJsonV1 -> Tag(
|
is TagJsonV1 -> Tag(
|
||||||
id = json.id,
|
id = json.id,
|
||||||
label = json.label,
|
label = json.label,
|
||||||
|
meta = json.meta ?: false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -19,6 +20,7 @@ class TagJsonFactory {
|
||||||
return TagJsonV1(
|
return TagJsonV1(
|
||||||
id = tag.id,
|
id = tag.id,
|
||||||
label = tag.label,
|
label = tag.label,
|
||||||
|
meta = tag.meta.takeIf { it },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,4 +6,5 @@ import kotlinx.serialization.Serializable
|
||||||
data class TagJsonV1(
|
data class TagJsonV1(
|
||||||
override val id: String,
|
override val id: String,
|
||||||
val label: String,
|
val label: String,
|
||||||
|
val meta: Boolean?,
|
||||||
) : TagJson
|
) : TagJson
|
||||||
Loading…
Add table
Add a link
Reference in a new issue