Add haptic feedback (thx Jérémy). better handling of removal animation.
This commit is contained in:
parent
b27149edaf
commit
2c5337f3dc
6 changed files with 58 additions and 15 deletions
|
|
@ -62,9 +62,10 @@ class InventoryFactory @Inject constructor() {
|
|||
items: Map<String, Item>,
|
||||
fires: List<FireItem>,
|
||||
order: Map<String, Int>,
|
||||
parent: Map<String, String?>,
|
||||
): Map<String?, List<Any>> {
|
||||
return fires
|
||||
.groupBy { it.parentId }
|
||||
.groupBy { parent[it.id] }
|
||||
.mapValues { (_, fires) ->
|
||||
fires
|
||||
.asSequence()
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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<Map<String, Int>>(emptyMap())
|
||||
private val parentOverrider = MutableStateFlow<Map<String, String?>>(emptyMap())
|
||||
private val _selectedContainerId = MutableStateFlow<String?>(null)
|
||||
|
||||
private val _containers: StateFlow<List<InventoryContainerUio>> = 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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
BIN
app/src/main/res/drawable/ic_drive_bear_trap.webp
Normal file
BIN
app/src/main/res/drawable/ic_drive_bear_trap.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
BIN
app/src/main/res/drawable/ic_drive_chalk_stick.webp
Normal file
BIN
app/src/main/res/drawable/ic_drive_chalk_stick.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Loading…
Add table
Add a link
Reference in a new issue