From 1ebcb02f0a9e58e1af4f3838f073d3de2e48e4b8 Mon Sep 17 00:00:00 2001 From: darksnake Date: Mon, 28 Nov 2022 07:56:15 +0300 Subject: [PATCH] More robust drag API and implementation --- gradle.properties | 4 +- .../sciprog/maps/compose/MapFeaturesState.kt | 47 +++++++++++++++---- .../center/sciprog/maps/compose/MapView.kt | 17 +++---- .../center/sciprog/maps/compose/MapViewJvm.kt | 7 +-- 4 files changed, 48 insertions(+), 27 deletions(-) diff --git a/gradle.properties b/gradle.properties index 53180c4..5d580af 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,8 @@ kotlin.code.style=official -compose.version=1.2.0 +compose.version=1.2.1 agp.version=4.2.2 android.useAndroidX=true -toolsVersion=0.13.1-kotlin-1.7.20 \ No newline at end of file +toolsVersion=0.13.3-kotlin-1.7.20 \ No newline at end of file diff --git a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapFeaturesState.kt b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapFeaturesState.kt index e118d88..3f1943e 100644 --- a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapFeaturesState.kt +++ b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapFeaturesState.kt @@ -14,7 +14,7 @@ import center.sciprog.maps.coordinates.* public typealias FeatureId = String -public object DraggableAttribute : MapFeaturesState.Attribute +public object DraggableAttribute : MapFeaturesState.Attribute public class MapFeaturesState internal constructor( private val features: MutableMap, @@ -23,10 +23,25 @@ public class MapFeaturesState internal constructor( public interface Attribute //TODO use context receiver for that - public fun FeatureId.draggable(enabled: Boolean = true) { - setAttribute(this, DraggableAttribute, enabled) + public fun FeatureId.draggable( + //TODO add constraints + callback: DragHandle = DragHandle.BYPASS + ) { + val handle = DragHandle.withPrimaryButton { event, start, end -> + val feature = features[this] as? DraggableMapFeature ?: return@withPrimaryButton true + val boundingBox = feature.getBoundingBox(start.zoom) ?: return@withPrimaryButton true + if (start.focus in boundingBox) { + addFeature(this, feature.withCoordinates(end.focus)) + callback.handle(event, start, end) + false + } else { + true + } + } + setAttribute(this, DraggableAttribute, handle) } + public fun features(): Map = features @@ -42,17 +57,31 @@ public class MapFeaturesState internal constructor( attributes.getOrPut(id) { mutableStateMapOf() }[key] = value } + public fun removeAttribute(id: FeatureId, key: Attribute<*>) { + attributes[id]?.remove(key) + } + @Suppress("UNCHECKED_CAST") public fun getAttribute(id: FeatureId, key: Attribute): T? = attributes[id]?.get(key)?.let { it as T } - @Suppress("UNCHECKED_CAST") - public fun findAllWithAttribute(key: Attribute, condition: (T) -> Boolean): Set { - return attributes.filterValues { - condition(it[key] as T) - }.keys +// @Suppress("UNCHECKED_CAST") +// public fun findAllWithAttribute(key: Attribute, condition: (T) -> Boolean): Set { +// return attributes.filterValues { +// condition(it[key] as T) +// }.keys +// } + + public fun forEachWithAttribute(key: Attribute, block: (id: FeatureId, attributeValue: T) -> Unit) { + attributes.forEach { (id, attributeMap) -> + attributeMap[key]?.let { + @Suppress("UNCHECKED_CAST") + block(id, it as T) + } + } } - public companion object{ + + public companion object { /** * Build, but do not remember map feature state diff --git a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt index 825cbc3..8f9fcf9 100644 --- a/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt +++ b/maps-kt-compose/src/commonMain/kotlin/center/sciprog/maps/compose/MapView.kt @@ -37,7 +37,7 @@ public fun interface DragHandle { if (event.buttons.isPrimaryPressed) { block(event, start, end) } else { - false + true } } @@ -145,17 +145,12 @@ public fun MapView( ?: MapViewPoint.globe } - val featureDrag = DragHandle.withPrimaryButton { _, start, end -> - val zoom = start.zoom - featureState.findAllWithAttribute(DraggableAttribute) { it }.forEach { id -> - val feature = features[id] as? DraggableMapFeature ?: return@forEach - val boundingBox = feature.getBoundingBox(zoom) ?: return@forEach - if (start.focus in boundingBox) { - featureState.addFeature(id, feature.withCoordinates(end.focus)) - return@withPrimaryButton false - } + val featureDrag: DragHandle = DragHandle.withPrimaryButton { event, start, end -> + var bypass = true + featureState.forEachWithAttribute(DraggableAttribute) { _, handle -> + bypass = bypass and handle.handle(event, start, end) } - return@withPrimaryButton true + bypass } diff --git a/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/MapViewJvm.kt b/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/MapViewJvm.kt index 5288a1a..4e8ba25 100644 --- a/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/MapViewJvm.kt +++ b/maps-kt-compose/src/jvmMain/kotlin/center/sciprog/maps/compose/MapViewJvm.kt @@ -112,11 +112,8 @@ public actual fun MapView( drag(change.id) { dragChange -> val dragAmount = dragChange.position - dragChange.previousPosition - val dpStart = DpOffset( - dragChange.previousPosition.x.toDp(), - dragChange.previousPosition.y.toDp() - ) - val dpEnd = DpOffset(dragChange.position.x.toDp(), dragChange.position.y.toDp()) + val dpStart = dragChange.previousPosition.toDpOffset() + val dpEnd = dragChange.position.toDpOffset() //apply drag handle and check if it prohibits the drag even propagation if (