diff --git a/CHANGELOG.md b/CHANGELOG.md index 72c5637e6a940..873952e1668a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Package-specific changes not released in any SDK will be added here just before - Updated `@react-native-community/datetimepicker` from `2.2.2` to `2.4.0`. ([#8476](https://github.com/expo/expo/pull/8476) by [@tsapeta](https://github.com/tsapeta)) - Updated `react-native-webview` from `8.1.1` to `9.4.0`. ([#8489](https://github.com/expo/expo/pull/8489) by [@tsapeta](https://github.com/tsapeta)) - Updated `react-native-svg` from `11.0.1` to `12.1.0`. ([#8491](https://github.com/expo/expo/pull/8491) by [@tsapeta](https://github.com/tsapeta)) +- Updated `react-native-maps` from `0.26.1` to `0.27.1`. ([#8495](https://github.com/expo/expo/pull/8495) by [@esamelson](https://github.com/esamelson)) ### 🛠 Breaking changes diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapManager.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapManager.java index 05b6654214c58..c4a9cc4f94c82 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapManager.java +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapManager.java @@ -14,6 +14,7 @@ import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.events.RCTEventEmitter; +import com.google.android.gms.location.LocationRequest; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMapOptions; import com.google.android.gms.maps.model.LatLng; @@ -50,6 +51,13 @@ public class AirMapManager extends ViewGroupManager { "none", GoogleMap.MAP_TYPE_NONE ); + private final Map MY_LOCATION_PRIORITY = MapBuilder.of( + "balanced", LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY, + "high", LocationRequest.PRIORITY_HIGH_ACCURACY, + "low", LocationRequest.PRIORITY_LOW_POWER, + "passive", LocationRequest.PRIORITY_NO_POWER + ); + private final ReactApplicationContext appContext; private AirMapMarkerManager markerManager; @@ -152,6 +160,21 @@ public void setShowsUserLocation(AirMapView view, boolean showUserLocation) { view.setShowsUserLocation(showUserLocation); } + @ReactProp(name = "userLocationPriority") + public void setUserLocationPriority(AirMapView view, @Nullable String accuracy) { + view.setUserLocationPriority(MY_LOCATION_PRIORITY.get(accuracy)); + } + + @ReactProp(name = "userLocationUpdateInterval", defaultInt = 5000) + public void setUserLocationUpdateInterval(AirMapView view, int updateInterval) { + view.setUserLocationUpdateInterval(updateInterval); + } + + @ReactProp(name = "userLocationFastestInterval", defaultInt = 5000) + public void setUserLocationFastestInterval(AirMapView view, int fastestInterval) { + view.setUserLocationFastestInterval(fastestInterval); + } + @ReactProp(name = "showsMyLocationButton", defaultBoolean = true) public void setShowsMyLocationButton(AirMapView view, boolean showMyLocationButton) { view.setShowsMyLocationButton(showMyLocationButton); diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapOverlay.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapOverlay.java index f3abac8482018..e4931efd0d5ef 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapOverlay.java +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapOverlay.java @@ -50,12 +50,12 @@ public void setZIndex(float zIndex) { } } - // public void setTransparency(float transparency) { - // this.transparency = transparency; - // if (groundOverlay != null) { - // groundOverlay.setTransparency(transparency); - // } - // } + public void setTransparency(float transparency) { + this.transparency = transparency; + if (groundOverlay != null) { + groundOverlay.setTransparency(transparency); + } + } public void setImage(String uri) { this.mImageReader.setImage(uri); @@ -138,6 +138,7 @@ public void update() { if (this.groundOverlay != null) { this.groundOverlay.setVisible(true); this.groundOverlay.setImage(this.iconBitmapDescriptor); + this.groundOverlay.setTransparency(this.transparency); this.groundOverlay.setClickable(this.tappable); } } diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapOverlayManager.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapOverlayManager.java index f471b34292339..e31fed87d6129 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapOverlayManager.java +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapOverlayManager.java @@ -51,10 +51,10 @@ public void setZIndex(AirMapOverlay view, float zIndex) { view.setZIndex(zIndex); } - // @ReactProp(name = "transparency", defaultFloat = 1.0f) - // public void setTransparency(AirMapOverlay view, float transparency) { - // view.setTransparency(transparency); - // } + @ReactProp(name = "opacity", defaultFloat = 1.0f) + public void setOpacity(AirMapOverlay view, float opacity) { + view.setTransparency(1 - opacity); + } @ReactProp(name = "image") public void setImage(AirMapOverlay view, @Nullable String source) { diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapView.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapView.java index 0082b243429cd..290ab7f544b8c 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapView.java +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/AirMapView.java @@ -112,6 +112,7 @@ public class AirMapView extends MapView implements GoogleMap.InfoWindowAdapter, private boolean destroyed = false; private final ThemedReactContext context; private final EventDispatcher eventDispatcher; + private FusedLocationSource fusedLocationSource; private ViewAttacherGroup attacherGroup; @@ -161,6 +162,8 @@ public AirMapView(ThemedReactContext reactContext, ReactApplicationContext appCo final AirMapView view = this; + fusedLocationSource = new FusedLocationSource(context); + gestureDetector = new GestureDetectorCompat(reactContext, new GestureDetector.SimpleOnGestureListener() { @@ -385,6 +388,7 @@ public void onHostResume() { if (hasPermissions()) { //noinspection MissingPermission map.setMyLocationEnabled(showUserLocation); + map.setLocationSource(fusedLocationSource); } synchronized (AirMapView.this) { if (!destroyed) { @@ -513,11 +517,24 @@ public void setCamera(ReadableMap camera) { public void setShowsUserLocation(boolean showUserLocation) { this.showUserLocation = showUserLocation; // hold onto this for lifecycle handling if (hasPermissions()) { + map.setLocationSource(fusedLocationSource); //noinspection MissingPermission map.setMyLocationEnabled(showUserLocation); } } + public void setUserLocationPriority(int priority){ + fusedLocationSource.setPriority(priority); + } + + public void setUserLocationUpdateInterval(int interval){ + fusedLocationSource.setInterval(interval); + } + + public void setUserLocationFastestInterval(int interval){ + fusedLocationSource.setFastestInterval(interval); + } + public void setShowsMyLocationButton(boolean showMyLocationButton) { if (hasPermissions() || !showMyLocationButton) { map.getUiSettings().setMyLocationButtonEnabled(showMyLocationButton); diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/FusedLocationSource.java b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/FusedLocationSource.java new file mode 100644 index 0000000000000..32780fa710381 --- /dev/null +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/maps/FusedLocationSource.java @@ -0,0 +1,66 @@ +package versioned.host.exp.exponent.modules.api.components.maps; + +import android.content.Context; +import android.location.Location; +import android.os.Looper; + +import com.google.android.gms.location.FusedLocationProviderClient; +import com.google.android.gms.location.LocationCallback; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationResult; +import com.google.android.gms.location.LocationServices; +import com.google.android.gms.maps.LocationSource; +import com.google.android.gms.tasks.OnSuccessListener; + +public class FusedLocationSource implements LocationSource { + + private final FusedLocationProviderClient fusedLocationClientProviderClient; + private final LocationRequest locationRequest; + private LocationCallback locationCallback; + + public FusedLocationSource(Context context){ + fusedLocationClientProviderClient = + LocationServices.getFusedLocationProviderClient(context); + locationRequest = LocationRequest.create(); + locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + locationRequest.setInterval(5000); + } + + public void setPriority(int priority){ + locationRequest.setPriority(priority); + } + + public void setInterval(int interval){ + locationRequest.setInterval(interval); + } + + public void setFastestInterval(int fastestInterval){ + locationRequest.setFastestInterval(fastestInterval); + } + + @Override + public void activate(final OnLocationChangedListener onLocationChangedListener) { + fusedLocationClientProviderClient.getLastLocation().addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(Location location) { + if (location != null) { + onLocationChangedListener.onLocationChanged(location); + } + } + }); + locationCallback = new LocationCallback() { + @Override + public void onLocationResult(LocationResult locationResult) { + for (Location location : locationResult.getLocations()) { + onLocationChangedListener.onLocationChanged(location); + } + } + }; + fusedLocationClientProviderClient.requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper()); + } + + @Override + public void deactivate() { + fusedLocationClientProviderClient.removeLocationUpdates(locationCallback); + } +} diff --git a/apps/native-component-list/package.json b/apps/native-component-list/package.json index 2f364c1a4208e..7168f281cac57 100644 --- a/apps/native-component-list/package.json +++ b/apps/native-component-list/package.json @@ -86,7 +86,7 @@ "react-native-branch": "4.2.1", "react-native-gesture-handler": "~1.6.0", "react-native-is-iphonex": "^1.0.1", - "react-native-maps": "0.26.1", + "react-native-maps": "0.27.1", "react-native-paper": "github:brentvatne/react-native-paper#@brent/fix-bottom-navigation-rn-57", "react-native-platform-touchable": "^1.1.1", "react-native-reanimated": "~1.9.0", diff --git a/home/package.json b/home/package.json index c77342c4c4528..0d527fb9ac982 100644 --- a/home/package.json +++ b/home/package.json @@ -50,7 +50,7 @@ "react-native-fade-in-image": "^1.5.0", "react-native-gesture-handler": "~1.6.0", "react-native-infinite-scroll-view": "^0.4.5", - "react-native-maps": "0.26.1", + "react-native-maps": "0.27.1", "react-native-safe-area-context": "2.0.1", "react-navigation": "4.1.0-alpha.1", "react-navigation-material-bottom-tabs": "1.1.1", diff --git a/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapManager.m b/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapManager.m index 752dd8484cccc..da3c1e6d582a3 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapManager.m +++ b/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapManager.m @@ -48,7 +48,7 @@ - (UIView *)view AIRGoogleMap *map = [AIRGoogleMap new]; map.bridge = self.bridge; map.delegate = self; - map.isAccessibilityElement = YES; + map.isAccessibilityElement = NO; map.accessibilityElementsHidden = NO; map.settings.consumesGesturesInView = NO; map.indoorDisplay.delegate = self; @@ -65,6 +65,7 @@ - (UIView *)view return map; } +RCT_EXPORT_VIEW_PROPERTY(isAccessibilityElement, BOOL) RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString) RCT_EXPORT_VIEW_PROPERTY(initialCamera, GMSCameraPosition) RCT_REMAP_VIEW_PROPERTY(camera, cameraProp, GMSCameraPosition) diff --git a/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapMarker.m b/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapMarker.m index 02c63a5b6c599..cf69ac7baf3a5 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapMarker.m +++ b/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapMarker.m @@ -9,7 +9,7 @@ #import "AIRGoogleMapMarker.h" #import -#import +#import #import #import "AIRGMSMarker.h" #import "AIRGoogleMapCallout.h" @@ -117,9 +117,9 @@ - (void)hideCalloutView { - (void)redraw { if (!_realMarker.iconView) return; - + BOOL oldValue = _realMarker.tracksViewChanges; - + if (oldValue == YES) { // Immediate refresh, like right now. Not waiting for next frame. @@ -270,7 +270,7 @@ - (void)setImageSrc:(NSString *)imageSrc [self iconViewInsertSubview:_iconImageView atIndex:0]; } - _reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc] + _reloadImageCancellationBlock = [[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc] size:self.bounds.size scale:RCTScreenScale() clipped:YES @@ -327,7 +327,7 @@ - (void)setIconSrc:(NSString *)iconSrc } _reloadImageCancellationBlock = - [_bridge.imageLoader loadImageWithURLRequest:[RCTConvert NSURLRequest:_iconSrc] + [[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:_iconSrc] size:self.bounds.size scale:RCTScreenScale() clipped:YES diff --git a/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlay.h b/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlay.h index 0fd00ebdf009a..14c1892a603a5 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlay.h +++ b/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlay.h @@ -18,6 +18,7 @@ @property (nonatomic, copy) NSString *imageSrc; @property (nonatomic, strong, readonly) UIImage *overlayImage; @property (nonatomic, copy) NSArray *boundsRect; +@property (nonatomic, assign) CGFloat opacity; @property (nonatomic, readonly) GMSCoordinateBounds *overlayBounds; @property (nonatomic, weak) RCTBridge *bridge; diff --git a/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlay.m b/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlay.m index 20dba83bf1ddd..a474c9666b63b 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlay.m +++ b/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlay.m @@ -8,7 +8,7 @@ #import "AIRGoogleMapOverlay.h" #import -#import +#import #import #import @@ -42,7 +42,7 @@ - (void)setImageSrc:(NSString *)imageSrc } __weak typeof(self) weakSelf = self; - _reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc] + _reloadImageCancellationBlock = [[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc] size:weakSelf.bounds.size scale:RCTScreenScale() clipped:YES @@ -75,6 +75,11 @@ - (void)setBoundsRect:(NSArray *)boundsRect _overlay.bounds = _overlayBounds; } +- (void)setOpacity:(CGFloat)opacity +{ + _overlay.opacity = opacity; +} + @end #endif diff --git a/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlayManager.m b/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlayManager.m index 12b29e738d176..9273eb29b8483 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlayManager.m +++ b/ios/Exponent/Versioned/Core/Api/Components/GoogleMaps/AIRGoogleMapOverlayManager.m @@ -18,5 +18,6 @@ - (UIView *)view RCT_REMAP_VIEW_PROPERTY(bounds, boundsRect, NSArray) RCT_REMAP_VIEW_PROPERTY(image, imageSrc, NSString) +RCT_REMAP_VIEW_PROPERTY(opacity, opacity, CGFloat) @end diff --git a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMap.h b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMap.h index 751bef9bdc680..84b53ec77b4f0 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMap.h +++ b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMap.h @@ -45,6 +45,7 @@ extern const NSInteger AIRMapMaxZoomLevel; @property (nonatomic, assign) CGFloat minZoomLevel; @property (nonatomic, assign) CGFloat maxZoomLevel; @property (nonatomic, assign) CGPoint compassOffset; +@property (nonatomic, assign) UIEdgeInsets mapPadding; @property (nonatomic, assign) CLLocationCoordinate2D pendingCenter; @property (nonatomic, assign) MKCoordinateSpan pendingSpan; @@ -66,6 +67,7 @@ extern const NSInteger AIRMapMaxZoomLevel; @property (nonatomic, copy) RCTDirectEventBlock onMarkerDragEnd; @property (nonatomic, copy) RCTDirectEventBlock onCalloutPress; @property (nonatomic, copy) RCTDirectEventBlock onRegionChange; +@property (nonatomic, copy) RCTBubblingEventBlock onUserLocationChange; - (void)cacheViewIfNeeded; - (void)beginLoading; diff --git a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMap.m b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMap.m index 6db04960ce060..6b47930ac2fae 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMap.m +++ b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMap.m @@ -358,6 +358,11 @@ - (void)setShowsUserLocation:(BOOL)showsUserLocation } } +- (void)setTintColor:(UIColor *)tintColor +{ + super.tintColor = tintColor; +} + - (void)setFollowsUserLocation:(BOOL)followsUserLocation { _followUserLocation = followsUserLocation; @@ -526,6 +531,11 @@ - (void)updateZoomEnabled { } - (void)cacheViewIfNeeded { + // https://github.com/react-native-community/react-native-maps/issues/3100 + // Do nothing if app is not active + if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) { + return; + } if (self.hasShownInitialLoading) { if (!self.cacheEnabled) { if (_cacheImageView != nil) { @@ -581,6 +591,14 @@ - (void)setLegalLabelInsets:(UIEdgeInsets)legalLabelInsets { [self updateLegalLabelInsets]; } +- (void)setMapPadding:(UIEdgeInsets)mapPadding { + self.layoutMargins = mapPadding; +} + +- (UIEdgeInsets)mapPadding { + return self.layoutMargins; +} + - (void)beginLoading { if ((!self.hasShownInitialLoading && self.loadingEnabled) || (self.cacheEnabled && self.cacheImageView.image == nil)) { self.loadingView.hidden = NO; diff --git a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapManager.m b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapManager.m index bff75b1767a47..52c24d2cfc44b 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapManager.m +++ b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapManager.m @@ -52,7 +52,7 @@ - (UIView *)view AIRMap *map = [AIRMap new]; map.delegate = self; - map.isAccessibilityElement = YES; + map.isAccessibilityElement = NO; map.accessibilityElementsHidden = NO; // MKMapView doesn't report tap events, so we attach gesture recognizers to it @@ -83,8 +83,10 @@ - (UIView *)view return map; } +RCT_EXPORT_VIEW_PROPERTY(isAccessibilityElement, BOOL) RCT_REMAP_VIEW_PROPERTY(testID, accessibilityIdentifier, NSString) RCT_EXPORT_VIEW_PROPERTY(showsUserLocation, BOOL) +RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor) RCT_EXPORT_VIEW_PROPERTY(userLocationAnnotationTitle, NSString) RCT_EXPORT_VIEW_PROPERTY(followsUserLocation, BOOL) RCT_EXPORT_VIEW_PROPERTY(showsPointsOfInterest, BOOL) @@ -106,6 +108,7 @@ - (UIView *)view RCT_EXPORT_VIEW_PROPERTY(minDelta, CGFloat) RCT_EXPORT_VIEW_PROPERTY(compassOffset, CGPoint) RCT_EXPORT_VIEW_PROPERTY(legalLabelInsets, UIEdgeInsets) +RCT_EXPORT_VIEW_PROPERTY(mapPadding, UIEdgeInsets) RCT_EXPORT_VIEW_PROPERTY(mapType, MKMapType) RCT_EXPORT_VIEW_PROPERTY(onMapReady, RCTBubblingEventBlock) RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock) @@ -120,6 +123,7 @@ - (UIView *)view RCT_EXPORT_VIEW_PROPERTY(onMarkerDrag, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onMarkerDragEnd, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onCalloutPress, RCTDirectEventBlock) +RCT_EXPORT_VIEW_PROPERTY(onUserLocationChange, RCTBubblingEventBlock) RCT_CUSTOM_VIEW_PROPERTY(initialRegion, MKCoordinateRegion, AIRMap) { if (json == nil) return; @@ -468,6 +472,7 @@ - (UIView *)view AIRMap *mapView = (AIRMap *)view; MKMapSnapshotOptions *options = [[MKMapSnapshotOptions alloc] init]; + options.mapType = mapView.mapType; options.region = (region.center.latitude && region.center.longitude) ? region : mapView.region; options.size = CGSizeMake( ([width floatValue] == 0) ? mapView.bounds.size.width : [width floatValue], @@ -948,6 +953,21 @@ - (void)observeValueForKeyPath:(NSString *)keyPath - (void)mapView:(AIRMap *)mapView didUpdateUserLocation:(MKUserLocation *)location { + id event = @{@"coordinate": @{ + @"latitude": @(location.coordinate.latitude), + @"longitude": @(location.coordinate.longitude), + @"altitude": @(location.location.altitude), + @"timestamp": @(location.location.timestamp.timeIntervalSinceReferenceDate * 1000), + @"accuracy": @(location.location.horizontalAccuracy), + @"altitudeAccuracy": @(location.location.verticalAccuracy), + @"speed": @(location.location.speed), + } + }; + + if (mapView.onUserLocationChange) { + mapView.onUserLocationChange(event); + } + if (mapView.followUserLocation) { MKCoordinateRegion region; region.span.latitudeDelta = AIRMapDefaultSpan; @@ -958,6 +978,7 @@ - (void)mapView:(AIRMap *)mapView didUpdateUserLocation:(MKUserLocation *)locati // Move to user location only for the first time it loads up. // mapView.followUserLocation = NO; } + } - (void)mapView:(AIRMap *)mapView regionWillChangeAnimated:(__unused BOOL)animated @@ -1279,6 +1300,15 @@ - (double) zoomLevel:(AIRMap *)mapView { return zoomLevel; } +#pragma mark MKMapViewDelegate - Tracking the User Location + +- (void)mapView:(AIRMap *)mapView didFailToLocateUserWithError:(NSError *)error { + id event = @{@"error": @{ @"message": error.localizedDescription }}; + if (mapView.onUserLocationChange) { + mapView.onUserLocationChange(event); + } +} + - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES; } diff --git a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapMarker.h b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapMarker.h index 0613544a9c946..760acd4c9aa4c 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapMarker.h +++ b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapMarker.h @@ -34,6 +34,7 @@ @property (nonatomic, strong) UIColor *pinColor; @property (nonatomic, assign) NSInteger zIndex; @property (nonatomic, assign) double opacity; +@property (nonatomic, assign) BOOL isPreselected; @property (nonatomic, copy) RCTBubblingEventBlock onPress; @property (nonatomic, copy) RCTDirectEventBlock onSelect; diff --git a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapMarker.m b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapMarker.m index d90f89cf245fd..65098aadf869d 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapMarker.m +++ b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapMarker.m @@ -11,7 +11,7 @@ #import #import -#import +#import #import #import @@ -151,7 +151,7 @@ - (void)showCalloutView { _calloutIsOpen = YES; [self setZIndex:_zIndexBeforeOpen]; - + MKAnnotationView *annotationView = [self getAnnotationView]; [self setSelected:YES animated:NO]; @@ -203,12 +203,12 @@ - (void)addGestureRecognizerToView:(UIView *)view { - (void)_handleTap:(UITapGestureRecognizer *)recognizer { AIRMapMarker *marker = self; if (!marker) return; - + if (marker.selected) { CGPoint touchPoint = [recognizer locationInView:marker.map.calloutView]; CGRect bubbleFrame = [self.calloutView convertRect:marker.map.calloutView.bounds toView:marker.map]; CGPoint touchPointReal = [recognizer locationInView:self.calloutView]; - + UIView *calloutView = [marker.map.calloutView hitTest:touchPoint withEvent:nil]; if (calloutView) { // the callout (or its subview) got clicked, not the marker @@ -222,7 +222,7 @@ - (void)_handleTap:(UITapGestureRecognizer *)recognizer { } tmp = tmp.superview; } - + id event = @{ @"action": calloutSubview ? @"callout-inside-press" : @"callout-press", @"id": marker.identifier ?: @"unknown", @@ -237,7 +237,7 @@ - (void)_handleTap:(UITapGestureRecognizer *)recognizer { @"height": @(bubbleFrame.size.height), } }; - + if (calloutSubview) calloutSubview.onPress(event); if (marker.onCalloutPress) marker.onCalloutPress(event); if (marker.calloutView && marker.calloutView.onPress) marker.calloutView.onPress(event); @@ -245,7 +245,7 @@ - (void)_handleTap:(UITapGestureRecognizer *)recognizer { return; } } - + // the actual marker got clicked id event = @{ @"action": @"marker-press", @@ -255,10 +255,10 @@ - (void)_handleTap:(UITapGestureRecognizer *)recognizer { @"longitude": @(marker.coordinate.longitude) } }; - + if (marker.onPress) marker.onPress(event); if (marker.map.onMarkerPress) marker.map.onMarkerPress(event); - + [marker.map selectAnnotation:marker animated:NO]; } @@ -314,7 +314,7 @@ - (void)setImageSrc:(NSString *)imageSrc _reloadImageCancellationBlock(); _reloadImageCancellationBlock = nil; } - _reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc] + _reloadImageCancellationBlock = [[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc] size:self.bounds.size scale:RCTScreenScale() clipped:YES @@ -348,6 +348,10 @@ - (void)setZIndex:(NSInteger)zIndex self.layer.zPosition = zIndex; } +- (BOOL)isSelected { + return _isPreselected || [super isSelected]; +} + - (void)dealloc { [self.layer removeObserver:self forKeyPath:@"zPosition"]; } diff --git a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapOverlay.m b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapOverlay.m index 316fd883a1a44..e99411d0dd683 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapOverlay.m +++ b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapOverlay.m @@ -2,7 +2,7 @@ #import #import -#import +#import #import #import @@ -27,7 +27,7 @@ - (void)setImageSrc:(NSString *)imageSrc _reloadImageCancellationBlock = nil; } __weak typeof(self) weakSelf = self; - _reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc] + _reloadImageCancellationBlock = [[_bridge moduleForName:@"ImageLoader"] loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc] size:weakSelf.bounds.size scale:RCTScreenScale() clipped:YES @@ -50,13 +50,13 @@ - (void)setImageSrc:(NSString *)imageSrc - (void)setBoundsRect:(NSArray *)boundsRect { _boundsRect = boundsRect; - _southWest = CLLocationCoordinate2DMake([boundsRect[1][0] doubleValue], [boundsRect[0][1] doubleValue]); - _northEast = CLLocationCoordinate2DMake([boundsRect[0][0] doubleValue], [boundsRect[1][1] doubleValue]); + _southWest = CLLocationCoordinate2DMake([boundsRect[0][0] doubleValue], [boundsRect[0][1] doubleValue]); + _northEast = CLLocationCoordinate2DMake([boundsRect[1][0] doubleValue], [boundsRect[1][1] doubleValue]); MKMapPoint southWest = MKMapPointForCoordinate(_southWest); MKMapPoint northEast = MKMapPointForCoordinate(_northEast); - _mapRect = MKMapRectMake(southWest.x, northEast.y, northEast.x - southWest.x, northEast.y - southWest.y); + _mapRect = MKMapRectMake(southWest.x, northEast.y, ABS(northEast.x - southWest.x), ABS(northEast.y - southWest.y)); [self update]; } diff --git a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapOverlayRenderer.m b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapOverlayRenderer.m index 4cd0067eab6b5..a935e65961f4d 100644 --- a/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapOverlayRenderer.m +++ b/ios/Exponent/Versioned/Core/Api/Components/Maps/AIRMapOverlayRenderer.m @@ -15,6 +15,7 @@ - (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoomScale inContex CGContextRotateCTM(context, M_PI); CGContextScaleCTM(context, -1.0, 1.0); + CGContextTranslateCTM(context, 0.0, -theRect.size.height); CGContextAddRect(context, theRect); CGContextDrawImage(context, theRect, imageReference); diff --git a/packages/expo/bundledNativeModules.json b/packages/expo/bundledNativeModules.json index be3523e8987b0..950ca65e978c2 100644 --- a/packages/expo/bundledNativeModules.json +++ b/packages/expo/bundledNativeModules.json @@ -59,7 +59,7 @@ "lottie-react-native": "~2.6.1", "react-native-branch": "4.2.1", "react-native-gesture-handler": "~1.6.0", - "react-native-maps": "0.26.1", + "react-native-maps": "0.27.1", "react-native-reanimated": "~1.9.0", "react-native-screens": "~2.8.0", "react-native-svg": "12.1.0", diff --git a/yarn.lock b/yarn.lock index bac8e444154c2..91be44a5d7619 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13916,10 +13916,10 @@ react-native-is-iphonex@^1.0.1: resolved "https://registry.yarnpkg.com/react-native-is-iphonex/-/react-native-is-iphonex-1.0.1.tgz#4345eb0be61007e84be5c744495108b5634762a2" integrity sha512-r6Na6m5qtwhl0lHCy6bWiJu4qNau+zeaHDaNIG5pZhEbX/q+mHLoRYOY5cWuGPiUN+9VNEGzm+z2q4tfg0j6rA== -react-native-maps@0.26.1: - version "0.26.1" - resolved "https://registry.yarnpkg.com/react-native-maps/-/react-native-maps-0.26.1.tgz#6ec316259b38d259c8974448d894bd7a23101da4" - integrity sha512-p4VTB8YB5ZmOmDRCUpoHZkm05amZwhIo04AJMBbB9+JAR2PNNfpo0vceoWX0Mag4wnePkdzPomeWMplr/wimTg== +react-native-maps@0.27.1: + version "0.27.1" + resolved "https://registry.yarnpkg.com/react-native-maps/-/react-native-maps-0.27.1.tgz#2f10cd417bb2fd938c9e015b1c9b6d9b1a44b97f" + integrity sha512-HygBkZBecTnIVRYrSiLRAvu4OmXOYso/A7c6Cy73HkOh9CgGV8Ap5eBea24tvmFGptjj5Hg8AJ94/YbmWK1Okw== "react-native-paper@github:brentvatne/react-native-paper#@brent/fix-bottom-navigation-rn-57": version "2.1.3"