1 /* 2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.compose.ui.draganddrop 18 19 import android.view.DragEvent 20 import android.view.View 21 import androidx.collection.ArraySet 22 import androidx.compose.ui.Modifier 23 import androidx.compose.ui.geometry.Offset 24 import androidx.compose.ui.geometry.Size 25 import androidx.compose.ui.graphics.drawscope.DrawScope 26 import androidx.compose.ui.node.ModifierNodeElement 27 import androidx.compose.ui.platform.InspectorInfo 28 29 /** A Class that provides access [View.OnDragListener] APIs for a [DragAndDropNode]. */ 30 internal class AndroidDragAndDropManager( 31 private val startDrag: 32 ( 33 transferData: DragAndDropTransferData, 34 decorationSize: Size, 35 drawDragDecoration: DrawScope.() -> Unit 36 ) -> Boolean 37 ) : View.OnDragListener, DragAndDropManager { 38 39 private val rootDragAndDropNode = DragAndDropNode() 40 41 /** 42 * A collection [DragAndDropNode] instances that registered interested in a drag and drop 43 * session by returning true in [DragAndDropNode.onStarted]. 44 */ 45 private val interestedTargets = ArraySet<DragAndDropTarget>() 46 47 override val modifier: Modifier = 48 object : ModifierNodeElement<DragAndDropNode>() { createnull49 override fun create() = rootDragAndDropNode 50 51 override fun update(node: DragAndDropNode) = Unit 52 53 override fun InspectorInfo.inspectableProperties() { 54 name = "RootDragAndDropNode" 55 } 56 hashCodenull57 override fun hashCode(): Int = rootDragAndDropNode.hashCode() 58 59 override fun equals(other: Any?) = other === this 60 } 61 62 override val isRequestDragAndDropTransferRequired: Boolean 63 get() = true 64 65 override fun requestDragAndDropTransfer(node: DragAndDropNode, offset: Offset) { 66 var isTransferStarted = false 67 val dragAndDropSourceScope = 68 object : DragAndDropStartTransferScope { 69 override fun startDragAndDropTransfer( 70 transferData: DragAndDropTransferData, 71 decorationSize: Size, 72 drawDragDecoration: DrawScope.() -> Unit 73 ): Boolean { 74 isTransferStarted = 75 startDrag( 76 transferData, 77 decorationSize, 78 drawDragDecoration, 79 ) 80 return isTransferStarted 81 } 82 } 83 with(node) { dragAndDropSourceScope.startDragAndDropTransfer(offset) { isTransferStarted } } 84 } 85 onDragnull86 override fun onDrag(view: View, event: DragEvent): Boolean { 87 val dragAndDropEvent = DragAndDropEvent(dragEvent = event) 88 return when (event.action) { 89 DragEvent.ACTION_DRAG_STARTED -> { 90 val accepted = rootDragAndDropNode.acceptDragAndDropTransfer(dragAndDropEvent) 91 interestedTargets.forEach { it.onStarted(dragAndDropEvent) } 92 accepted 93 } 94 DragEvent.ACTION_DROP -> { 95 rootDragAndDropNode.onDrop(dragAndDropEvent) 96 } 97 DragEvent.ACTION_DRAG_ENTERED -> { 98 rootDragAndDropNode.onEntered(dragAndDropEvent) 99 false 100 } 101 DragEvent.ACTION_DRAG_LOCATION -> { 102 rootDragAndDropNode.onMoved(dragAndDropEvent) 103 false 104 } 105 DragEvent.ACTION_DRAG_EXITED -> { 106 rootDragAndDropNode.onExited(dragAndDropEvent) 107 false 108 } 109 DragEvent.ACTION_DRAG_ENDED -> { 110 rootDragAndDropNode.onEnded(dragAndDropEvent) 111 interestedTargets.clear() 112 false 113 } 114 else -> false 115 } 116 } 117 registerTargetInterestnull118 override fun registerTargetInterest(target: DragAndDropTarget) { 119 interestedTargets.add(target) 120 } 121 isInterestedTargetnull122 override fun isInterestedTarget(target: DragAndDropTarget): Boolean { 123 return interestedTargets.contains(target) 124 } 125 } 126