diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryFactory.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryFactory.kt index c52ef6f..442860e 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryFactory.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryFactory.kt @@ -62,9 +62,10 @@ class InventoryFactory @Inject constructor() { items: Map, fires: List, order: Map, + parent: Map, ): Map> { return fires - .groupBy { it.parentId } + .groupBy { parent[it.id] } .mapValues { (_, fires) -> fires .asSequence() diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryPage.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryPage.kt index cde397b..aab401b 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryPage.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryPage.kt @@ -31,6 +31,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer +import androidx.compose.ui.platform.LocalHapticFeedback import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp @@ -70,6 +71,7 @@ fun InventoryPage( containerWidth: Dp = 64.dp, ) { val overlay = LocalRollOverlay.current + val feedback = LocalHapticFeedback.current val scope = rememberCoroutineScope() val selectedContainer = inventoryViewModel.selectedContainer @@ -78,10 +80,16 @@ fun InventoryPage( val dragDropState = rememberInventoryDragDropState( containerWidth = containerWidth, - isItemDraggable = inventoryViewModel::isItemDraggable, + isItemDraggable = { + inventoryViewModel.isItemDraggable(it, feedback) + }, isItemsMovable = inventoryViewModel::isItemsMovable, - onItemMove = inventoryViewModel::onItemMove, - onItemRelease = inventoryViewModel::onItemRelease, + onItemMove = { from, to -> + inventoryViewModel.onItemMove(from, to, feedback) + }, + onItemRelease = { from, to -> + inventoryViewModel.onItemRelease(from, to, feedback) + }, onItemLongClick = { // on container long press we want to display the detail dialog. if (it.type == Type.CONTAINER) { diff --git a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryViewModel.kt b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryViewModel.kt index d53e2b0..2a359c5 100644 --- a/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryViewModel.kt +++ b/app/src/main/java/com/pixelized/rplexicon/ui/screens/character/pages/inventory/InventoryViewModel.kt @@ -5,6 +5,8 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.State import androidx.compose.runtime.collectAsState +import androidx.compose.ui.hapticfeedback.HapticFeedback +import androidx.compose.ui.hapticfeedback.HapticFeedbackType import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope @@ -41,6 +43,7 @@ class InventoryViewModel @Inject constructor( private val character = savedStateHandle.characterSheetArgument.name private val orderOverrider = MutableStateFlow>(emptyMap()) + private val parentOverrider = MutableStateFlow>(emptyMap()) private val _selectedContainerId = MutableStateFlow(null) private val _containers: StateFlow> = combine( @@ -77,6 +80,7 @@ class InventoryViewModel @Inject constructor( itemRepository.data, fireRepository.getInventory(character), orderOverrider, + parentOverrider, transform = inventoryFactory::fromModelsToItemUio, ).stateIn( scope = viewModelScope, @@ -88,6 +92,24 @@ class InventoryViewModel @Inject constructor( @Stable get() = _items.collectAsState() + + init { + viewModelScope.launch { + launch(Dispatchers.Default) { + // Listen to fire repository to update the orderOverrider as soon as firebase is updated. + fireRepository.getInventory(character = character).collect { fires -> + orderOverrider.value = fires.associate { fire -> fire.id to fire.order } + } + } + launch(Dispatchers.Default) { + // Listen to fire repository to update the orderOverrider as soon as firebase is updated. + fireRepository.getInventory(character = character).collect { fires -> + parentOverrider.value = fires.associate { fire -> fire.id to fire.parentId } + } + } + } + } + fun getItem(element: Element): Any? { return when (element.type) { Type.CONTAINER -> _containers.value.getOrNull(element.index) @@ -99,11 +121,17 @@ class InventoryViewModel @Inject constructor( _selectedContainerId.value = id } - fun isItemDraggable(element: Element): Boolean { + fun isItemDraggable(element: Element, feedback: HapticFeedback): Boolean { Log.d("InventoryViewModel", "isItemDraggable(element:${element}") return when (val item = getItem(element = element)) { - is InventoryItemUio -> true - is InventoryContainerUio -> item.id != null + is InventoryItemUio -> { + feedback.performHapticFeedback(HapticFeedbackType.LongPress) + true + } + is InventoryContainerUio -> { + feedback.performHapticFeedback(HapticFeedbackType.LongPress) + item.id != null + } else -> false } } @@ -135,7 +163,7 @@ class InventoryViewModel @Inject constructor( } } - fun onItemMove(from: Element, to: Element) { + fun onItemMove(from: Element, to: Element, feedback: HapticFeedback) { if (from != to) { Log.d("InventoryViewModel", "onItemMove(from:${from}, to:${to})") val fromItem: Any? = getItem(element = from) @@ -146,6 +174,8 @@ class InventoryViewModel @Inject constructor( val refFromItem = itemRepository.find(id = fromItem.id) val refToItem = itemRepository.find(id = toItem.id) if (refFromItem?.type != null && refFromItem.type == refToItem?.type) { + // perform feedback + feedback.performHapticFeedback(HapticFeedbackType.TextHandleMove) // reorder locally orderOverrider.value = orderOverrider.value.toMutableMap().also { it[fromItem.id] = toItem.order @@ -168,6 +198,8 @@ class InventoryViewModel @Inject constructor( val refFromItem = itemRepository.find(id = fromItem.id) val refToItem = itemRepository.find(id = toItem.id) if (refFromItem?.type != null && refFromItem.type == refToItem?.type) { + // perform feedback + feedback.performHapticFeedback(HapticFeedbackType.TextHandleMove) // reorder locally orderOverrider.value = orderOverrider.value.toMutableMap().also { it[fromItem.id] = toItem.order @@ -189,9 +221,7 @@ class InventoryViewModel @Inject constructor( } } - fun onItemRelease(from: Element, to: Element) { - // clean the order override map, this is only needed when moving items around. - orderOverrider.value = emptyMap() + fun onItemRelease(from: Element, to: Element, feedback: HapticFeedback) { // only do something when an item is release on top of a container. if (from.type == Type.ITEM && to.type == Type.CONTAINER) { // fetch the itemId & containerId. @@ -215,7 +245,12 @@ class InventoryViewModel @Inject constructor( val typedOrderContainerFires = fires.filter { typedItems[it.id] != null && it.parentId == containerId } - + parentOverrider.value = parentOverrider.value.toMutableMap().also { override -> + override[fire.id] = containerId + } + // perform feedback + feedback.performHapticFeedback(HapticFeedbackType.TextHandleMove) + // update the data layer. viewModelScope.launch(Dispatchers.IO) { // remove the item from the list fireRepository.removeItem( @@ -247,9 +282,6 @@ class InventoryViewModel @Inject constructor( defaultParentId: String? = _selectedContainerId.value, quantity: Int, ) { - // clean the order override map, this is only needed when moving items around. - orderOverrider.value = emptyMap() - val item = itemRepository.find(id = itemId) // check the new quantity to decide if we update or remove the item diff --git a/app/src/main/java/com/pixelized/rplexicon/utilitary/ImageCache.kt b/app/src/main/java/com/pixelized/rplexicon/utilitary/ImageCache.kt index d1bf243..f5a077f 100644 --- a/app/src/main/java/com/pixelized/rplexicon/utilitary/ImageCache.kt +++ b/app/src/main/java/com/pixelized/rplexicon/utilitary/ImageCache.kt @@ -106,12 +106,14 @@ object ImageCache { "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=1FX7HpnxLUXFPqrKGvCYyJNkUSwFacKh9" to R.drawable.ic_silver_coin_pile_unfaded, "https://drive.google.com/uc?export=view&id=1jJkltHU5HzCuU5ixVly_J5Dr0stEawEV" to R.drawable.ic_drive_deck_of_card, + "https://drive.google.com/uc?export=view&id=1JhUikzOesAyGCtCL9bFW_HRdqM8hj1sf" to R.drawable.ic_drive_bear_trap, "https://drive.google.com/uc?export=view&id=1Jo0Nk_Mj4j-VKvBe0W6_73uE_tKUgPUF" to R.drawable.ic_drive_kitsune, "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=1KVXSKHI8JgU1Wnhp9rmEZ1f4rsUfoV2a" to R.drawable.ic_gold_coin_pile_unfaded, "https://drive.google.com/uc?export=view&id=1lLu7o1h1pkXuNRbHJ2dnxQLKyrNRxV3P" to R.drawable.ic_drive_bear_claw_neckless, "https://drive.google.com/uc?export=view&id=1nazdbGFLyiGNMYvPhVXiZoeyBxDtYMtI" to R.drawable.ic_electrum_coin_pile_unfaded, "https://drive.google.com/uc?export=view&id=1p5OSYPeeKa-niiTa9GFChdpnu0FqkswG" to R.drawable.ic_drive_harlequin, + "https://drive.google.com/uc?export=view&id=1TDTCkVZb520gdndC4FmAneWDGgf9wmDM" to R.drawable.ic_drive_chalk_stick, "https://drive.google.com/uc?export=view&id=1PlhfW61aSncyX3Ml1oPDPokHTR7U8O2y" to R.drawable.ic_drive_quiver, "https://drive.google.com/uc?export=view&id=1WSpydN6AVjQrS6J_F8EFT00McQqCCxCw" to R.drawable.ic_drive_stake, "https://drive.google.com/uc?export=view&id=1ywDHw0C6exwxNCu-qNgQ0X2Sx9LfqSNH" to R.drawable.ic_drive_bird_skull, diff --git a/app/src/main/res/drawable/ic_drive_bear_trap.webp b/app/src/main/res/drawable/ic_drive_bear_trap.webp new file mode 100644 index 0000000..2c8a3f1 Binary files /dev/null and b/app/src/main/res/drawable/ic_drive_bear_trap.webp differ diff --git a/app/src/main/res/drawable/ic_drive_chalk_stick.webp b/app/src/main/res/drawable/ic_drive_chalk_stick.webp new file mode 100644 index 0000000..d69537c Binary files /dev/null and b/app/src/main/res/drawable/ic_drive_chalk_stick.webp differ