diff --git a/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotationManager.kt b/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotationManager.kt index 412169566..cf1ddc039 100644 --- a/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotationManager.kt +++ b/android/src/main/java/com/rnmapbox/rnmbx/components/annotation/RNMBXPointAnnotationManager.kt @@ -78,6 +78,15 @@ class RNMBXPointAnnotationManager(reactApplicationContext: ReactApplicationConte annotation.setAnchor(mapValue.getDouble("x").toFloat(), mapValue.getDouble("y").toFloat()) } + override fun setSelected( + annotation: RNMBXPointAnnotation, + value: Dynamic? + ) { + value?.let { + annotation.isSelected = it.asBoolean() + } + } + @ReactProp(name = "draggable") override fun setDraggable(annotation: RNMBXPointAnnotation, draggable: Dynamic) { annotation.setDraggable(draggable.asBoolean()) diff --git a/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXPointAnnotationManagerDelegate.java b/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXPointAnnotationManagerDelegate.java index 950dc3b15..4dafe0dbe 100644 --- a/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXPointAnnotationManagerDelegate.java +++ b/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXPointAnnotationManagerDelegate.java @@ -35,6 +35,9 @@ public void setProperty(T view, String propName, @Nullable Object value) { case "anchor": mViewManager.setAnchor(view, new DynamicFromObject(value)); break; + case "selected": + mViewManager.setSelected(view, new DynamicFromObject(value)); + break; default: super.setProperty(view, propName, value); } diff --git a/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXPointAnnotationManagerInterface.java b/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXPointAnnotationManagerInterface.java index 3fac103d2..395accc45 100644 --- a/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXPointAnnotationManagerInterface.java +++ b/android/src/main/old-arch/com/facebook/react/viewmanagers/RNMBXPointAnnotationManagerInterface.java @@ -16,4 +16,5 @@ public interface RNMBXPointAnnotationManagerInterface { void setDraggable(T view, Dynamic value); void setId(T view, Dynamic value); void setAnchor(T view, Dynamic value); + void setSelected(T view, Dynamic value); } diff --git a/ios/RNMBX/RNMBXMapView.swift b/ios/RNMBX/RNMBXMapView.swift index bd59417ab..81511621c 100644 --- a/ios/RNMBX/RNMBXMapView.swift +++ b/ios/RNMBX/RNMBXMapView.swift @@ -1522,6 +1522,19 @@ class RNMBXPointAnnotationManager : AnnotationInteractionDelegate { // We handle taps ourselfs // onTap(annotations: annotations) } + + func selected(pointAnnotation: RNMBXPointAnnotation) { + if (selected != nil) { + deselectCurrentlySelected(deselectAnnotationOnTap: false) + } + selected = pointAnnotation + } + + func unselected(pointAnnotation: RNMBXPointAnnotation) { + if (selected == pointAnnotation) { + deselectCurrentlySelected(deselectAnnotationOnTap: false) + } + } func deselectCurrentlySelected(deselectAnnotationOnTap: Bool = false) -> Bool { if let selected = selected { @@ -1754,6 +1767,7 @@ class RNMBXPointAnnotationManager : AnnotationInteractionDelegate { #endif func add(_ annotation: PointAnnotation, _ rnmbxPointAnnotation: RNMBXPointAnnotation) { + rnmbxPointAnnotation.manager = self manager.annotations.append(annotation) manager.refresh() #if RNMBX_11 diff --git a/ios/RNMBX/RNMBXPointAnnotation.swift b/ios/RNMBX/RNMBXPointAnnotation.swift index fbe524cca..8ffd02dd2 100644 --- a/ios/RNMBX/RNMBXPointAnnotation.swift +++ b/ios/RNMBX/RNMBXPointAnnotation.swift @@ -10,6 +10,8 @@ final class WeakRef { } @objc public class RNMBXPointAnnotation : RNMBXInteractiveElement { + weak var manager:RNMBXPointAnnotationManager? = nil + static let key = "RNMBXPointAnnotation" static var gid = 0; @@ -26,12 +28,29 @@ public class RNMBXPointAnnotation : RNMBXInteractiveElement { var image : UIImage? = nil var reactSubviews : [UIView] = [] - @objc public var onDeselected: RCTBubblingEventBlock? = nil @objc public var onDrag: RCTBubblingEventBlock? = nil @objc public var onDragEnd: RCTBubblingEventBlock? = nil @objc public var onSelected: RCTBubblingEventBlock? = nil + private var selected: Bool? = nil { + didSet { + update { annotation in + if let selected = selected { + annotation.isSelected = selected + } + } + } + } + + @objc public func setReactSelected(_ _selected: Bool) { + if (_selected == true && self.selected != true) { + manager?.selected(pointAnnotation: self) + } else if (_selected == false && self.selected == true) { + manager?.unselected(pointAnnotation: self) + } + } + @objc public var coordinate : String? { didSet { _updateCoordinate() @@ -173,6 +192,7 @@ public class RNMBXPointAnnotation : RNMBXInteractiveElement { } func doSelect() { + self.selected = true let event = makeEvent(isSelect: true) if let onSelected = onSelected { onSelected(event.toJSON()) @@ -181,6 +201,7 @@ public class RNMBXPointAnnotation : RNMBXInteractiveElement { } func doDeselect(deselectAnnotationOnMapTap: Bool = false) { + self.selected = false let event = makeEvent(isSelect: false, deselectAnnotationOnMapTap: deselectAnnotationOnMapTap) if let onDeselected = onDeselected { onDeselected(event.toJSON()) diff --git a/ios/RNMBX/RNMBXPointAnnotationComponentView.mm b/ios/RNMBX/RNMBXPointAnnotationComponentView.mm index cc8c07c4f..e2c4b566b 100644 --- a/ios/RNMBX/RNMBXPointAnnotationComponentView.mm +++ b/ios/RNMBX/RNMBXPointAnnotationComponentView.mm @@ -11,6 +11,8 @@ #import #import +#import "RNMBXFabricPropConvert.h" + using namespace facebook::react; @interface RNMBXPointAnnotationComponentView () @@ -122,23 +124,26 @@ - (void)unmountChildComponentView:(UIView *)childCompo - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps { - const auto &newProps = static_cast(*props); - id coordinate = RNMBXConvertFollyDynamicToId(newProps.coordinate); + const auto &newViewProps = static_cast(*props); + const auto &oldViewProps = static_cast(*oldProps); + id coordinate = RNMBXConvertFollyDynamicToId(newViewProps.coordinate); if (coordinate != nil) { _view.coordinate = coordinate; } - id draggable = RNMBXConvertFollyDynamicToId(newProps.draggable); + id draggable = RNMBXConvertFollyDynamicToId(newViewProps.draggable); if (draggable != nil) { _view.draggable = draggable; } - id idx = RNMBXConvertFollyDynamicToId(newProps.id); + id idx = RNMBXConvertFollyDynamicToId(newViewProps.id); if (idx != nil) { _view.id = idx; } - id anchor = RNMBXConvertFollyDynamicToId(newProps.anchor); + id anchor = RNMBXConvertFollyDynamicToId(newViewProps.anchor); if (anchor != nil) { _view.anchor = anchor; } + + RNMBX_REMAP_OPTIONAL_PROP_BOOL(selected, reactSelected); [super updateProps:props oldProps:oldProps]; } diff --git a/src/specs/RNMBXPointAnnotationNativeComponent.ts b/src/specs/RNMBXPointAnnotationNativeComponent.ts index be373c471..a74ddb979 100644 --- a/src/specs/RNMBXPointAnnotationNativeComponent.ts +++ b/src/specs/RNMBXPointAnnotationNativeComponent.ts @@ -28,6 +28,7 @@ export interface NativeProps extends ViewProps { draggable: UnsafeMixed; id: UnsafeMixed; anchor: UnsafeMixed; + selected: UnsafeMixed; onMapboxPointAnnotationDeselected: DirectEventHandler; onMapboxPointAnnotationDrag: DirectEventHandler; diff --git a/src/specs/codegenUtils.ts b/src/specs/codegenUtils.ts index cc5872949..f03327b32 100644 --- a/src/specs/codegenUtils.ts +++ b/src/specs/codegenUtils.ts @@ -1,6 +1,9 @@ // codegen will generate folly::dynamic in place of this type, but it's not exported by RN // since codegen doesn't really follow imports, this way we can trick it into generating the correct type // while keeping typescript happy +// +// For booleans: UnsafeMixed preserves nullability (true/false/null) vs boolean which defaults to false +// This allows native code to distinguish between "prop not set" vs "prop explicitly set to false" export type UnsafeMixed = T; // Fabric doesn't support optional props, so we need to use UnsafeMixed