+
+
\ No newline at end of file
diff --git a/.jscodeshiftignore b/.jscodeshiftignore
new file mode 100644
index 000000000..a78536177
--- /dev/null
+++ b/.jscodeshiftignore
@@ -0,0 +1,9 @@
+# To run a codeshift on the react-native-maps library, cd to the root dir and run:
+# jscodeshift -t PATH_TO_TRANSFORM . --ignore-config .jscodeshiftignore
+.idea
+android
+docs
+example
+gradle
+node_modules
+scripts
\ No newline at end of file
diff --git a/.npmignore b/.npmignore
index 33a9488b1..4ce7bc58b 100644
--- a/.npmignore
+++ b/.npmignore
@@ -1 +1,2 @@
example
+.babelrc
diff --git a/.travis.yml b/.travis.yml
index 5e075585c..34c6353e8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,6 +6,5 @@ node_js:
cache:
directories:
- node_modules
- - example/node_modules
-script: npm run lint
+script: npm run ci
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 763902cc6..109091a39 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,300 @@
# Change Log
+## 0.18.3 (November 30, 2017)
+* Android: [#1839](https://github.com/airbnb/react-native-maps/pull/1839) [AirGoogleMapManager] Use RCTDirectEventBlock for onMarkerPress
+
+## 0.18.2 (November 29, 2017)
+* Android: [#1835](https://github.com/airbnb/react-native-maps/pull/1835) [AirMapView] Null check map instance on view methods
+
+## 0.18.1 (November 28, 2017)
+* Android: [#1828](https://github.com/airbnb/react-native-maps/pull/1828) [AirMapManager] Update MapBuilder for getCommandsMap to support all entires
+
+## 0.18.0 (November 28, 2017)
+* Android/iOS: [#1587](https://github.com/airbnb/react-native-maps/pull/1750) Add support to set map boundaries
+* Android/iOS: [#1750](https://github.com/airbnb/react-native-maps/pull/1750) Add mapPadding property
+* Common: [#1792](https://github.com/airbnb/react-native-maps/pull/1792) Make all components use ViewPropTypes || View.propTypes
+* iOS: [#1774](https://github.com/airbnb/react-native-maps/pull/1774) Added missing parameters to google map screenshot
+* iOS: [#1824](https://github.com/airbnb/react-native-maps/pull/1824) Add new iOS `mutedStandard` map-type
+* iOS: [#1705](https://github.com/airbnb/react-native-maps/pull/1705) Enable control of Google Maps Marker tracksViewChanges property.
+* Android: [#1710](https://github.com/airbnb/react-native-maps/pull/1710) Added support for new Android camera movement APIs
+* iOS: [#1741](https://github.com/airbnb/react-native-maps/pull/1741) Fixed iOS google MapView.onMarkerPress not receiving the marker identifier
+* iOS: [#1816](https://github.com/airbnb/react-native-maps/pull/1816) Fix The name of the given podspec ‘yoga' doesn't match the expected one ‘Yoga'
+* iOS: [#1797](https://github.com/airbnb/react-native-maps/pull/1797) Fixed onMapReady event on iOS to resemble onMapReady on Android
+* Common: [#1817](https://github.com/airbnb/react-native-maps/pull/1817) Allow fitToCoordinates to be called without options parameter
+
+## 0.17.1 (October 18, 2017)
+* Common: [#1687](https://github.com/airbnb/react-native-maps/pull/1687) Fixed TypeScript definitions
+
+## 0.17.0 (October 11, 2017)
+* iOS: [#1527](https://github.com/airbnb/react-native-maps/pull/1527) Added [iOS / Google Maps] support for showsIndoorLevelPicker
+* iOS/Android: [#1544](https://github.com/airbnb/react-native-maps/pull/1544) Adds support to animateToBearing and animateToViewingAngle ( IOS + Android )
+* JS: [#1503](https://github.com/airbnb/react-native-maps/pull/1503) Remove caret from "react": "^16.0.0-alpha.12
+* Android: [#1521](https://github.com/airbnb/react-native-maps/pull/1521) Fix rare android crashes when map size is 0
+* Common: [#1601](https://github.com/airbnb/react-native-maps/pull/1610) Added Typescript Definitions
+* Android: [#1612](https://github.com/airbnb/react-native-maps/pull/1612) Remove legalNotice from android AirMapModule
+
+## 0.16.4 (September 13, 2017)
+* Android: [#1643](https://github.com/airbnb/react-native-maps/pull/1643) [MapMarker] fix android release crash on custom marker
+
+## 0.16.3 (September 2, 2017)
+* iOS: [#1603](https://github.com/airbnb/react-native-maps/pull/1603) Added missing satellite option for iOS Google Maps
+* iOS: [#1579](https://github.com/airbnb/react-native-maps/pull/1579) Set initial region on view
+
+## 0.16.2 (August 17, 2017)
+* Android: [#1563](https://github.com/airbnb/react-native-maps/pull/#1563) Add missing native method for setting initial region
+* iOS: [#1187](https://github.com/airbnb/react-native-maps/pull/1187) Reverted due to build issues
+
+## 0.16.1 (August 15, 2017)
+* Android: [#1428](https://github.com/airbnb/react-native-maps/pull/#1428) Add ability to load marker image from drawable
+* iOS: [#1187](https://github.com/airbnb/react-native-maps/pull/1187) Improve marker performance
+* iOS/Android: [#1458](https://github.com/airbnb/react-native-maps/pull/1458) Add Google Maps legalNotice constant
+* JS: [#1546](https://github.com/airbnb/react-native-maps/pull/1546) Fix initial region native prop
+
+## 0.16.0 (August 9, 2017)
+* Android: [#1481](https://github.com/airbnb/react-native-maps/pull/1481) Handle Android RN 0.47 breaking change
+* iOS: [#1357](https://github.com/airbnb/react-native-maps/pull/1357) add MKTileOverlayRenderer
+* iOS: [#1369](https://github.com/airbnb/react-native-maps/pull/1369) Add onMapReady callback
+* Android/iOS/JS: [#1360](https://github.com/airbnb/react-native-maps/pull/1360) Add minZoom and maxZoom properties for android and ios
+* JS: [#1479](https://github.com/airbnb/react-native-maps/pull/1479) Fix timing function used in AnimatedRegion.spring
+
+## 0.15.3 (June 27, 2017)
+
+* iOS: [#1362](https://github.com/airbnb/react-native-maps/pull/1362) Updates for React 0.43-0.45 and React 16.
+* JS: [#1323](https://github.com/airbnb/react-native-maps/pull/1323) Updates for React 0.43-0.45 and React 16.
+* Android/iOS/JS: [#1440](https://github.com/airbnb/react-native-maps/pull/1440) Updates for React 0.43-0.45 and React 16.
+* iOS: [#1115](https://github.com/airbnb/react-native-maps/pull/1115) Fix animateToCoordinate and animateToRegion
+* Android: [#1403](https://github.com/airbnb/react-native-maps/pull/1403) Fix an NPE
+
+## 0.15.2 (May 20, 2017)
+
+* iOS: [#1351](https://github.com/airbnb/react-native-maps/pull/1351) Fix file references
+
+## 0.15.1 (May 19, 2017)
+
+* iOS: [#1341](https://github.com/airbnb/react-native-maps/pull/1341) Fix compile error in rn version >= 0.40
+* iOS: [#1194](https://github.com/airbnb/react-native-maps/pull/1194) Add onPress support for Google Maps Polyline
+* iOS: [#1326](https://github.com/airbnb/react-native-maps/pull/1326) Add Marker rotation for Google Maps on iOS
+* Android: [#1311](https://github.com/airbnb/react-native-maps/pull/1311) Fix overlay issue
+* Common [#1313](https://github.com/airbnb/react-native-maps/pull/1313) Fix Android sourceDir for react-native-link
+
+## 0.15.0 (May 8, 2017)
+
+* iOS: [#1195](https://github.com/airbnb/react-native-maps/pull/1195) Rename project file to fix iOS build error
+* Android: Update Google Play Services to version `10.2.4`
+
+## 0.14.0 (April 4, 2017)
+
+## Enhancements
+
+* Restructure project #1164
+
+* Add showsIndoorLevelPicker -> setIndoorLevelPickerEnabled to MapView #1019
+[#1188](https://github.com/airbnb/react-native-maps/pull/1188)
+
+* iOS - Added onPress support for Polygons on Google Maps
+[#1024](https://github.com/airbnb/react-native-maps/pull/1024)
+
+* Add customized user location annotation text
+[#1049](https://github.com/airbnb/react-native-maps/pull/1049)
+
+* iOS - Google Maps - Add `showsMyLocationButton` support
+[#1157](https://github.com/airbnb/react-native-maps/pull/1157)
+
+
+## Patches
+
+* Fix getResources() null crash in mapview
+[#1188](https://github.com/airbnb/react-native-maps/pull/1188)
+
+* Rename MapKit category to avoid conflicts with the one in RN
+[#1172](https://github.com/airbnb/react-native-maps/pull/1172)
+
+* Upgrade GMS dependencies to 10.2.0
+[#1169](https://github.com/airbnb/react-native-maps/pull/1169)
+
+* fix multiple-instance memory leak
+[#1130](https://github.com/airbnb/react-native-maps/pull/1130)
+
+* fix onSelected event for markers with custom view
+[#1079](https://github.com/airbnb/react-native-maps/pull/1079)
+
+* Crash in our App fix
+[#1096](https://github.com/airbnb/react-native-maps/pull/1096)
+
+* Use local RCTConvert+MapKit instead of the one in React Native
+[#1138](https://github.com/airbnb/react-native-maps/pull/1138)
+
+
+## 0.13.1 (March 21, 2017)
+
+
+## Enhancements
+
+* Add id identifier to marker-press event on Android
+[#1008](https://github.com/airbnb/react-native-maps/pull/1008)
+ (@stan229)
+
+* setNativeProps, marker opacity, nested components
+[#940](https://github.com/airbnb/react-native-maps/pull/940)
+ (@unboundfire)
+
+
+## Patches
+
+* Update the android buildToolsVersion to 25.0.0
+[#1152](https://github.com/airbnb/react-native-maps/pull/1152)
+ (@markusguenther)
+
+* use `provided` for RN gradle dependency
+[#1151](https://github.com/airbnb/react-native-maps/pull/1151)
+ (@gpeal)
+
+* fix null activity crash
+[#1150](https://github.com/airbnb/react-native-maps/pull/1150)
+ (@lelandrichardson)
+
+* Updated Google play services and gradle build plugin
+[#1023](https://github.com/airbnb/react-native-maps/pull/1023)
+ (@chris-at-translate)
+
+* Sets the map value for the AirMapUrlTile so that it can be updated properly
+[#992](https://github.com/airbnb/react-native-maps/pull/992)
+ (@jschloer)
+
+* onPress and onCalloutPress doesn't trigger on markers in iOS
+[#954](https://github.com/airbnb/react-native-maps/pull/954)
+ (@RajkumarPunchh)
+
+
+
+## 0.13.0 (January 6, 2017)
+
+### Breaking Changes
+
+* Update iOS header imports and JS SyntheticEvent import for RN 0.40
+ [#923](https://github.com/airbnb/react-native-maps/pull/923)
+ (@ide)
+
+### Patches
+
+* Fix issue where callouts sometimes overlap or don't appear
+ [#936](https://github.com/airbnb/react-native-maps/pull/936)
+ (@RajkumarPunchh)
+
+## 0.12.3 (January 6, 2017)
+
+### Patches
+
+* Fix "Animating with MapViews" example – fixes #763
+ [#888](https://github.com/airbnb/react-native-maps/pull/888)
+ (@javiercr)
+* [iOS] Fix "Option 2" method of building Google Maps
+ [#900](https://github.com/airbnb/react-native-maps/pull/900)
+ (@vjeranc)
+* [Android] Fix exception when animating region during initialization
+ [#901](https://github.com/airbnb/react-native-maps/pull/901)
+ (@mlanter)
+* Updated documentation
+ [#902](https://github.com/airbnb/react-native-maps/pull/902),
+ [#904](https://github.com/airbnb/react-native-maps/pull/904),
+ [#910](https://github.com/airbnb/react-native-maps/pull/910)
+ (@anami, @dboydor, @ali-alamine)
+
+
+## 0.12.2 (December 9, 2016)
+
+### Patches
+
+* [Android] Added support for taking snapshots on Android
+ [#625](https://github.com/airbnb/react-native-maps/pull/625)
+ (@IjzerenHein)
+* [iOS] Allow legalLabelInsets to be changed and animated
+ [#873](https://github.com/airbnb/react-native-maps/pull/873)
+ (@scarlac)
+* Added rotation attribute documentation
+ [#871](https://github.com/airbnb/react-native-maps/pull/871)
+ (@Arman92)
+* Update mapview.md documentation
+ [#866](https://github.com/airbnb/react-native-maps/pull/866)
+ (@dccarmo)
+
+
+## 0.12.1 (December 6, 2016)
+
+This release only corrects the version in package.json.
+
+## 0.12.0 (December 6, 2016)
+
+NOTE: This version was not published because package.json was not properly updated
+
+### Breaking Changes
+
+* [android] If we've disabled scrolling within the map, then don't capture the touch events
+ [#664](https://github.com/airbnb/react-native-maps/pull/664)
+ (@mikelambert)
+* [android] Use latest Google Play Services
+ [#731](https://github.com/airbnb/react-native-maps/pull/731)
+ (@mlanter)
+* [android] update google play services
+ [#805](https://github.com/airbnb/react-native-maps/pull/805)
+ (@lrivera)
+
+### Patches
+
+* [iOS] Support iOS SDK < 10 ( XCode < 8 )
+ [#708](https://github.com/airbnb/react-native-maps/pull/708)
+ (@rops)
+* [iOS] Added showsUserLocation property support for Google Maps
+ [#721](https://github.com/airbnb/react-native-maps/pull/721)
+ (@julien-rodrigues)
+* [iOS] Added Google Maps Circle, Polygon, Polyline, MapType Support
+ [#722](https://github.com/airbnb/react-native-maps/pull/722)
+ (@unboundfire)
+* [iOS] Fix Anchor point on Google Maps iOS
+ [#734](https://github.com/airbnb/react-native-maps/pull/734)
+ (@btoueg)
+* [Google Maps iOS] Marker init with image props.
+ [#738](https://github.com/airbnb/react-native-maps/pull/738)
+ (@btoueg)
+* [iOS] Fix dynamic imageSrc removal
+ [#737](https://github.com/airbnb/react-native-maps/pull/737)
+ (@btoueg)
+* [iOS] implement fitToSuppliedMarkers and fitToCoordinates for google
+ [#750](https://github.com/airbnb/react-native-maps/pull/750)
+ (@gilbox)
+* [iOS][android] Add onPress for polygons and polylines on iOS and Android
+ [#760](https://github.com/airbnb/react-native-maps/pull/760)
+ (@frankrowe)
+* [iOS] Fix flicker of map pins on state change
+ [#728](https://github.com/airbnb/react-native-maps/pull/728)
+ (@mlanter)
+* [iOS] Set region only when view has width&height
+ [#785](https://github.com/airbnb/react-native-maps/pull/785)
+ (@gilbox)
+* [iOS] Implements animateToRegion for Google
+ [#779](https://github.com/airbnb/react-native-maps/pull/779)
+ (@btoueg)
+* [iOS] Google Maps Custom Tile Support
+ [#770](https://github.com/airbnb/react-native-maps/pull/770)
+ (@unboundfire)
+* [android] Map Styling for android
+ [#808](https://github.com/airbnb/react-native-maps/pull/808)
+ (@ali-alamine using @azt3k code)
+* [iOS] IOS Google Map styling
+ [#817](https://github.com/airbnb/react-native-maps/pull/817)
+ (@ali-alamine using @azt3k code)
+* [iOS] Add support for polygon holes for Apple Maps and Google Maps on iOS
+ [#801](https://github.com/airbnb/react-native-maps/pull/801)
+ (@therealgilles)
+* [iOS] Fixes #470. Support legalLabelInsets on Apple Maps
+ [#840](https://github.com/airbnb/react-native-maps/pull/840)
+ (@scarlac)
+
## 0.11.0 (October 16, 2016)
+NOTE: `0.10.4` was released *after* this version, and it's possible
+`0.11.0` does not include everything in `0.10.4`. (see #851)
+
### Breaking Changes
* Update example app for RN 0.35, fix Gmaps bug for 0.35
@@ -154,7 +447,7 @@ Failed to build DependencyGraph: @providesModule naming collision:
Duplicate module name: String.prototype.es6
Paths: /Users//node_modules/react-native-maps/example2/node_modules/react-native/packager/react-packager/src/Resolver/polyfills/String.prototype.es6.js collides with /Users//node_modules/react-native/packager/react-packager/src/Resolver/polyfills/String.prototype.es6.js
-This error is caused by a @providesModule declaration with the same name accross two different files.
+This error is caused by a @providesModule declaration with the same name across two different files.
```
0.8.2 is identical to 0.8.1, except with the offending code removed from the NPM package.
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 000000000..e696ba58e
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,3 @@
+source 'https://rubygems.org'
+ruby '2.2.4'
+gem 'cocoapods', '1.2.0'
diff --git a/example/ios/Gemfile.lock b/Gemfile.lock
similarity index 64%
rename from example/ios/Gemfile.lock
rename to Gemfile.lock
index b8c6feba0..9265653cd 100644
--- a/example/ios/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,43 +1,43 @@
GEM
remote: https://rubygems.org/
specs:
- CFPropertyList (2.3.3)
- activesupport (4.2.7.1)
+ CFPropertyList (2.3.5)
+ activesupport (4.2.8)
i18n (~> 0.7)
- json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
claide (1.0.1)
- cocoapods (1.1.1)
+ cocoapods (1.2.0)
activesupport (>= 4.0.2, < 5)
claide (>= 1.0.1, < 2.0)
- cocoapods-core (= 1.1.1)
+ cocoapods-core (= 1.2.0)
cocoapods-deintegrate (>= 1.0.1, < 2.0)
- cocoapods-downloader (>= 1.1.2, < 2.0)
+ cocoapods-downloader (>= 1.1.3, < 2.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
cocoapods-stats (>= 1.0.0, < 2.0)
- cocoapods-trunk (>= 1.1.1, < 2.0)
+ cocoapods-trunk (>= 1.1.2, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0)
colored (~> 1.2)
escape (~> 0.0.4)
fourflusher (~> 2.0.1)
gh_inspector (~> 1.0)
- molinillo (~> 0.5.1)
+ molinillo (~> 0.5.5)
nap (~> 1.0)
- xcodeproj (>= 1.3.3, < 2.0)
- cocoapods-core (1.1.1)
+ ruby-macho (~> 0.2.5)
+ xcodeproj (>= 1.4.1, < 2.0)
+ cocoapods-core (1.2.0)
activesupport (>= 4.0.2, < 5)
fuzzy_match (~> 2.0.4)
nap (~> 1.0)
cocoapods-deintegrate (1.0.1)
- cocoapods-downloader (1.1.2)
+ cocoapods-downloader (1.1.3)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.0)
cocoapods-stats (1.0.0)
- cocoapods-trunk (1.1.1)
+ cocoapods-trunk (1.1.2)
nap (>= 0.8, < 2.0)
netrc (= 0.7.8)
cocoapods-try (1.1.0)
@@ -45,29 +45,32 @@ GEM
escape (0.0.4)
fourflusher (2.0.1)
fuzzy_match (2.0.4)
- gh_inspector (1.0.2)
- i18n (0.7.0)
- json (1.8.3)
- minitest (5.9.1)
- molinillo (0.5.3)
- nanaimo (0.2.2)
+ gh_inspector (1.0.3)
+ i18n (0.8.1)
+ minitest (5.10.1)
+ molinillo (0.5.7)
+ nanaimo (0.2.3)
nap (1.1.0)
netrc (0.7.8)
- thread_safe (0.3.5)
- tzinfo (1.2.2)
+ ruby-macho (0.2.6)
+ thread_safe (0.3.6)
+ tzinfo (1.2.3)
thread_safe (~> 0.1)
- xcodeproj (1.4.1)
+ xcodeproj (1.4.2)
CFPropertyList (~> 2.3.3)
activesupport (>= 3)
claide (>= 1.0.1, < 2.0)
colored (~> 1.2)
- nanaimo (~> 0.2.0)
+ nanaimo (~> 0.2.3)
PLATFORMS
ruby
DEPENDENCIES
- cocoapods (~> 1.1.1)
+ cocoapods (= 1.2.0)
+
+RUBY VERSION
+ ruby 2.2.4p230
BUNDLED WITH
- 1.10.6
+ 1.14.6
diff --git a/README.md b/README.md
index fe945bd7c..e11e91b88 100644
--- a/README.md
+++ b/README.md
@@ -190,6 +190,24 @@ render() {
);
}
```
+For iOS, in addition to providing the `mapStyle` you will need to do the following
+
+```jsx
+import MapView, { PROVIDER_GOOGLE } from 'react-native-maps'
+
+// ...
+
+
+```
+
+Then add the AirGoogleMaps directory:
+
+https://github.com/airbnb/react-native-maps/blob/1e71a21f39e7b88554852951f773c731c94680c9/docs/installation.md#ios
+
+An unofficial step-by-step guide is also available at https://gist.github.com/heron2014/e60fa003e9b117ce80d56bb1d5bfe9e0
## Examples
@@ -373,7 +391,6 @@ render() {
```
### Take Snapshot of map
-currently only for ios, android implementation WIP
```jsx
getInitialState() {
@@ -386,17 +403,25 @@ getInitialState() {
}
takeSnapshot () {
- // arguments to 'takeSnapshot' are width, height, coordinates and callback
- this.refs.map.takeSnapshot(300, 300, this.state.coordinate, (err, snapshot) => {
- // snapshot contains image 'uri' - full path to image and 'data' - base64 encoded image
- this.setState({ mapSnapshot: snapshot })
- })
+ // 'takeSnapshot' takes a config object with the
+ // following options
+ const snapshot = this.map.takeSnapshot({
+ width: 300, // optional, when omitted the view-width is used
+ height: 300, // optional, when omitted the view-height is used
+ region: {..}, // iOS only, optional region to render
+ format: 'png', // image formats: 'png', 'jpg' (default: 'png')
+ quality: 0.8, // image quality: 0..1 (only relevant for jpg, default: 1)
+ result: 'file' // result types: 'file', 'base64' (default: 'file')
+ });
+ snapshot.then((uri) => {
+ this.setState({ mapSnapshot: uri });
+ });
}
render() {
return (
-
+ { this.map = map }}>
@@ -427,6 +452,7 @@ Pass an array of coordinates to focus a map region on said coordinates.
* Make sure that you have [properly installed](docs/installation.md) react-native-maps.
* Check in the logs if there is more informations about the issue.
* Try setting the style of the MapView to an absolute position with top, left, right and bottom values set.
+* Make sure you have enabled Google Maps API in 
```javascript
const styles = StyleSheet.create({
@@ -469,7 +495,7 @@ Good:
License
--------
- Copyright (c) 2015 Leland Richardson
+ Copyright (c) 2017 Airbnb
Licensed under the The MIT License (MIT) (the "License");
you may not use this file except in compliance with the License.
diff --git a/android/build.gradle b/android/build.gradle
deleted file mode 100644
index ccc3757c7..000000000
--- a/android/build.gradle
+++ /dev/null
@@ -1,60 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-apply plugin: 'com.android.library'
-apply from: 'gradle-maven-push.gradle'
-
-buildscript {
- repositories {
- mavenLocal()
- jcenter()
- maven {
- // For developing the library outside the context of the example app, expect `react-native`
- // to be installed at `./node_modules`.
- url "$projectDir/../node_modules/react-native/android"
- }
- maven {
- // For developing the example app.
- url "$projectDir/../../react-native/android"
- }
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:2.1.0'
- }
-}
-
-allprojects {
- repositories {
- mavenLocal()
- jcenter()
- maven {
- // For developing the library outside the context of the example app, expect `react-native`
- // to be installed at `./node_modules`.
- url "$projectDir/../node_modules/react-native/android"
- }
- maven {
- // For developing the example app.
- url "$projectDir/../../react-native/android"
- }
- }
-}
-
-android {
- compileSdkVersion 23
- buildToolsVersion "23.0.3"
-
- defaultConfig {
- minSdkVersion 16
- targetSdkVersion 23
- }
-
- lintOptions {
- disable 'InvalidPackage'
- }
-}
-
-dependencies {
- compile 'com.facebook.react:react-native:+'
- compile "com.google.android.gms:play-services-base:9.8.0"
- compile 'com.google.android.gms:play-services-maps:9.8.0'
- compile 'com.google.maps.android:android-maps-utils:0.4+'
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapCallout.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapCallout.java
deleted file mode 100644
index c434c9c12..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapCallout.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-
-import com.facebook.react.views.view.ReactViewGroup;
-
-public class AirMapCallout extends ReactViewGroup {
- private boolean tooltip = false;
- public int width;
- public int height;
-
- public AirMapCallout(Context context) {
- super(context);
- }
-
- public void setTooltip(boolean tooltip) {
- this.tooltip = tooltip;
- }
-
- public boolean getTooltip() {
- return this.tooltip;
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapCalloutManager.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapCalloutManager.java
deleted file mode 100644
index 359e6847b..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapCalloutManager.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.LayoutShadowNode;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.ViewGroupManager;
-import com.facebook.react.uimanager.annotations.ReactProp;
-
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-public class AirMapCalloutManager extends ViewGroupManager {
-
- @Override
- public String getName() {
- return "AIRMapCallout";
- }
-
- @Override
- public AirMapCallout createViewInstance(ThemedReactContext context) {
- return new AirMapCallout(context);
- }
-
- @ReactProp(name = "tooltip", defaultBoolean = false)
- public void setTooltip(AirMapCallout view, boolean tooltip) {
- view.setTooltip(tooltip);
- }
-
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- return MapBuilder.of("onPress", MapBuilder.of("registrationName", "onPress"));
- }
-
- @Override
- public LayoutShadowNode createShadowNodeInstance() {
- // we use a custom shadow node that emits the width/height of the view
- // after layout with the updateExtraData method. Without this, we can't generate
- // a bitmap of the appropriate width/height of the rendered view.
- return new SizeReportingShadowNode();
- }
-
- @Override
- public void updateExtraData(AirMapCallout view, Object extraData) {
- // This method is called from the shadow node with the width/height of the rendered
- // marker view.
- //noinspection unchecked
- Map data = (Map) extraData;
- float width = data.get("width");
- float height = data.get("height");
- view.width = (int) width;
- view.height = (int) height;
- }
-
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapCircle.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapCircle.java
deleted file mode 100644
index e428b04f6..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapCircle.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-
-import com.google.android.gms.maps.GoogleMap;
-import com.google.android.gms.maps.model.Circle;
-import com.google.android.gms.maps.model.CircleOptions;
-import com.google.android.gms.maps.model.LatLng;
-
-public class AirMapCircle extends AirMapFeature {
-
- private CircleOptions circleOptions;
- private Circle circle;
-
- private LatLng center;
- private double radius;
- private int strokeColor;
- private int fillColor;
- private float strokeWidth;
- private float zIndex;
-
- public AirMapCircle(Context context) {
- super(context);
- }
-
- public void setCenter(LatLng center) {
- this.center = center;
- if (circle != null) {
- circle.setCenter(this.center);
- }
- }
-
- public void setRadius(double radius) {
- this.radius = radius;
- if (circle != null) {
- circle.setRadius(this.radius);
- }
- }
-
- public void setFillColor(int color) {
- this.fillColor = color;
- if (circle != null) {
- circle.setFillColor(color);
- }
- }
-
- public void setStrokeColor(int color) {
- this.strokeColor = color;
- if (circle != null) {
- circle.setStrokeColor(color);
- }
- }
-
- public void setStrokeWidth(float width) {
- this.strokeWidth = width;
- if (circle != null) {
- circle.setStrokeWidth(width);
- }
- }
-
- public void setZIndex(float zIndex) {
- this.zIndex = zIndex;
- if (circle != null) {
- circle.setZIndex(zIndex);
- }
- }
-
- public CircleOptions getCircleOptions() {
- if (circleOptions == null) {
- circleOptions = createCircleOptions();
- }
- return circleOptions;
- }
-
- private CircleOptions createCircleOptions() {
- CircleOptions options = new CircleOptions();
- options.center(center);
- options.radius(radius);
- options.fillColor(fillColor);
- options.strokeColor(strokeColor);
- options.strokeWidth(strokeWidth);
- options.zIndex(zIndex);
- return options;
- }
-
- @Override
- public Object getFeature() {
- return circle;
- }
-
- @Override
- public void addToMap(GoogleMap map) {
- circle = map.addCircle(getCircleOptions());
- }
-
- @Override
- public void removeFromMap(GoogleMap map) {
- circle.remove();
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapCircleManager.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapCircleManager.java
deleted file mode 100644
index c0eaf8f14..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapCircleManager.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.os.Build;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
-
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.ViewGroupManager;
-import com.facebook.react.uimanager.annotations.ReactProp;
-import com.google.android.gms.maps.model.LatLng;
-
-public class AirMapCircleManager extends ViewGroupManager {
- private final DisplayMetrics metrics;
-
- public AirMapCircleManager(ReactApplicationContext reactContext) {
- super();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- metrics = new DisplayMetrics();
- ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay()
- .getRealMetrics(metrics);
- } else {
- metrics = reactContext.getResources().getDisplayMetrics();
- }
- }
-
- @Override
- public String getName() {
- return "AIRMapCircle";
- }
-
- @Override
- public AirMapCircle createViewInstance(ThemedReactContext context) {
- return new AirMapCircle(context);
- }
-
- @ReactProp(name = "center")
- public void setCenter(AirMapCircle view, ReadableMap center) {
- view.setCenter(new LatLng(center.getDouble("latitude"), center.getDouble("longitude")));
- }
-
- @ReactProp(name = "radius", defaultDouble = 0)
- public void setRadius(AirMapCircle view, double radius) {
- view.setRadius(radius);
- }
-
- @ReactProp(name = "strokeWidth", defaultFloat = 1f)
- public void setStrokeWidth(AirMapCircle view, float widthInPoints) {
- float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
- view.setStrokeWidth(widthInScreenPx);
- }
-
- @ReactProp(name = "fillColor", defaultInt = Color.RED, customType = "Color")
- public void setFillColor(AirMapCircle view, int color) {
- view.setFillColor(color);
- }
-
- @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
- public void setStrokeColor(AirMapCircle view, int color) {
- view.setStrokeColor(color);
- }
-
- @ReactProp(name = "zIndex", defaultFloat = 1.0f)
- public void setZIndex(AirMapCircle view, float zIndex) {
- view.setZIndex(zIndex);
- }
-
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapLiteManager.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapLiteManager.java
deleted file mode 100644
index 62495c5e4..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapLiteManager.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.google.android.gms.maps.GoogleMapOptions;
-
-public class AirMapLiteManager extends AirMapManager {
-
- private static final String REACT_CLASS = "AIRMapLite";
-
- @Override
- public String getName() {
- return REACT_CLASS;
- }
-
- public AirMapLiteManager(ReactApplicationContext context) {
- super(context);
- this.googleMapOptions = new GoogleMapOptions().liteMode(true);
- }
-
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java
deleted file mode 100644
index 75ed5777f..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java
+++ /dev/null
@@ -1,305 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.view.View;
-
-import com.facebook.react.bridge.Arguments;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.common.MapBuilder;
-import com.facebook.react.modules.core.DeviceEventManagerModule;
-import com.facebook.react.uimanager.LayoutShadowNode;
-import com.facebook.react.uimanager.ThemedReactContext;
-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.maps.GoogleMap;
-import com.google.android.gms.maps.GoogleMapOptions;
-import com.google.android.gms.maps.MapsInitializer;
-import com.google.android.gms.maps.model.LatLng;
-import com.google.android.gms.maps.model.LatLngBounds;
-import com.google.android.gms.maps.model.MapStyleOptions;
-
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-public class AirMapManager extends ViewGroupManager {
-
- private static final String REACT_CLASS = "AIRMap";
- private static final int ANIMATE_TO_REGION = 1;
- private static final int ANIMATE_TO_COORDINATE = 2;
- private static final int FIT_TO_ELEMENTS = 3;
- private static final int FIT_TO_SUPPLIED_MARKERS = 4;
- private static final int FIT_TO_COORDINATES = 5;
-
- private final Map MAP_TYPES = MapBuilder.of(
- "standard", GoogleMap.MAP_TYPE_NORMAL,
- "satellite", GoogleMap.MAP_TYPE_SATELLITE,
- "hybrid", GoogleMap.MAP_TYPE_HYBRID,
- "terrain", GoogleMap.MAP_TYPE_TERRAIN,
- "none", GoogleMap.MAP_TYPE_NONE
- );
-
- private ReactContext reactContext;
-
- private final ReactApplicationContext appContext;
-
- protected GoogleMapOptions googleMapOptions;
-
- public AirMapManager(ReactApplicationContext context) {
- this.appContext = context;
- this.googleMapOptions = new GoogleMapOptions();
- }
-
- @Override
- public String getName() {
- return REACT_CLASS;
- }
-
- @Override
- protected AirMapView createViewInstance(ThemedReactContext context) {
- reactContext = context;
-
- try {
- MapsInitializer.initialize(this.appContext);
- } catch (RuntimeException e) {
- e.printStackTrace();
- emitMapError("Map initialize error", "map_init_error");
- }
-
- return new AirMapView(context, this.appContext.getCurrentActivity(), this, this.googleMapOptions);
- }
-
- private void emitMapError(String message, String type) {
- WritableMap error = Arguments.createMap();
- error.putString("message", message);
- error.putString("type", type);
-
- reactContext
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
- .emit("onError", error);
- }
-
- @ReactProp(name = "region")
- public void setRegion(AirMapView view, ReadableMap region) {
- view.setRegion(region);
- }
-
- @ReactProp(name = "mapType")
- public void setMapType(AirMapView view, @Nullable String mapType) {
- int typeId = MAP_TYPES.get(mapType);
- view.map.setMapType(typeId);
- }
-
- @ReactProp(name = "customMapStyleString")
- public void setMapStyle(AirMapView view, @Nullable String customMapStyleString) {
- view.map.setMapStyle(new MapStyleOptions(customMapStyleString));
- }
-
- @ReactProp(name = "showsUserLocation", defaultBoolean = false)
- public void setShowsUserLocation(AirMapView view, boolean showUserLocation) {
- view.setShowsUserLocation(showUserLocation);
- }
-
- @ReactProp(name = "showsMyLocationButton", defaultBoolean = true)
- public void setShowsMyLocationButton(AirMapView view, boolean showMyLocationButton) {
- view.setShowsMyLocationButton(showMyLocationButton);
- }
-
- @ReactProp(name = "toolbarEnabled", defaultBoolean = true)
- public void setToolbarEnabled(AirMapView view, boolean toolbarEnabled) {
- view.setToolbarEnabled(toolbarEnabled);
- }
-
- // This is a private prop to improve performance of panDrag by disabling it when the callback is not set
- @ReactProp(name = "handlePanDrag", defaultBoolean = false)
- public void setHandlePanDrag(AirMapView view, boolean handlePanDrag) {
- view.setHandlePanDrag(handlePanDrag);
- }
-
- @ReactProp(name = "showsTraffic", defaultBoolean = false)
- public void setShowTraffic(AirMapView view, boolean showTraffic) {
- view.map.setTrafficEnabled(showTraffic);
- }
-
- @ReactProp(name = "showsBuildings", defaultBoolean = false)
- public void setShowBuildings(AirMapView view, boolean showBuildings) {
- view.map.setBuildingsEnabled(showBuildings);
- }
-
- @ReactProp(name = "showsIndoors", defaultBoolean = false)
- public void setShowIndoors(AirMapView view, boolean showIndoors) {
- view.map.setIndoorEnabled(showIndoors);
- }
-
- @ReactProp(name = "showsCompass", defaultBoolean = false)
- public void setShowsCompass(AirMapView view, boolean showsCompass) {
- view.map.getUiSettings().setCompassEnabled(showsCompass);
- }
-
- @ReactProp(name = "scrollEnabled", defaultBoolean = false)
- public void setScrollEnabled(AirMapView view, boolean scrollEnabled) {
- view.map.getUiSettings().setScrollGesturesEnabled(scrollEnabled);
- }
-
- @ReactProp(name = "zoomEnabled", defaultBoolean = false)
- public void setZoomEnabled(AirMapView view, boolean zoomEnabled) {
- view.map.getUiSettings().setZoomGesturesEnabled(zoomEnabled);
- }
-
- @ReactProp(name = "rotateEnabled", defaultBoolean = false)
- public void setRotateEnabled(AirMapView view, boolean rotateEnabled) {
- view.map.getUiSettings().setRotateGesturesEnabled(rotateEnabled);
- }
-
- @ReactProp(name = "cacheEnabled", defaultBoolean = false)
- public void setCacheEnabled(AirMapView view, boolean cacheEnabled) {
- view.setCacheEnabled(cacheEnabled);
- }
-
- @ReactProp(name = "loadingEnabled", defaultBoolean = false)
- public void setLoadingEnabled(AirMapView view, boolean loadingEnabled) {
- view.enableMapLoading(loadingEnabled);
- }
-
- @ReactProp(name = "moveOnMarkerPress", defaultBoolean = true)
- public void setMoveOnMarkerPress(AirMapView view, boolean moveOnPress) {
- view.setMoveOnMarkerPress(moveOnPress);
- }
-
- @ReactProp(name = "loadingBackgroundColor", customType = "Color")
- public void setLoadingBackgroundColor(AirMapView view, @Nullable Integer loadingBackgroundColor) {
- view.setLoadingBackgroundColor(loadingBackgroundColor);
- }
-
- @ReactProp(name = "loadingIndicatorColor", customType = "Color")
- public void setLoadingIndicatorColor(AirMapView view, @Nullable Integer loadingIndicatorColor) {
- view.setLoadingIndicatorColor(loadingIndicatorColor);
- }
-
- @ReactProp(name = "pitchEnabled", defaultBoolean = false)
- public void setPitchEnabled(AirMapView view, boolean pitchEnabled) {
- view.map.getUiSettings().setTiltGesturesEnabled(pitchEnabled);
- }
-
- @Override
- public void receiveCommand(AirMapView view, int commandId, @Nullable ReadableArray args) {
- Integer duration;
- Double lat;
- Double lng;
- Double lngDelta;
- Double latDelta;
- ReadableMap region;
-
- switch (commandId) {
- case ANIMATE_TO_REGION:
- region = args.getMap(0);
- duration = args.getInt(1);
- lng = region.getDouble("longitude");
- lat = region.getDouble("latitude");
- lngDelta = region.getDouble("longitudeDelta");
- latDelta = region.getDouble("latitudeDelta");
- LatLngBounds bounds = new LatLngBounds(
- new LatLng(lat - latDelta / 2, lng - lngDelta / 2), // southwest
- new LatLng(lat + latDelta / 2, lng + lngDelta / 2) // northeast
- );
- view.animateToRegion(bounds, duration);
- break;
-
- case ANIMATE_TO_COORDINATE:
- region = args.getMap(0);
- duration = args.getInt(1);
- lng = region.getDouble("longitude");
- lat = region.getDouble("latitude");
- view.animateToCoordinate(new LatLng(lat, lng), duration);
- break;
-
- case FIT_TO_ELEMENTS:
- view.fitToElements(args.getBoolean(0));
- break;
-
- case FIT_TO_SUPPLIED_MARKERS:
- view.fitToSuppliedMarkers(args.getArray(0), args.getBoolean(1));
- break;
- case FIT_TO_COORDINATES:
- view.fitToCoordinates(args.getArray(0), args.getMap(1), args.getBoolean(2));
- break;
- }
- }
-
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- Map> map = MapBuilder.of(
- "onMapReady", MapBuilder.of("registrationName", "onMapReady"),
- "onPress", MapBuilder.of("registrationName", "onPress"),
- "onLongPress", MapBuilder.of("registrationName", "onLongPress"),
- "onMarkerPress", MapBuilder.of("registrationName", "onMarkerPress"),
- "onMarkerSelect", MapBuilder.of("registrationName", "onMarkerSelect"),
- "onMarkerDeselect", MapBuilder.of("registrationName", "onMarkerDeselect"),
- "onCalloutPress", MapBuilder.of("registrationName", "onCalloutPress")
- );
-
- map.putAll(MapBuilder.of(
- "onMarkerDragStart", MapBuilder.of("registrationName", "onMarkerDragStart"),
- "onMarkerDrag", MapBuilder.of("registrationName", "onMarkerDrag"),
- "onMarkerDragEnd", MapBuilder.of("registrationName", "onMarkerDragEnd"),
- "onPanDrag", MapBuilder.of("registrationName", "onPanDrag")
- ));
-
- return map;
- }
-
- @Override
- @Nullable
- public Map getCommandsMap() {
- return MapBuilder.of(
- "animateToRegion", ANIMATE_TO_REGION,
- "animateToCoordinate", ANIMATE_TO_COORDINATE,
- "fitToElements", FIT_TO_ELEMENTS,
- "fitToSuppliedMarkers", FIT_TO_SUPPLIED_MARKERS,
- "fitToCoordinates", FIT_TO_COORDINATES
- );
- }
-
- @Override
- public LayoutShadowNode createShadowNodeInstance() {
- // A custom shadow node is needed in order to pass back the width/height of the map to the
- // view manager so that it can start applying camera moves with bounds.
- return new SizeReportingShadowNode();
- }
-
- @Override
- public void addView(AirMapView parent, View child, int index) {
- parent.addFeature(child, index);
- }
-
- @Override
- public int getChildCount(AirMapView view) {
- return view.getFeatureCount();
- }
-
- @Override
- public View getChildAt(AirMapView view, int index) {
- return view.getFeatureAt(index);
- }
-
- @Override
- public void removeViewAt(AirMapView parent, int index) {
- parent.removeFeatureAt(index);
- }
-
- @Override
- public void updateExtraData(AirMapView view, Object extraData) {
- view.updateExtraData(extraData);
- }
-
- void pushEvent(View view, String name, WritableMap data) {
- reactContext.getJSModule(RCTEventEmitter.class)
- .receiveEvent(view.getId(), name, data);
- }
-
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapMarker.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapMarker.java
deleted file mode 100644
index de01d106e..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapMarker.java
+++ /dev/null
@@ -1,420 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.drawable.Animatable;
-import android.net.Uri;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.facebook.common.references.CloseableReference;
-import com.facebook.datasource.DataSource;
-import com.facebook.drawee.backends.pipeline.Fresco;
-import com.facebook.drawee.controller.BaseControllerListener;
-import com.facebook.drawee.controller.ControllerListener;
-import com.facebook.drawee.drawable.ScalingUtils;
-import com.facebook.drawee.generic.GenericDraweeHierarchy;
-import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
-import com.facebook.drawee.interfaces.DraweeController;
-import com.facebook.drawee.view.DraweeHolder;
-import com.facebook.imagepipeline.core.ImagePipeline;
-import com.facebook.imagepipeline.image.CloseableImage;
-import com.facebook.imagepipeline.image.CloseableStaticBitmap;
-import com.facebook.imagepipeline.image.ImageInfo;
-import com.facebook.imagepipeline.request.ImageRequest;
-import com.facebook.imagepipeline.request.ImageRequestBuilder;
-import com.facebook.react.bridge.ReadableMap;
-import com.google.android.gms.maps.GoogleMap;
-import com.google.android.gms.maps.model.BitmapDescriptor;
-import com.google.android.gms.maps.model.BitmapDescriptorFactory;
-import com.google.android.gms.maps.model.LatLng;
-import com.google.android.gms.maps.model.Marker;
-import com.google.android.gms.maps.model.MarkerOptions;
-
-import javax.annotation.Nullable;
-
-public class AirMapMarker extends AirMapFeature {
-
- private MarkerOptions markerOptions;
- private Marker marker;
- private int width;
- private int height;
- private String identifier;
-
- private LatLng position;
- private String title;
- private String snippet;
-
- private boolean anchorIsSet;
- private float anchorX;
- private float anchorY;
-
- private AirMapCallout calloutView;
- private View wrappedCalloutView;
- private final Context context;
-
- private float markerHue = 0.0f; // should be between 0 and 360
- private BitmapDescriptor iconBitmapDescriptor;
- private Bitmap iconBitmap;
-
- private float rotation = 0.0f;
- private boolean flat = false;
- private boolean draggable = false;
- private int zIndex = 0;
-
- private float calloutAnchorX;
- private float calloutAnchorY;
- private boolean calloutAnchorIsSet;
-
- private boolean hasCustomMarkerView = false;
-
- private final DraweeHolder> logoHolder;
- private DataSource> dataSource;
- private final ControllerListener mLogoControllerListener =
- new BaseControllerListener() {
- @Override
- public void onFinalImageSet(
- String id,
- @Nullable final ImageInfo imageInfo,
- @Nullable Animatable animatable) {
- CloseableReference imageReference = null;
- try {
- imageReference = dataSource.getResult();
- if (imageReference != null) {
- CloseableImage image = imageReference.get();
- if (image != null && image instanceof CloseableStaticBitmap) {
- CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image;
- Bitmap bitmap = closeableStaticBitmap.getUnderlyingBitmap();
- if (bitmap != null) {
- bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
- iconBitmap = bitmap;
- iconBitmapDescriptor = BitmapDescriptorFactory.fromBitmap(bitmap);
- }
- }
- }
- } finally {
- dataSource.close();
- if (imageReference != null) {
- CloseableReference.closeSafely(imageReference);
- }
- }
- update();
- }
- };
-
- public AirMapMarker(Context context) {
- super(context);
- this.context = context;
- logoHolder = DraweeHolder.create(createDraweeHierarchy(), context);
- logoHolder.onAttach();
- }
-
- private GenericDraweeHierarchy createDraweeHierarchy() {
- return new GenericDraweeHierarchyBuilder(getResources())
- .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
- .setFadeDuration(0)
- .build();
- }
-
- public void setCoordinate(ReadableMap coordinate) {
- position = new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude"));
- if (marker != null) {
- marker.setPosition(position);
- }
- update();
- }
-
- public void setIdentifier(String identifier) {
- this.identifier = identifier;
- update();
- }
-
- public String getIdentifier() {
- return this.identifier;
- }
-
- public void setTitle(String title) {
- this.title = title;
- if (marker != null) {
- marker.setTitle(title);
- }
- update();
- }
-
- public void setSnippet(String snippet) {
- this.snippet = snippet;
- if (marker != null) {
- marker.setSnippet(snippet);
- }
- update();
- }
-
- public void setRotation(float rotation) {
- this.rotation = rotation;
- if (marker != null) {
- marker.setRotation(rotation);
- }
- update();
- }
-
- public void setFlat(boolean flat) {
- this.flat = flat;
- if (marker != null) {
- marker.setFlat(flat);
- }
- update();
- }
-
- public void setDraggable(boolean draggable) {
- this.draggable = draggable;
- if (marker != null) {
- marker.setDraggable(draggable);
- }
- update();
- }
-
- public void setZIndex(int zIndex) {
- this.zIndex = zIndex;
- if (marker != null) {
- marker.setZIndex(zIndex);
- }
- update();
- }
-
- public void setMarkerHue(float markerHue) {
- this.markerHue = markerHue;
- update();
- }
-
- public void setAnchor(double x, double y) {
- anchorIsSet = true;
- anchorX = (float) x;
- anchorY = (float) y;
- if (marker != null) {
- marker.setAnchor(anchorX, anchorY);
- }
- update();
- }
-
- public void setCalloutAnchor(double x, double y) {
- calloutAnchorIsSet = true;
- calloutAnchorX = (float) x;
- calloutAnchorY = (float) y;
- if (marker != null) {
- marker.setInfoWindowAnchor(calloutAnchorX, calloutAnchorY);
- }
- update();
- }
-
- public void setImage(String uri) {
- if (uri == null) {
- iconBitmapDescriptor = null;
- update();
- } else if (uri.startsWith("http://") || uri.startsWith("https://") ||
- uri.startsWith("file://")) {
- ImageRequest imageRequest = ImageRequestBuilder
- .newBuilderWithSource(Uri.parse(uri))
- .build();
-
- ImagePipeline imagePipeline = Fresco.getImagePipeline();
- dataSource = imagePipeline.fetchDecodedImage(imageRequest, this);
- DraweeController controller = Fresco.newDraweeControllerBuilder()
- .setImageRequest(imageRequest)
- .setControllerListener(mLogoControllerListener)
- .setOldController(logoHolder.getController())
- .build();
- logoHolder.setController(controller);
- } else {
- iconBitmapDescriptor = getBitmapDescriptorByName(uri);
- update();
- }
- }
-
- public MarkerOptions getMarkerOptions() {
- if (markerOptions == null) {
- markerOptions = createMarkerOptions();
- }
- return markerOptions;
- }
-
- @Override
- public void addView(View child, int index) {
- super.addView(child, index);
- // if children are added, it means we are rendering a custom marker
- if (!(child instanceof AirMapCallout)) {
- hasCustomMarkerView = true;
- }
- update();
- }
-
- @Override
- public Object getFeature() {
- return marker;
- }
-
- @Override
- public void addToMap(GoogleMap map) {
- marker = map.addMarker(getMarkerOptions());
- }
-
- @Override
- public void removeFromMap(GoogleMap map) {
- marker.remove();
- marker = null;
- }
-
- private BitmapDescriptor getIcon() {
- if (hasCustomMarkerView) {
- // creating a bitmap from an arbitrary view
- if (iconBitmapDescriptor != null) {
- Bitmap viewBitmap = createDrawable();
- int width = Math.max(iconBitmap.getWidth(), viewBitmap.getWidth());
- int height = Math.max(iconBitmap.getHeight(), viewBitmap.getHeight());
- Bitmap combinedBitmap = Bitmap.createBitmap(width, height, iconBitmap.getConfig());
- Canvas canvas = new Canvas(combinedBitmap);
- canvas.drawBitmap(iconBitmap, 0, 0, null);
- canvas.drawBitmap(viewBitmap, 0, 0, null);
- return BitmapDescriptorFactory.fromBitmap(combinedBitmap);
- } else {
- return BitmapDescriptorFactory.fromBitmap(createDrawable());
- }
- } else if (iconBitmapDescriptor != null) {
- // use local image as a marker
- return iconBitmapDescriptor;
- } else {
- // render the default marker pin
- return BitmapDescriptorFactory.defaultMarker(this.markerHue);
- }
- }
-
- private MarkerOptions createMarkerOptions() {
- MarkerOptions options = new MarkerOptions().position(position);
- if (anchorIsSet) options.anchor(anchorX, anchorY);
- if (calloutAnchorIsSet) options.infoWindowAnchor(calloutAnchorX, calloutAnchorY);
- options.title(title);
- options.snippet(snippet);
- options.rotation(rotation);
- options.flat(flat);
- options.draggable(draggable);
- options.zIndex(zIndex);
- options.icon(getIcon());
- return options;
- }
-
- public void update() {
- if (marker == null) {
- return;
- }
-
- marker.setIcon(getIcon());
-
- if (anchorIsSet) {
- marker.setAnchor(anchorX, anchorY);
- } else {
- marker.setAnchor(0.5f, 1.0f);
- }
-
- if (calloutAnchorIsSet) {
- marker.setInfoWindowAnchor(calloutAnchorX, calloutAnchorY);
- } else {
- marker.setInfoWindowAnchor(0.5f, 0);
- }
- }
-
- public void update(int width, int height) {
- this.width = width;
- this.height = height;
- update();
- }
-
- private Bitmap createDrawable() {
- int width = this.width <= 0 ? 100 : this.width;
- int height = this.height <= 0 ? 100 : this.height;
- this.buildDrawingCache();
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-
- Canvas canvas = new Canvas(bitmap);
- this.draw(canvas);
-
- return bitmap;
- }
-
- public void setCalloutView(AirMapCallout view) {
- this.calloutView = view;
- }
-
- public AirMapCallout getCalloutView() {
- return this.calloutView;
- }
-
- public View getCallout() {
- if (this.calloutView == null) return null;
-
- if (this.wrappedCalloutView == null) {
- this.wrapCalloutView();
- }
-
- if (this.calloutView.getTooltip()) {
- return this.wrappedCalloutView;
- } else {
- return null;
- }
- }
-
- public View getInfoContents() {
- if (this.calloutView == null) return null;
-
- if (this.wrappedCalloutView == null) {
- this.wrapCalloutView();
- }
-
- if (this.calloutView.getTooltip()) {
- return null;
- } else {
- return this.wrappedCalloutView;
- }
- }
-
- private void wrapCalloutView() {
- // some hackery is needed to get the arbitrary infowindow view to render centered, and
- // with only the width/height that it needs.
- if (this.calloutView == null || this.calloutView.getChildCount() == 0) {
- return;
- }
-
- LinearLayout LL = new LinearLayout(context);
- LL.setOrientation(LinearLayout.VERTICAL);
- LL.setLayoutParams(new LinearLayout.LayoutParams(
- this.calloutView.width,
- this.calloutView.height,
- 0f
- ));
-
-
- LinearLayout LL2 = new LinearLayout(context);
- LL2.setOrientation(LinearLayout.HORIZONTAL);
- LL2.setLayoutParams(new LinearLayout.LayoutParams(
- this.calloutView.width,
- this.calloutView.height,
- 0f
- ));
-
- LL.addView(LL2);
- LL2.addView(this.calloutView);
-
- this.wrappedCalloutView = LL;
- }
-
- private int getDrawableResourceByName(String name) {
- return getResources().getIdentifier(
- name,
- "drawable",
- getContext().getPackageName());
- }
-
- private BitmapDescriptor getBitmapDescriptorByName(String name) {
- return BitmapDescriptorFactory.fromResource(getDrawableResourceByName(name));
- }
-
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapMarkerManager.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapMarkerManager.java
deleted file mode 100644
index f6da4c1cd..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapMarkerManager.java
+++ /dev/null
@@ -1,204 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.graphics.Color;
-import android.view.View;
-
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.LayoutShadowNode;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.ViewGroupManager;
-import com.facebook.react.uimanager.annotations.ReactProp;
-import com.google.android.gms.maps.model.Marker;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.annotation.Nullable;
-
-public class AirMapMarkerManager extends ViewGroupManager {
-
- private static final int SHOW_INFO_WINDOW = 1;
- private static final int HIDE_INFO_WINDOW = 2;
-
- public AirMapMarkerManager() {
- }
-
- @Override
- public String getName() {
- return "AIRMapMarker";
- }
-
- @Override
- public AirMapMarker createViewInstance(ThemedReactContext context) {
- return new AirMapMarker(context);
- }
-
- @ReactProp(name = "coordinate")
- public void setCoordinate(AirMapMarker view, ReadableMap map) {
- view.setCoordinate(map);
- }
-
- @ReactProp(name = "title")
- public void setTitle(AirMapMarker view, String title) {
- view.setTitle(title);
- }
-
- @ReactProp(name = "identifier")
- public void setIdentifier(AirMapMarker view, String identifier) {
- view.setIdentifier(identifier);
- }
-
- @ReactProp(name = "description")
- public void setDescription(AirMapMarker view, String description) {
- view.setSnippet(description);
- }
-
- // NOTE(lmr):
- // android uses normalized coordinate systems for this, and is provided through the
- // `anchor` property and `calloutAnchor` instead. Perhaps some work could be done
- // to normalize iOS and android to use just one of the systems.
-// @ReactProp(name = "centerOffset")
-// public void setCenterOffset(AirMapMarker view, ReadableMap map) {
-//
-// }
-//
-// @ReactProp(name = "calloutOffset")
-// public void setCalloutOffset(AirMapMarker view, ReadableMap map) {
-//
-// }
-
- @ReactProp(name = "anchor")
- public void setAnchor(AirMapMarker view, ReadableMap map) {
- // should default to (0.5, 1) (bottom middle)
- double x = map != null && map.hasKey("x") ? map.getDouble("x") : 0.5;
- double y = map != null && map.hasKey("y") ? map.getDouble("y") : 1.0;
- view.setAnchor(x, y);
- }
-
- @ReactProp(name = "calloutAnchor")
- public void setCalloutAnchor(AirMapMarker view, ReadableMap map) {
- // should default to (0.5, 0) (top middle)
- double x = map != null && map.hasKey("x") ? map.getDouble("x") : 0.5;
- double y = map != null && map.hasKey("y") ? map.getDouble("y") : 0.0;
- view.setCalloutAnchor(x, y);
- }
-
- @ReactProp(name = "image")
- public void setImage(AirMapMarker view, @Nullable String source) {
- view.setImage(source);
- }
-// public void setImage(AirMapMarker view, ReadableMap image) {
-// view.setImage(image);
-// }
-
- @ReactProp(name = "pinColor", defaultInt = Color.RED, customType = "Color")
- public void setPinColor(AirMapMarker view, int pinColor) {
- float[] hsv = new float[3];
- Color.colorToHSV(pinColor, hsv);
- // NOTE: android only supports a hue
- view.setMarkerHue(hsv[0]);
- }
-
- @ReactProp(name = "rotation", defaultFloat = 0.0f)
- public void setMarkerRotation(AirMapMarker view, float rotation) {
- view.setRotation(rotation);
- }
-
- @ReactProp(name = "flat", defaultBoolean = false)
- public void setFlat(AirMapMarker view, boolean flat) {
- view.setFlat(flat);
- }
-
- @ReactProp(name = "draggable", defaultBoolean = false)
- public void setDraggable(AirMapMarker view, boolean draggable) {
- view.setDraggable(draggable);
- }
-
- @Override
- @ReactProp(name = "zIndex", defaultFloat = 0.0f)
- public void setZIndex(AirMapMarker view, float zIndex) {
- super.setZIndex(view, zIndex);
- int integerZIndex = Math.round(zIndex);
- view.setZIndex(integerZIndex);
- }
-
- @Override
- public void addView(AirMapMarker parent, View child, int index) {
- // if an component is a child, then it is a callout view, NOT part of the
- // marker.
- if (child instanceof AirMapCallout) {
- parent.setCalloutView((AirMapCallout) child);
- } else {
- super.addView(parent, child, index);
- parent.update();
- }
- }
-
- @Override
- public void removeViewAt(AirMapMarker parent, int index) {
- super.removeViewAt(parent, index);
- parent.update();
- }
-
- @Override
- @Nullable
- public Map getCommandsMap() {
- return MapBuilder.of(
- "showCallout", SHOW_INFO_WINDOW,
- "hideCallout", HIDE_INFO_WINDOW
- );
- }
-
- @Override
- public void receiveCommand(AirMapMarker view, int commandId, @Nullable ReadableArray args) {
- switch (commandId) {
- case SHOW_INFO_WINDOW:
- ((Marker) view.getFeature()).showInfoWindow();
- break;
-
- case HIDE_INFO_WINDOW:
- ((Marker) view.getFeature()).hideInfoWindow();
- break;
- }
- }
-
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- Map> map = MapBuilder.of(
- "onPress", MapBuilder.of("registrationName", "onPress"),
- "onCalloutPress", MapBuilder.of("registrationName", "onCalloutPress"),
- "onDragStart", MapBuilder.of("registrationName", "onDragStart"),
- "onDrag", MapBuilder.of("registrationName", "onDrag"),
- "onDragEnd", MapBuilder.of("registrationName", "onDragEnd")
- );
-
- map.putAll(MapBuilder.of(
- "onDragStart", MapBuilder.of("registrationName", "onDragStart"),
- "onDrag", MapBuilder.of("registrationName", "onDrag"),
- "onDragEnd", MapBuilder.of("registrationName", "onDragEnd")
- ));
-
- return map;
- }
-
- @Override
- public LayoutShadowNode createShadowNodeInstance() {
- // we use a custom shadow node that emits the width/height of the view
- // after layout with the updateExtraData method. Without this, we can't generate
- // a bitmap of the appropriate width/height of the rendered view.
- return new SizeReportingShadowNode();
- }
-
- @Override
- public void updateExtraData(AirMapMarker view, Object extraData) {
- // This method is called from the shadow node with the width/height of the rendered
- // marker view.
- HashMap data = (HashMap) extraData;
- float width = data.get("width");
- float height = data.get("height");
- view.update((int) width, (int) height);
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygon.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygon.java
deleted file mode 100644
index 226bc241c..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygon.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.ReadableMap;
-import com.google.android.gms.maps.GoogleMap;
-import com.google.android.gms.maps.model.LatLng;
-import com.google.android.gms.maps.model.Polygon;
-import com.google.android.gms.maps.model.PolygonOptions;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class AirMapPolygon extends AirMapFeature {
-
- private PolygonOptions polygonOptions;
- private Polygon polygon;
-
- private List coordinates;
- private int strokeColor;
- private int fillColor;
- private float strokeWidth;
- private boolean geodesic;
- private float zIndex;
-
- public AirMapPolygon(Context context) {
- super(context);
- }
-
- public void setCoordinates(ReadableArray coordinates) {
- // it's kind of a bummer that we can't run map() or anything on the ReadableArray
- this.coordinates = new ArrayList<>(coordinates.size());
- for (int i = 0; i < coordinates.size(); i++) {
- ReadableMap coordinate = coordinates.getMap(i);
- this.coordinates.add(i,
- new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude")));
- }
- if (polygon != null) {
- polygon.setPoints(this.coordinates);
- }
- }
-
- public void setFillColor(int color) {
- this.fillColor = color;
- if (polygon != null) {
- polygon.setFillColor(color);
- }
- }
-
- public void setStrokeColor(int color) {
- this.strokeColor = color;
- if (polygon != null) {
- polygon.setStrokeColor(color);
- }
- }
-
- public void setStrokeWidth(float width) {
- this.strokeWidth = width;
- if (polygon != null) {
- polygon.setStrokeWidth(width);
- }
- }
-
- public void setGeodesic(boolean geodesic) {
- this.geodesic = geodesic;
- if (polygon != null) {
- polygon.setGeodesic(geodesic);
- }
- }
-
- public void setZIndex(float zIndex) {
- this.zIndex = zIndex;
- if (polygon != null) {
- polygon.setZIndex(zIndex);
- }
- }
-
- public PolygonOptions getPolygonOptions() {
- if (polygonOptions == null) {
- polygonOptions = createPolygonOptions();
- }
- return polygonOptions;
- }
-
- private PolygonOptions createPolygonOptions() {
- PolygonOptions options = new PolygonOptions();
- options.addAll(coordinates);
- options.fillColor(fillColor);
- options.strokeColor(strokeColor);
- options.strokeWidth(strokeWidth);
- options.geodesic(geodesic);
- options.zIndex(zIndex);
- return options;
- }
-
- @Override
- public Object getFeature() {
- return polygon;
- }
-
- @Override
- public void addToMap(GoogleMap map) {
- polygon = map.addPolygon(getPolygonOptions());
- polygon.setClickable(true);
- }
-
- @Override
- public void removeFromMap(GoogleMap map) {
- polygon.remove();
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygonManager.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygonManager.java
deleted file mode 100644
index 3eaa0e550..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygonManager.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.os.Build;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
-
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.ViewGroupManager;
-import com.facebook.react.uimanager.annotations.ReactProp;
-
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.Nullable;
-
-public class AirMapPolygonManager extends ViewGroupManager {
- private final DisplayMetrics metrics;
-
- public AirMapPolygonManager(ReactApplicationContext reactContext) {
- super();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- metrics = new DisplayMetrics();
- ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay()
- .getRealMetrics(metrics);
- } else {
- metrics = reactContext.getResources().getDisplayMetrics();
- }
- }
-
- @Override
- public String getName() {
- return "AIRMapPolygon";
- }
-
- @Override
- public AirMapPolygon createViewInstance(ThemedReactContext context) {
- return new AirMapPolygon(context);
- }
-
- @ReactProp(name = "coordinates")
- public void setCoordinate(AirMapPolygon view, ReadableArray coordinates) {
- view.setCoordinates(coordinates);
- }
-
- @ReactProp(name = "strokeWidth", defaultFloat = 1f)
- public void setStrokeWidth(AirMapPolygon view, float widthInPoints) {
- float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
- view.setStrokeWidth(widthInScreenPx);
- }
-
- @ReactProp(name = "fillColor", defaultInt = Color.RED, customType = "Color")
- public void setFillColor(AirMapPolygon view, int color) {
- view.setFillColor(color);
- }
-
- @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
- public void setStrokeColor(AirMapPolygon view, int color) {
- view.setStrokeColor(color);
- }
-
- @ReactProp(name = "geodesic", defaultBoolean = false)
- public void setGeodesic(AirMapPolygon view, boolean geodesic) {
- view.setGeodesic(geodesic);
- }
-
- @ReactProp(name = "zIndex", defaultFloat = 1.0f)
- public void setZIndex(AirMapPolygon view, float zIndex) {
- view.setZIndex(zIndex);
- }
-
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- return MapBuilder.of(
- "onPress", MapBuilder.of("registrationName", "onPress")
- );
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapPolyline.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapPolyline.java
deleted file mode 100644
index 9a15fdc99..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapPolyline.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.ReadableMap;
-import com.google.android.gms.maps.GoogleMap;
-import com.google.android.gms.maps.model.LatLng;
-import com.google.android.gms.maps.model.Polyline;
-import com.google.android.gms.maps.model.PolylineOptions;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class AirMapPolyline extends AirMapFeature {
-
- private PolylineOptions polylineOptions;
- private Polyline polyline;
-
- private List coordinates;
- private int color;
- private float width;
- private boolean geodesic;
- private float zIndex;
-
- public AirMapPolyline(Context context) {
- super(context);
- }
-
- public void setCoordinates(ReadableArray coordinates) {
- this.coordinates = new ArrayList<>(coordinates.size());
- for (int i = 0; i < coordinates.size(); i++) {
- ReadableMap coordinate = coordinates.getMap(i);
- this.coordinates.add(i,
- new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude")));
- }
- if (polyline != null) {
- polyline.setPoints(this.coordinates);
- }
- }
-
- public void setColor(int color) {
- this.color = color;
- if (polyline != null) {
- polyline.setColor(color);
- }
- }
-
- public void setWidth(float width) {
- this.width = width;
- if (polyline != null) {
- polyline.setWidth(width);
- }
- }
-
- public void setZIndex(float zIndex) {
- this.zIndex = zIndex;
- if (polyline != null) {
- polyline.setZIndex(zIndex);
- }
- }
-
- public void setGeodesic(boolean geodesic) {
- this.geodesic = geodesic;
- if (polyline != null) {
- polyline.setGeodesic(geodesic);
- }
- }
-
- public PolylineOptions getPolylineOptions() {
- if (polylineOptions == null) {
- polylineOptions = createPolylineOptions();
- }
- return polylineOptions;
- }
-
- private PolylineOptions createPolylineOptions() {
- PolylineOptions options = new PolylineOptions();
- options.addAll(coordinates);
- options.color(color);
- options.width(width);
- options.geodesic(geodesic);
- options.zIndex(zIndex);
- return options;
- }
-
- @Override
- public Object getFeature() {
- return polyline;
- }
-
- @Override
- public void addToMap(GoogleMap map) {
- polyline = map.addPolyline(getPolylineOptions());
- polyline.setClickable(true);
- }
-
- @Override
- public void removeFromMap(GoogleMap map) {
- polyline.remove();
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapPolylineManager.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapPolylineManager.java
deleted file mode 100644
index c5afc61e0..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapPolylineManager.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-import android.graphics.Color;
-import android.os.Build;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
-
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.common.MapBuilder;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.ViewGroupManager;
-import com.facebook.react.uimanager.annotations.ReactProp;
-
-import java.util.HashMap;
-import java.util.Map;
-import javax.annotation.Nullable;
-
-public class AirMapPolylineManager extends ViewGroupManager {
- private final DisplayMetrics metrics;
-
- public AirMapPolylineManager(ReactApplicationContext reactContext) {
- super();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- metrics = new DisplayMetrics();
- ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay()
- .getRealMetrics(metrics);
- } else {
- metrics = reactContext.getResources().getDisplayMetrics();
- }
- }
-
- @Override
- public String getName() {
- return "AIRMapPolyline";
- }
-
- @Override
- public AirMapPolyline createViewInstance(ThemedReactContext context) {
- return new AirMapPolyline(context);
- }
-
- @ReactProp(name = "coordinates")
- public void setCoordinate(AirMapPolyline view, ReadableArray coordinates) {
- view.setCoordinates(coordinates);
- }
-
- @ReactProp(name = "strokeWidth", defaultFloat = 1f)
- public void setStrokeWidth(AirMapPolyline view, float widthInPoints) {
- float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
- view.setWidth(widthInScreenPx);
- }
-
- @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
- public void setStrokeColor(AirMapPolyline view, int color) {
- view.setColor(color);
- }
-
- @ReactProp(name = "geodesic", defaultBoolean = false)
- public void setGeodesic(AirMapPolyline view, boolean geodesic) {
- view.setGeodesic(geodesic);
- }
-
- @ReactProp(name = "zIndex", defaultFloat = 1.0f)
- public void setZIndex(AirMapPolyline view, float zIndex) {
- view.setZIndex(zIndex);
- }
-
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- return MapBuilder.of(
- "onPress", MapBuilder.of("registrationName", "onPress")
- );
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTile.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTile.java
deleted file mode 100644
index 691c2fd3c..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTile.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-
-import com.google.android.gms.maps.GoogleMap;
-import com.google.android.gms.maps.model.TileOverlay;
-import com.google.android.gms.maps.model.TileOverlayOptions;
-import com.google.android.gms.maps.model.UrlTileProvider;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-public class AirMapUrlTile extends AirMapFeature {
-
- class AIRMapUrlTileProvider extends UrlTileProvider
- {
- private String urlTemplate;
- public AIRMapUrlTileProvider(int width, int height, String urlTemplate) {
- super(width, height);
- this.urlTemplate = urlTemplate;
- }
- @Override
- public synchronized URL getTileUrl(int x, int y, int zoom) {
-
- String s = this.urlTemplate
- .replace("{x}", Integer.toString(x))
- .replace("{y}", Integer.toString(y))
- .replace("{z}", Integer.toString(zoom));
- URL url = null;
- try {
- url = new URL(s);
- } catch (MalformedURLException e) {
- throw new AssertionError(e);
- }
- return url;
- }
-
- public void setUrlTemplate(String urlTemplate) {
- this.urlTemplate = urlTemplate;
- }
- }
-
- private TileOverlayOptions tileOverlayOptions;
- private TileOverlay tileOverlay;
- private AIRMapUrlTileProvider tileProvider;
-
- private String urlTemplate;
- private float zIndex;
-
- public AirMapUrlTile(Context context) {
- super(context);
- }
-
- public void setUrlTemplate(String urlTemplate) {
- this.urlTemplate = urlTemplate;
- if (tileProvider != null) {
- tileProvider.setUrlTemplate(urlTemplate);
- }
- if (tileOverlay != null) {
- tileOverlay.clearTileCache();
- }
- }
-
- public void setZIndex(float zIndex) {
- this.zIndex = zIndex;
- if (tileOverlay != null) {
- tileOverlay.setZIndex(zIndex);
- }
- }
-
- public TileOverlayOptions getTileOverlayOptions() {
- if (tileOverlayOptions == null) {
- tileOverlayOptions = createTileOverlayOptions();
- }
- return tileOverlayOptions;
- }
-
- private TileOverlayOptions createTileOverlayOptions() {
- TileOverlayOptions options = new TileOverlayOptions();
- options.zIndex(zIndex);
- this.tileProvider = new AIRMapUrlTileProvider(256, 256, this.urlTemplate);
- options.tileProvider(this.tileProvider);
- return options;
- }
-
- @Override
- public Object getFeature() {
- return tileOverlay;
- }
-
- @Override
- public void addToMap(GoogleMap map) {
- this.tileOverlay = map.addTileOverlay(getTileOverlayOptions());
- }
-
- @Override
- public void removeFromMap(GoogleMap map) {
- tileOverlay.remove();
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTileManager.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTileManager.java
deleted file mode 100644
index 7ea0726dc..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTileManager.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-import android.os.Build;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
-
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.ViewGroupManager;
-import com.facebook.react.uimanager.annotations.ReactProp;
-
-public class AirMapUrlTileManager extends ViewGroupManager {
- private DisplayMetrics metrics;
-
- public AirMapUrlTileManager(ReactApplicationContext reactContext) {
- super();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- metrics = new DisplayMetrics();
- ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay()
- .getRealMetrics(metrics);
- } else {
- metrics = reactContext.getResources().getDisplayMetrics();
- }
- }
-
- @Override
- public String getName() {
- return "AIRMapUrlTile";
- }
-
- @Override
- public AirMapUrlTile createViewInstance(ThemedReactContext context) {
- return new AirMapUrlTile(context);
- }
-
- @ReactProp(name = "urlTemplate")
- public void setUrlTemplate(AirMapUrlTile view, String urlTemplate) {
- view.setUrlTemplate(urlTemplate);
- }
-
- @ReactProp(name = "zIndex", defaultFloat = -1.0f)
- public void setZIndex(AirMapUrlTile view, float zIndex) {
- view.setZIndex(zIndex);
- }
-
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java b/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java
deleted file mode 100644
index 76686a41e..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java
+++ /dev/null
@@ -1,836 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.content.res.ColorStateList;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Point;
-import android.graphics.PorterDuff;
-import android.os.Build;
-import android.os.Handler;
-import android.support.v4.view.GestureDetectorCompat;
-import android.support.v4.view.MotionEventCompat;
-import android.view.GestureDetector;
-import android.view.MotionEvent;
-import android.view.ScaleGestureDetector;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
-import android.util.Log;
-
-import com.facebook.react.bridge.LifecycleEventListener;
-import com.facebook.react.bridge.ReadableArray;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.bridge.WritableArray;
-import com.facebook.react.bridge.WritableNativeMap;
-import com.facebook.react.bridge.WritableNativeArray;
-import com.facebook.react.uimanager.ThemedReactContext;
-import com.facebook.react.uimanager.UIManagerModule;
-import com.facebook.react.uimanager.events.EventDispatcher;
-import com.google.android.gms.maps.CameraUpdate;
-import com.google.android.gms.maps.CameraUpdateFactory;
-import com.google.android.gms.maps.GoogleMap;
-import com.google.android.gms.maps.GoogleMapOptions;
-import com.google.android.gms.maps.MapView;
-import com.google.android.gms.maps.OnMapReadyCallback;
-import com.google.android.gms.maps.Projection;
-import com.google.android.gms.maps.model.CameraPosition;
-import com.google.android.gms.maps.model.LatLng;
-import com.google.android.gms.maps.model.LatLngBounds;
-import com.google.android.gms.maps.model.Marker;
-import com.google.android.gms.maps.model.Polygon;
-import com.google.android.gms.maps.model.Polyline;
-
-import com.google.maps.android.geojson.GeoJsonFeature;
-import com.google.maps.android.geojson.GeoJsonLayer;
-import com.google.maps.android.geojson.GeoJsonGeometry;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static android.support.v4.content.PermissionChecker.checkSelfPermission;
-
-public class AirMapView extends MapView implements GoogleMap.InfoWindowAdapter,
- GoogleMap.OnMarkerDragListener, OnMapReadyCallback {
- public GoogleMap map;
- private ProgressBar mapLoadingProgressBar;
- private RelativeLayout mapLoadingLayout;
- private ImageView cacheImageView;
- private Boolean isMapLoaded = false;
- private Integer loadingBackgroundColor = null;
- private Integer loadingIndicatorColor = null;
- private final int baseMapPadding = 50;
-
- private LatLngBounds boundsToMove;
- private boolean showUserLocation = false;
- private boolean isMonitoringRegion = false;
- private boolean isTouchDown = false;
- private boolean handlePanDrag = false;
- private boolean moveOnMarkerPress = true;
- private boolean cacheEnabled = false;
-
- private static final String[] PERMISSIONS = new String[] {
- "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION"};
-
- private final List features = new ArrayList<>();
- private final Map markerMap = new HashMap<>();
- private final Map polylineMap = new HashMap<>();
- private final Map polygonMap = new HashMap<>();
- private final ScaleGestureDetector scaleDetector;
- private final GestureDetectorCompat gestureDetector;
- private final AirMapManager manager;
- private boolean paused = false;
- private final ThemedReactContext context;
- private final EventDispatcher eventDispatcher;
-
- public AirMapView(ThemedReactContext reactContext, Context appContext, AirMapManager manager,
- GoogleMapOptions googleMapOptions) {
- super(appContext, googleMapOptions);
-
- this.manager = manager;
- this.context = reactContext;
-
- super.onCreate(null);
- super.onResume();
- super.getMapAsync(this);
-
- final AirMapView view = this;
- scaleDetector =
- new ScaleGestureDetector(reactContext, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
- @Override
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- view.startMonitoringRegion();
- return true; // stop recording this gesture. let mapview handle it.
- }
- });
-
- gestureDetector =
- new GestureDetectorCompat(reactContext, new GestureDetector.SimpleOnGestureListener() {
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- view.startMonitoringRegion();
- return false;
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY) {
- if (handlePanDrag) {
- onPanDrag(e2);
- }
- view.startMonitoringRegion();
- return false;
- }
- });
-
- this.addOnLayoutChangeListener(new OnLayoutChangeListener() {
- @Override public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- if (!paused) {
- AirMapView.this.cacheView();
- }
- }
- });
-
- eventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
- }
-
- @Override
- public void onMapReady(final GoogleMap map) {
- this.map = map;
- this.map.setInfoWindowAdapter(this);
- this.map.setOnMarkerDragListener(this);
-
- manager.pushEvent(this, "onMapReady", new WritableNativeMap());
-
- final AirMapView view = this;
-
- map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
- @Override
- public boolean onMarkerClick(Marker marker) {
- WritableMap event;
-
- event = makeClickEventData(marker.getPosition());
- event.putString("action", "marker-press");
- manager.pushEvent(view, "onMarkerPress", event);
-
- event = makeClickEventData(marker.getPosition());
- event.putString("action", "marker-press");
- manager.pushEvent(markerMap.get(marker), "onPress", event);
-
- // Return false to open the callout info window and center on the marker
- // https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener
- if (view.moveOnMarkerPress) {
- return false;
- } else {
- marker.showInfoWindow();
- return true;
- }
- }
- });
-
- map.setOnPolygonClickListener(new GoogleMap.OnPolygonClickListener() {
- @Override
- public void onPolygonClick(Polygon polygon) {
- WritableMap event = makeClickEventData(polygon.getPoints().get(0));
- event.putString("action", "polygon-press");
- manager.pushEvent(polygonMap.get(polygon), "onPress", event);
- }
- });
-
- map.setOnPolylineClickListener(new GoogleMap.OnPolylineClickListener() {
- @Override
- public void onPolylineClick(Polyline polyline) {
- WritableMap event = makeClickEventData(polyline.getPoints().get(0));
- event.putString("action", "polyline-press");
- manager.pushEvent(polylineMap.get(polyline), "onPress", event);
- }
- });
-
- map.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
- @Override
- public void onInfoWindowClick(Marker marker) {
- WritableMap event;
-
- event = makeClickEventData(marker.getPosition());
- event.putString("action", "callout-press");
- manager.pushEvent(view, "onCalloutPress", event);
-
- event = makeClickEventData(marker.getPosition());
- event.putString("action", "callout-press");
- AirMapMarker markerView = markerMap.get(marker);
- manager.pushEvent(markerView, "onCalloutPress", event);
-
- event = makeClickEventData(marker.getPosition());
- event.putString("action", "callout-press");
- AirMapCallout infoWindow = markerView.getCalloutView();
- if (infoWindow != null) manager.pushEvent(infoWindow, "onPress", event);
- }
- });
-
- map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
- @Override
- public void onMapClick(LatLng point) {
- WritableMap event = makeClickEventData(point);
- event.putString("action", "press");
- manager.pushEvent(view, "onPress", event);
- }
- });
-
- map.setOnPolygonClickListener(new GoogleMap.OnPolygonClickListener() {
- @Override
- public void onPolygonClick (Polygon polygon) {
- WritableMap event = makePolygonClickEventData(polygon);
- event.putString("action", "press");
- manager.pushEvent(view, "onPress", event);
- }
- });
-
- map.setOnPolylineClickListener(new GoogleMap.OnPolylineClickListener(){
- @Override
- public void onPolylineClick(Polyline polyline) {
- WritableMap event = makeLineClickEventData(polyline);
- event.putString("action", "press");
- manager.pushEvent(view, "onPress", event);
- }
- });
-
- map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
- @Override
- public void onMapLongClick(LatLng point) {
- WritableMap event = makeClickEventData(point);
- event.putString("action", "long-press");
- manager.pushEvent(view, "onLongPress", makeClickEventData(point));
- }
- });
-
- map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
- @Override
- public void onCameraChange(CameraPosition position) {
- LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds;
- LatLng center = position.target;
- lastBoundsEmitted = bounds;
- eventDispatcher.dispatchEvent(new RegionChangeEvent(getId(), bounds, center, isTouchDown));
- view.stopMonitoringRegion();
- }
- });
-
- map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
- @Override public void onMapLoaded() {
- isMapLoaded = true;
- AirMapView.this.cacheView();
- }
- });
-
- // We need to be sure to disable location-tracking when app enters background, in-case some
- // other module
- // has acquired a wake-lock and is controlling location-updates, otherwise, location-manager
- // will be left
- // updating location constantly, killing the battery, even though some other location-mgmt
- // module may
- // desire to shut-down location-services.
- LifecycleEventListener lifecycleListener = new LifecycleEventListener() {
- @Override
- public void onHostResume() {
- if (hasPermissions()) {
- //noinspection MissingPermission
- map.setMyLocationEnabled(showUserLocation);
- }
- synchronized (AirMapView.this) {
- AirMapView.this.onResume();
- paused = false;
- }
- }
-
- @Override
- public void onHostPause() {
- if (hasPermissions()) {
- //noinspection MissingPermission
- map.setMyLocationEnabled(false);
- }
- paused = true;
- }
-
- @Override
- public void onHostDestroy() {
- }
- };
-
- context.addLifecycleEventListener(lifecycleListener);
- }
-
- private boolean hasPermissions() {
- return checkSelfPermission(getContext(), PERMISSIONS[0]) == PackageManager.PERMISSION_GRANTED ||
- checkSelfPermission(getContext(), PERMISSIONS[1]) == PackageManager.PERMISSION_GRANTED;
- }
-
- public void setRegion(ReadableMap region) {
- if (region == null) return;
-
- Double lng = region.getDouble("longitude");
- Double lat = region.getDouble("latitude");
- Double lngDelta = region.getDouble("longitudeDelta");
- Double latDelta = region.getDouble("latitudeDelta");
- LatLngBounds bounds = new LatLngBounds(
- new LatLng(lat - latDelta / 2, lng - lngDelta / 2), // southwest
- new LatLng(lat + latDelta / 2, lng + lngDelta / 2) // northeast
- );
- if (super.getHeight() <= 0 || super.getWidth() <= 0) {
- // in this case, our map has not been laid out yet, so we save the bounds in a local
- // variable, and make a guess of zoomLevel 10. Not to worry, though: as soon as layout
- // occurs, we will move the camera to the saved bounds. Note that if we tried to move
- // to the bounds now, it would trigger an exception.
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lng), 10));
- boundsToMove = bounds;
- } else {
- map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0));
- boundsToMove = null;
- }
- }
-
- public void setShowsUserLocation(boolean showUserLocation) {
- this.showUserLocation = showUserLocation; // hold onto this for lifecycle handling
- if (hasPermissions()) {
- //noinspection MissingPermission
- map.setMyLocationEnabled(showUserLocation);
- }
- }
-
- public void setShowsMyLocationButton(boolean showMyLocationButton) {
- if (hasPermissions()) {
- map.getUiSettings().setMyLocationButtonEnabled(showMyLocationButton);
- }
- }
-
- public void setToolbarEnabled(boolean toolbarEnabled) {
- if (hasPermissions()) {
- map.getUiSettings().setMapToolbarEnabled(toolbarEnabled);
- }
- }
-
- public void setCacheEnabled(boolean cacheEnabled) {
- this.cacheEnabled = cacheEnabled;
- this.cacheView();
- }
-
- public void enableMapLoading(boolean loadingEnabled) {
- if (loadingEnabled && !this.isMapLoaded) {
- this.getMapLoadingLayoutView().setVisibility(View.VISIBLE);
- }
- }
-
- public void setMoveOnMarkerPress(boolean moveOnPress) {
- this.moveOnMarkerPress = moveOnPress;
- }
-
- public void setLoadingBackgroundColor(Integer loadingBackgroundColor) {
- this.loadingBackgroundColor = loadingBackgroundColor;
-
- if (this.mapLoadingLayout != null) {
- if (loadingBackgroundColor == null) {
- this.mapLoadingLayout.setBackgroundColor(Color.WHITE);
- } else {
- this.mapLoadingLayout.setBackgroundColor(this.loadingBackgroundColor);
- }
- }
- }
-
- public void setLoadingIndicatorColor(Integer loadingIndicatorColor) {
- this.loadingIndicatorColor = loadingIndicatorColor;
- if (this.mapLoadingProgressBar != null) {
- Integer color = loadingIndicatorColor;
- if (color == null) {
- color = Color.parseColor("#606060");
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- ColorStateList progressTintList = ColorStateList.valueOf(loadingIndicatorColor);
- ColorStateList secondaryProgressTintList = ColorStateList.valueOf(loadingIndicatorColor);
- ColorStateList indeterminateTintList = ColorStateList.valueOf(loadingIndicatorColor);
-
- this.mapLoadingProgressBar.setProgressTintList(progressTintList);
- this.mapLoadingProgressBar.setSecondaryProgressTintList(secondaryProgressTintList);
- this.mapLoadingProgressBar.setIndeterminateTintList(indeterminateTintList);
- } else {
- PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN;
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
- mode = PorterDuff.Mode.MULTIPLY;
- }
- if (this.mapLoadingProgressBar.getIndeterminateDrawable() != null)
- this.mapLoadingProgressBar.getIndeterminateDrawable().setColorFilter(color, mode);
- if (this.mapLoadingProgressBar.getProgressDrawable() != null)
- this.mapLoadingProgressBar.getProgressDrawable().setColorFilter(color, mode);
- }
- }
- }
-
- public void setHandlePanDrag(boolean handlePanDrag) {
- this.handlePanDrag = handlePanDrag;
- }
-
- public void addFeature(View child, int index) {
- // Our desired API is to pass up annotations/overlays as children to the mapview component.
- // This is where we intercept them and do the appropriate underlying mapview action.
- if (child instanceof AirMapMarker) {
- AirMapMarker annotation = (AirMapMarker) child;
- annotation.addToMap(map);
- features.add(index, annotation);
- Marker marker = (Marker) annotation.getFeature();
- markerMap.put(marker, annotation);
- } else if (child instanceof AirMapPolyline) {
- AirMapPolyline polylineView = (AirMapPolyline) child;
- polylineView.addToMap(map);
- features.add(index, polylineView);
- Polyline polyline = (Polyline) polylineView.getFeature();
- polylineMap.put(polyline, polylineView);
- } else if (child instanceof AirMapPolygon) {
- AirMapPolygon polygonView = (AirMapPolygon) child;
- polygonView.addToMap(map);
- features.add(index, polygonView);
- Polygon polygon = (Polygon) polygonView.getFeature();
- polygonMap.put(polygon, polygonView);
- } else if (child instanceof AirMapCircle) {
- AirMapCircle circleView = (AirMapCircle) child;
- circleView.addToMap(map);
- features.add(index, circleView);
- } else if (child instanceof AirMapUrlTile) {
- AirMapUrlTile urlTileView = (AirMapUrlTile) child;
- urlTileView.addToMap(map);
- features.add(index, urlTileView);
- } else if (child instanceof AirMapGeoJSON) {
- AirMapGeoJSON geoJsonView = (AirMapGeoJSON) child;
- geoJsonView.addToMap(map);
- features.add(index, geoJsonView);
- } else {
- // TODO(lmr): throw? User shouldn't be adding non-feature children.
- }
- }
-
- public int getFeatureCount() {
- return features.size();
- }
-
- public View getFeatureAt(int index) {
- return features.get(index);
- }
-
- public void removeFeatureAt(int index) {
- AirMapFeature feature = features.remove(index);
- if (feature instanceof AirMapMarker) {
- markerMap.remove(feature.getFeature());
- } else if(feature instanceof AirMapPolyline){
- polylineMap.remove(feature.getFeature());
- } else if(feature instanceof AirMapPolygon){
- polygonMap.remove(feature.getFeature());
- }
- feature.removeFromMap(map);
- }
-
- public WritableMap makeClickEventData(LatLng point) {
- WritableMap event = new WritableNativeMap();
-
- WritableMap coordinate = new WritableNativeMap();
- coordinate.putDouble("latitude", point.latitude);
- coordinate.putDouble("longitude", point.longitude);
- event.putMap("coordinate", coordinate);
-
- Projection projection = map.getProjection();
- Point screenPoint = projection.toScreenLocation(point);
-
- WritableMap position = new WritableNativeMap();
- position.putDouble("x", screenPoint.x);
- position.putDouble("y", screenPoint.y);
- event.putMap("position", position);
-
- return event;
- }
-
- public WritableMap makePolygonClickEventData(Polygon feature){
- WritableMap event = new WritableNativeMap();
- WritableArray points = new WritableNativeArray();
- List pointList = feature.getPoints();
- for(LatLng point : pointList){
- WritableMap position = new WritableNativeMap();
- position.putDouble("latitude", point.latitude);
- position.putDouble("longitude", point.longitude);
- points.pushMap(position);
- }
- event.putArray("polygon", points);
- //event.putMap("feature", feature);
-
- return event;
- }
-
- public WritableMap makeLineClickEventData(Polyline feature){
- WritableMap event = new WritableNativeMap();
- WritableArray points = new WritableNativeArray();
- List pointList = feature.getPoints();
- for(LatLng point : pointList){
- WritableMap position = new WritableNativeMap();
- position.putDouble("latitude", point.latitude);
- position.putDouble("longitude", point.longitude);
- points.pushMap(position);
- }
- event.putArray("line", points);
- //event.putMap("feature", feature);
-
- return event;
- }
-
- public void updateExtraData(Object extraData) {
- // if boundsToMove is not null, we now have the MapView's width/height, so we can apply
- // a proper camera move
- if (boundsToMove != null) {
- HashMap data = (HashMap) extraData;
- float width = data.get("width");
- float height = data.get("height");
- map.moveCamera(
- CameraUpdateFactory.newLatLngBounds(
- boundsToMove,
- (int) width,
- (int) height,
- 0
- )
- );
- boundsToMove = null;
- }
- }
-
- public void animateToRegion(LatLngBounds bounds, int duration) {
- startMonitoringRegion();
- map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0), duration, null);
- }
-
- public void animateToCoordinate(LatLng coordinate, int duration) {
- startMonitoringRegion();
- map.animateCamera(CameraUpdateFactory.newLatLng(coordinate), duration, null);
- }
-
- public void fitToElements(boolean animated) {
- LatLngBounds.Builder builder = new LatLngBounds.Builder();
-
- boolean addedPosition = false;
-
- for (AirMapFeature feature : features) {
- if (feature instanceof AirMapMarker) {
- Marker marker = (Marker) feature.getFeature();
- builder.include(marker.getPosition());
- addedPosition = true;
- }
- // TODO(lmr): may want to include shapes / etc.
- }
- if (addedPosition) {
- LatLngBounds bounds = builder.build();
- CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
- if (animated) {
- startMonitoringRegion();
- map.animateCamera(cu);
- } else {
- map.moveCamera(cu);
- }
- }
- }
-
- public void fitToSuppliedMarkers(ReadableArray markerIDsArray, boolean animated) {
- LatLngBounds.Builder builder = new LatLngBounds.Builder();
-
- String[] markerIDs = new String[markerIDsArray.size()];
- for (int i = 0; i < markerIDsArray.size(); i++) {
- markerIDs[i] = markerIDsArray.getString(i);
- }
-
- boolean addedPosition = false;
-
- List markerIDList = Arrays.asList(markerIDs);
-
- for (AirMapFeature feature : features) {
- if (feature instanceof AirMapMarker) {
- String identifier = ((AirMapMarker)feature).getIdentifier();
- Marker marker = (Marker)feature.getFeature();
- if (markerIDList.contains(identifier)) {
- builder.include(marker.getPosition());
- addedPosition = true;
- }
- }
- }
-
- if (addedPosition) {
- LatLngBounds bounds = builder.build();
- CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
- if (animated) {
- startMonitoringRegion();
- map.animateCamera(cu);
- } else {
- map.moveCamera(cu);
- }
- }
- }
-
- public void fitToCoordinates(ReadableArray coordinatesArray, ReadableMap edgePadding, boolean animated) {
- LatLngBounds.Builder builder = new LatLngBounds.Builder();
-
- for (int i = 0; i < coordinatesArray.size(); i++) {
- ReadableMap latLng = coordinatesArray.getMap(i);
- Double lat = latLng.getDouble("latitude");
- Double lng = latLng.getDouble("longitude");
- builder.include(new LatLng(lat, lng));
- }
-
- LatLngBounds bounds = builder.build();
- CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
-
- if (edgePadding != null) {
- map.setPadding(edgePadding.getInt("left"), edgePadding.getInt("top"), edgePadding.getInt("right"), edgePadding.getInt("bottom"));
- }
-
- if (animated) {
- startMonitoringRegion();
- map.animateCamera(cu);
- } else {
- map.moveCamera(cu);
- }
- map.setPadding(0, 0, 0, 0); // Without this, the Google logo is moved up by the value of edgePadding.bottom
- }
-
- // InfoWindowAdapter interface
-
- @Override
- public View getInfoWindow(Marker marker) {
- AirMapMarker markerView = markerMap.get(marker);
- return markerView.getCallout();
- }
-
- @Override
- public View getInfoContents(Marker marker) {
- AirMapMarker markerView = markerMap.get(marker);
- return markerView.getInfoContents();
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- scaleDetector.onTouchEvent(ev);
- gestureDetector.onTouchEvent(ev);
-
- int action = MotionEventCompat.getActionMasked(ev);
-
- switch (action) {
- case (MotionEvent.ACTION_DOWN):
- this.getParent().requestDisallowInterceptTouchEvent(true);
- isTouchDown = true;
- break;
- case (MotionEvent.ACTION_MOVE):
- startMonitoringRegion();
- break;
- case (MotionEvent.ACTION_UP):
- this.getParent().requestDisallowInterceptTouchEvent(false);
- isTouchDown = false;
- break;
- }
- super.dispatchTouchEvent(ev);
- return true;
- }
-
- // Timer Implementation
-
- public void startMonitoringRegion() {
- if (isMonitoringRegion) return;
- timerHandler.postDelayed(timerRunnable, 100);
- isMonitoringRegion = true;
- }
-
- public void stopMonitoringRegion() {
- if (!isMonitoringRegion) return;
- timerHandler.removeCallbacks(timerRunnable);
- isMonitoringRegion = false;
- }
-
- private LatLngBounds lastBoundsEmitted;
-
- Handler timerHandler = new Handler();
- Runnable timerRunnable = new Runnable() {
-
- @Override
- public void run() {
-
- LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds;
- if (lastBoundsEmitted == null ||
- LatLngBoundsUtils.BoundsAreDifferent(bounds, lastBoundsEmitted)) {
- LatLng center = map.getCameraPosition().target;
- lastBoundsEmitted = bounds;
- eventDispatcher.dispatchEvent(new RegionChangeEvent(getId(), bounds, center, true));
- }
-
- timerHandler.postDelayed(this, 100);
- }
- };
-
- @Override
- public void onMarkerDragStart(Marker marker) {
- WritableMap event = makeClickEventData(marker.getPosition());
- manager.pushEvent(this, "onMarkerDragStart", event);
-
- AirMapMarker markerView = markerMap.get(marker);
- event = makeClickEventData(marker.getPosition());
- manager.pushEvent(markerView, "onDragStart", event);
- }
-
- @Override
- public void onMarkerDrag(Marker marker) {
- WritableMap event = makeClickEventData(marker.getPosition());
- manager.pushEvent(this, "onMarkerDrag", event);
-
- AirMapMarker markerView = markerMap.get(marker);
- event = makeClickEventData(marker.getPosition());
- manager.pushEvent(markerView, "onDrag", event);
- }
-
- @Override
- public void onMarkerDragEnd(Marker marker) {
- WritableMap event = makeClickEventData(marker.getPosition());
- manager.pushEvent(this, "onMarkerDragEnd", event);
-
- AirMapMarker markerView = markerMap.get(marker);
- event = makeClickEventData(marker.getPosition());
- manager.pushEvent(markerView, "onDragEnd", event);
- }
-
- private ProgressBar getMapLoadingProgressBar() {
- if (this.mapLoadingProgressBar == null) {
- this.mapLoadingProgressBar = new ProgressBar(getContext());
- this.mapLoadingProgressBar.setIndeterminate(true);
- }
- if (this.loadingIndicatorColor != null) {
- this.setLoadingIndicatorColor(this.loadingIndicatorColor);
- }
- return this.mapLoadingProgressBar;
- }
-
- private RelativeLayout getMapLoadingLayoutView() {
- if (this.mapLoadingLayout == null) {
- this.mapLoadingLayout = new RelativeLayout(getContext());
- this.mapLoadingLayout.setBackgroundColor(Color.LTGRAY);
- this.addView(this.mapLoadingLayout,
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
-
- RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
- RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
- params.addRule(RelativeLayout.CENTER_IN_PARENT);
- this.mapLoadingLayout.addView(this.getMapLoadingProgressBar(), params);
-
- this.mapLoadingLayout.setVisibility(View.INVISIBLE);
- }
- this.setLoadingBackgroundColor(this.loadingBackgroundColor);
- return this.mapLoadingLayout;
- }
-
- private ImageView getCacheImageView() {
- if (this.cacheImageView == null) {
- this.cacheImageView = new ImageView(getContext());
- this.addView(this.cacheImageView,
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
- this.cacheImageView.setVisibility(View.INVISIBLE);
- }
- return this.cacheImageView;
- }
-
- private void removeCacheImageView() {
- if (this.cacheImageView != null) {
- ((ViewGroup)this.cacheImageView.getParent()).removeView(this.cacheImageView);
- this.cacheImageView = null;
- }
- }
-
- private void removeMapLoadingProgressBar() {
- if (this.mapLoadingProgressBar != null) {
- ((ViewGroup)this.mapLoadingProgressBar.getParent()).removeView(this.mapLoadingProgressBar);
- this.mapLoadingProgressBar = null;
- }
- }
-
- private void removeMapLoadingLayoutView() {
- this.removeMapLoadingProgressBar();
- if (this.mapLoadingLayout != null) {
- ((ViewGroup)this.mapLoadingLayout.getParent()).removeView(this.mapLoadingLayout);
- this.mapLoadingLayout = null;
- }
- }
-
- private void cacheView() {
- if (this.cacheEnabled) {
- final ImageView cacheImageView = this.getCacheImageView();
- final RelativeLayout mapLoadingLayout = this.getMapLoadingLayoutView();
- cacheImageView.setVisibility(View.INVISIBLE);
- mapLoadingLayout.setVisibility(View.VISIBLE);
- if (this.isMapLoaded) {
- this.map.snapshot(new GoogleMap.SnapshotReadyCallback() {
- @Override public void onSnapshotReady(Bitmap bitmap) {
- cacheImageView.setImageBitmap(bitmap);
- cacheImageView.setVisibility(View.VISIBLE);
- mapLoadingLayout.setVisibility(View.INVISIBLE);
- }
- });
- }
- }
- else {
- this.removeCacheImageView();
- if (this.isMapLoaded) {
- this.removeMapLoadingLayoutView();
- }
- }
- }
-
- public void onPanDrag(MotionEvent ev) {
- Point point = new Point((int) ev.getX(), (int) ev.getY());
- LatLng coords = this.map.getProjection().fromScreenLocation(point);
- WritableMap event = makeClickEventData(coords);
- manager.pushEvent(this, "onPanDrag", event);
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/LatLngBoundsUtils.java b/android/src/main/java/com/airbnb/android/react/maps/LatLngBoundsUtils.java
deleted file mode 100644
index ed1058c88..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/LatLngBoundsUtils.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import com.google.android.gms.maps.model.LatLng;
-import com.google.android.gms.maps.model.LatLngBounds;
-
-public class LatLngBoundsUtils {
- public static boolean BoundsAreDifferent(LatLngBounds a, LatLngBounds b) {
- LatLng centerA = a.getCenter();
- double latA = centerA.latitude;
- double lngA = centerA.longitude;
- double latDeltaA = a.northeast.latitude - a.southwest.latitude;
- double lngDeltaA = a.northeast.longitude - a.southwest.longitude;
-
- LatLng centerB = b.getCenter();
- double latB = centerB.latitude;
- double lngB = centerB.longitude;
- double latDeltaB = b.northeast.latitude - b.southwest.latitude;
- double lngDeltaB = b.northeast.longitude - b.southwest.longitude;
-
- double latEps = LatitudeEpsilon(a, b);
- double lngEps = LongitudeEpsilon(a, b);
-
- return
- different(latA, latB, latEps) ||
- different(lngA, lngB, lngEps) ||
- different(latDeltaA, latDeltaB, latEps) ||
- different(lngDeltaA, lngDeltaB, lngEps);
- }
-
- private static boolean different(double a, double b, double epsilon) {
- return Math.abs(a - b) > epsilon;
- }
-
- private static double LatitudeEpsilon(LatLngBounds a, LatLngBounds b) {
- double sizeA = a.northeast.latitude - a.southwest.latitude; // something mod 180?
- double sizeB = b.northeast.latitude - b.southwest.latitude; // something mod 180?
- double size = Math.min(Math.abs(sizeA), Math.abs(sizeB));
- return size / 2560;
- }
-
- private static double LongitudeEpsilon(LatLngBounds a, LatLngBounds b) {
- double sizeA = a.northeast.longitude - a.southwest.longitude;
- double sizeB = b.northeast.longitude - b.southwest.longitude;
- double size = Math.min(Math.abs(sizeA), Math.abs(sizeB));
- return size / 2560;
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java b/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java
deleted file mode 100644
index d42804436..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import android.app.Activity;
-
-import com.facebook.react.ReactPackage;
-import com.facebook.react.bridge.JavaScriptModule;
-import com.facebook.react.bridge.NativeModule;
-import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.uimanager.ViewManager;
-
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-public class MapsPackage implements ReactPackage {
- public MapsPackage(Activity activity) {
- } // backwards compatability
-
- public MapsPackage() {
- }
-
- @Override
- public List createNativeModules(ReactApplicationContext reactContext) {
- return Collections.emptyList();
- }
-
- @Override
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
- @Override
- public List createViewManagers(ReactApplicationContext reactContext) {
- AirMapCalloutManager calloutManager = new AirMapCalloutManager();
- AirMapMarkerManager annotationManager = new AirMapMarkerManager();
- AirMapPolylineManager polylineManager = new AirMapPolylineManager(reactContext);
- AirMapPolygonManager polygonManager = new AirMapPolygonManager(reactContext);
- AirMapCircleManager circleManager = new AirMapCircleManager(reactContext);
- AirMapGeoJSONManager geoJsonManager = new AirMapGeoJSONManager(reactContext);
- AirMapManager mapManager = new AirMapManager(reactContext);
- AirMapLiteManager mapLiteManager = new AirMapLiteManager(reactContext);
- AirMapUrlTileManager tileManager = new AirMapUrlTileManager(reactContext);
-
- return Arrays.asList(
- calloutManager,
- annotationManager,
- polylineManager,
- polygonManager,
- circleManager,
- geoJsonManager,
- mapManager,
- mapLiteManager,
- tileManager);
- }
-}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/RegionChangeEvent.java b/android/src/main/java/com/airbnb/android/react/maps/RegionChangeEvent.java
deleted file mode 100644
index 28a3b322b..000000000
--- a/android/src/main/java/com/airbnb/android/react/maps/RegionChangeEvent.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.airbnb.android.react.maps;
-
-import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.bridge.WritableNativeMap;
-import com.facebook.react.uimanager.events.Event;
-import com.facebook.react.uimanager.events.RCTEventEmitter;
-import com.google.android.gms.maps.model.LatLng;
-import com.google.android.gms.maps.model.LatLngBounds;
-
-public class RegionChangeEvent extends Event {
- private final LatLngBounds bounds;
- private final LatLng center;
- private final boolean continuous;
-
- public RegionChangeEvent(int id, LatLngBounds bounds, LatLng center, boolean continuous) {
- super(id);
- this.bounds = bounds;
- this.center = center;
- this.continuous = continuous;
- }
-
- @Override
- public String getEventName() {
- return "topChange";
- }
-
- @Override
- public boolean canCoalesce() {
- return false;
- }
-
- @Override
- public void dispatch(RCTEventEmitter rctEventEmitter) {
-
- WritableMap event = new WritableNativeMap();
- event.putBoolean("continuous", continuous);
-
- WritableMap region = new WritableNativeMap();
- region.putDouble("latitude", center.latitude);
- region.putDouble("longitude", center.longitude);
- region.putDouble("latitudeDelta", bounds.northeast.latitude - bounds.southwest.latitude);
- region.putDouble("longitudeDelta", bounds.northeast.longitude - bounds.southwest.longitude);
- event.putMap("region", region);
-
- rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event);
- }
-}
diff --git a/build.gradle b/build.gradle
new file mode 100644
index 000000000..588e5cb99
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,25 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.3.2'
+ }
+}
+
+allprojects {
+ repositories {
+ mavenLocal()
+ jcenter()
+ maven {
+ // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
+ url "$rootDir/node_modules/react-native/android"
+ }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/docs/circle.md b/docs/circle.md
index 78a850283..992ac4567 100644
--- a/docs/circle.md
+++ b/docs/circle.md
@@ -7,10 +7,11 @@
| `center` | `LatLng` | (Required) | The coordinate of the center of the circle
| `radius` | `Number` | (Required) | The radius of the circle to be drawn (in meters)
| `strokeWidth` | `Number` | `1` | The stroke width to use for the path.
-| `strokeColor` | `String` | `#000` | The stroke color to use for the path.
-| `fillColor` | `String` | | The fill color to use for the path.
-| `lineCap` | `String` | `round` | The line cap style to apply to the open ends of the path.
-| `lineJoin` | `Array` | | The line join style to apply to corners of the path.
+| `strokeColor` | `String` | `#000`, `rgba(r,g,b,0.5)` | The stroke color to use for the path.
+| `fillColor` | `String` | `#000`, `rgba(r,g,b,0.5)` | The fill color to use for the path.
+| `zIndex` | `Number` | 0 | The order in which this tile overlay is drawn with respect to other overlays. An overlay with a larger z-index is drawn over overlays with smaller z-indices. The order of overlays with the same z-index is arbitrary. The default zIndex is 0. (Android Only)
+| `lineCap` | `String` | `round` | The line cap style to apply to the open ends of the path. Other values : `butt`, `square`
+| `lineJoin` | `String` | | The line join style to apply to corners of the path. possible value: `miter`, `round`, `bevel`
| `miterLimit` | `Number` | | The limiting value that helps avoid spikes at junctions between connected line segments. The miter limit helps you avoid spikes in paths that use the `miter` `lineJoin` style. If the ratio of the miter length—that is, the diagonal length of the miter join—to the line thickness exceeds the miter limit, the joint is converted to a bevel join. The default miter limit is 10, which results in the conversion of miters whose angle at the joint is less than 11 degrees.
| `geodesic` | `Boolean` | | Boolean to indicate whether to draw each segment of the line as a geodesic as opposed to straight lines on the Mercator projection. A geodesic is the shortest path between two points on the Earth's surface. The geodesic curve is constructed assuming the Earth is a sphere.
| `lineDashPhase` | `Number` | `0` | (iOS only) The offset (in points) at which to start drawing the dash pattern. Use this property to start drawing a dashed line partway through a segment or gap. For example, a phase value of 6 for the patter 5-2-3-2 would cause drawing to begin in the middle of the first gap.
diff --git a/docs/installation.md b/docs/installation.md
index c14995999..acd1f4657 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -6,29 +6,34 @@ First, download the library from npm:
npm install react-native-maps --save
```
-Then you must install the native dependencies: You can use `rnpm` (now part of `react-native` core) to
+Second, install the native dependencies: You can use `rnpm` (now part of `react-native` core via `link`) to
add native dependencies automatically then continue the directions below depending on your target OS.
- `$ react-native link`
+```
+react-native link react-native-maps
+```
>This installation should work in physical devices. For Genymotion, be sure to check Android installation about Google Play Services
## iOS
+> These options may not be necessary if you ran "react-native link"
+
### Option 1: CocoaPods - Same as the included AirMapsExplorer example
-1. Setup your `Podfile` like the included [example/ios/Podfile](../example/ios/Podfile) then run `pod install`.
+1. Setup your `Podfile` like the included [example/ios/Podfile](../example/ios/Podfile), replace all references to `AirMapsExplorer` with your project name, and then run `pod install`.
(If you do not need `GoogleMaps` support for iOS, then you can probably completely skip this step.)
1. Open your project in Xcode workspace
-1. Drag the following folder into your project:
- - `node_modules/react-native-maps/ios/AirMaps/`
-1. If you need `GoogleMaps` support also drag this folder into your project:
- - `node_modules/react-native-maps/ios/AirGoogleMaps/`
+1. If you need `GoogleMaps` support also
+ - Drag this folder `node_modules/react-native-maps/lib/ios/AirGoogleMaps/` into your project, and choose `Create groups` and `Copy items if needed` in the popup window.
+ - In `AppDelegate.m`, add `@import GoogleMaps;` before `@implementation AppDelegate`. In `- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions`, add `[GMSServices provideAPIKey:@"YOUR_GOOGLE_MAP_API_KEY"];`
+ - In your project's `Build Settings` > `Header Search Paths`, double click the value field. In the popup, add `$(SRCROOT)/../node_modules/react-native-maps/lib/ios/AirMaps` and change `non-recursive` to `recursive`. (Dragging the folder `node_modules/react-native-maps/lib/ios/AirMaps/` into your project introduces duplicate symbols. We should not do it.)
+
+Note: We recommend using a version of React Native >= .40. Newer versions (>= .40) require `package.json` to be set to `"react-native-maps": "^0.13.0"`, while older versions require `"react-native-maps": "^0.12.4"`.
-### Option 2: CocoaPods -- Untested Way
-NOTE: If you actually get this to work, please open an issue to let us know.
-This is now considered the **old way** because it is untested and if it does work at all, it
-will only work if you **don't** have `use_frameworks!` in your `Podfile`
+### Option 2: CocoaPods
+This is now considered the **old way** because it will only work if you **don't** have
+`use_frameworks!` in your `Podfile`.
To install using Cocoapods, simply insert the following line into your `Podfile`:
@@ -44,8 +49,10 @@ Now if you need `GoogleMaps` support you will also have to add a bunch of other
After your `Podfile` is setup properly, run `pod install`.
### Option 3: Manually
+ >This was already done for you if you ran "react-native link"
+
1. Open your project in Xcode, right click on `Libraries` and click `Add
- Files to "Your Project Name"` Look under `node_modules/react-native-maps/ios` and add `AIRMaps.xcodeproj`.
+ Files to "Your Project Name"` Look under `node_modules/react-native-maps/lib/ios` and add `AIRMaps.xcodeproj`.
1. Add `libAIRMaps.a` to `Build Phases -> Link Binary With Libraries.
1. Click on `AIRMaps.xcodeproj` in `Libraries` and go the `Build
Settings` tab. Double click the text to the right of `Header Search
@@ -60,6 +67,8 @@ After your `Podfile` is setup properly, run `pod install`.
## Android
1. In your `android/app/build.gradle` add:
+ >This step is not necessary if you ran "react-native link react-native-maps"
+
```groovy
...
dependencies {
@@ -68,17 +77,34 @@ After your `Podfile` is setup properly, run `pod install`.
}
```
+ If you have a different play services than the one included in this library, use the following instead (switch 10.0.1 for the desired version):
+
+ ```groovy
+ ...
+ dependencies {
+ ...
+ compile(project(':react-native-maps')){
+ exclude group: 'com.google.android.gms', module: 'play-services-base'
+ exclude group: 'com.google.android.gms', module: 'play-services-maps'
+ }
+ compile 'com.google.android.gms:play-services-base:10.0.1'
+ compile 'com.google.android.gms:play-services-maps:10.0.1'
+ }
+ ```
+
1. In your `android/settings.gradle` add:
+ >This step is not necessary if you ran "react-native link"
+
```groovy
...
include ':react-native-maps'
- project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-maps/android')
+ project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-maps/lib/android')
```
1. Specify your Google Maps API Key:
- > For development, it is recommended to use a ***Browser Key*** without referrer restrictions. Go to https://console.developers.google.com/apis/credentials to check your credentials.
+ > For development, you need to get a ***API Key***. Go to https://console.developers.google.com/apis/credentials to check your credentials.
- Add your **Browser** API key to your manifest file (`android\app\src\main\AndroidManifest.xml`):
+ Add your API key to your manifest file (`android\app\src\main\AndroidManifest.xml`):
```xml
@@ -87,41 +113,47 @@ After your `Podfile` is setup properly, run `pod install`.
android:name="com.google.android.geo.API_KEY"
android:value="Your Google maps API Key Here"/>
- ```
- > If that doesn't work, try using an ***Android Key*** without referrer restrictions. Go to https://console.developers.google.com/apis/credentials to check your credentials.
-
- Add your **Android** API key to your manifest file:
-
- ```xml
-
-
-
-
```
> Note: As shown above, com.google.android.geo.API_KEY is the recommended metadata name for the API key. A key with this name can be used to authenticate to multiple Google Maps-based APIs on the Android platform, including the Google Maps Android API. For backwards compatibility, the API also supports the name com.google.android.maps.v2.API_KEY. This legacy name allows authentication to the Android Maps API v2 only. An application can specify only one of the API key metadata names. If both are specified, the API throws an exception.
Source: https://developers.google.com/maps/documentation/android-api/signup
1. Ensure that you have Google Play Services installed:
- * For Genymotion you can follow [these instructions](http://stackoverflow.com/a/20137324/1424349).
+ * For Genymotion you can follow [these instructions](https://www.genymotion.com/help/desktop/faq/#google-play-services).
* For a physical device you need to search on Google for 'Google Play Services'. There will be a link that takes you to the Play Store and from there you will see a button to update it (do not search within the Play Store).
## Troubleshooting
-If you have a blank map issue, ([#118](https://github.com/airbnb/react-native-maps/issues/118), [#176](https://github.com/airbnb/react-native-maps/issues/176)) try the following lines :
+If you get the error `duplicate symbols for architecture x86_64` when building for iOS, you may need to reconfigure your linking and Podfile as [described in detail in this comment on issue #718](https://github.com/airbnb/react-native-maps/issues/718#issuecomment-295585410)
+
+If you have a blank map issue, ([#118](https://github.com/airbnb/react-native-maps/issues/118), [#176](https://github.com/airbnb/react-native-maps/issues/176), [#684](https://github.com/airbnb/react-native-maps/issues/684)), try the following lines :
### On iOS:
You have to link dependencies with rnpm and re-run the build:
-1. `rnpm link`
+1. `react-native link react-native-maps`
1. `react-native run-ios`
### On Android:
+1. Be sure to have `new MapsPackage()` in your `MainApplication.java` :
+ >This step is not necessary if you ran "react-native link react-native-maps"
+
+ ```
+ import com.airbnb.android.react.maps.MapsPackage;
+ ...
+ @Override
+ protected List getPackages() {
+ return Arrays.asList(
+ new MainReactPackage(),
+ new MapsPackage()
+ );
+ }
+ ```
+
1. Set this Stylesheet in your map component
```
+ import MapView from 'react-native-maps';
...
const styles = StyleSheet.create({
container: {
@@ -158,26 +190,35 @@ You have to link dependencies with rnpm and re-run the build:
}
}
```
-1. Run "android" and make sure every packages is updated.
+1. Run "android" and make sure all packages are up-to-date.
1. If not installed yet, you have to install the following packages :
- Extras / Google Play services
- Extras / Google Repository
- - Android 6.0 (API 23) / Google APIs Intel x86 Atom System Image Rev. 13
-1. Check manual installation steps
-1. Generate your SHA1 key :
- `keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android`
-
-1. Go to [Google API Console](https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend) and select your project, or create one.
-In `Overview -> Google Maps API -> Google Maps Android API ` -> Check if it's enabled
-Create a new key by clicking on `Create credentials -> API Key -> Android Key`, enter the name of the API key and your SHA1 key, generated before, and create it.
-Check installation step 4.
-
-1. Clean the cache :
- `watchman watch-del-all`
- `npm cache clean`
+ - Android 6.0 (API 23) / Google APIs Intel x86 Atom System Image Rev. 19
+ - Android SDK Build-tools 23.0.3
+1. Check manual installation steps if you didn't run "react-native link react-native-maps"
+1. Go to [Google API Console](https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend) and select your project, or create one.
+Then, once enabled, select `Go to credentials`.
+Select `Google Maps Android API` and create a new key.
+Enter the name of the API key and create it.
+
+1. Clean the cache :
+ ```
+ watchman watch-del-all
+ npm cache clean
+ ```
1. When starting emulator, make sure you have enabled `Wipe user data`.
1. Run `react-native run-android`
-1. At this step it should work, but if not, go to your [Google API Console](https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend&keyType=CLIENT_SIDE_ANDROID&pli=1) and create a `Browser key` instead of a `Android key` and go to step 6.
+1. If you encounter `com.android.dex.DexException: Multiple dex files define Landroid/support/v7/appcompat/R$anim`, then clear build folder.
+ ```
+ cd android
+ ./gradlew clean
+ cd ..
+ ```
+
+1. If you are using Android Virtual Devices (AVD), ensure that `Use Host GPU` is checked in the settings for your virtual device.
+
+1. If using an emulator and the only thing that shows up on the screen is the message: `[APPNAME] won't run without Google Play services which are not supported by your device.`, you need to change the emulator CPU/ABI setting to a system image that includes Google APIs. These may need to be downloaded from the Android SDK Manager first.
diff --git a/docs/mapview.md b/docs/mapview.md
index 3b11e6273..6d3227b4a 100644
--- a/docs/mapview.md
+++ b/docs/mapview.md
@@ -8,32 +8,41 @@
| `region` | `Region` | | The region to be displayed by the map.
The region is defined by the center coordinates and the span of coordinates to display.
| `initialRegion` | `Region` | | The initial region to be displayed by the map. Use this prop instead of `region` only if you don't want to control the viewport of the map besides the initial region.
Changing this prop after the component has mounted will not result in a region change.
This is similar to the `initialValue` prop of a text input.
| `liteMode` | `Boolean` | `false` | Enable lite mode. **Note**: Android only.
-| `mapType` | `String` | `"standard"` | The map type to be displayed.
- standard: standard road map (default) - satellite: satellite view - hybrid: satellite view with roads and points of interest overlayed - terrain: (Android only) topographic view
+| `mapType` | `String` | `"standard"` | The map type to be displayed.
- standard: standard road map (default) - satellite: satellite view - hybrid: satellite view with roads and points of interest overlayed - terrain: (Android only) topographic view - mutedStandard: more subtle, makes markers/lines pop more (iOS only)
+| `customMapStyle` | `Array` | | Adds custom styling to the map component. See [README](https://github.com/airbnb/react-native-maps#customizing-the-map-style) for more information.
| `showsUserLocation` | `Boolean` | `false` | If `true` the app will ask for the user's location. **NOTE**: You need to add `NSLocationWhenInUseUsageDescription` key in Info.plist to enable geolocation, otherwise it is going to *fail silently*!
+| `userLocationAnnotationTitle` | `String` | | The title of the annotation for current user location. This only works if `showsUserLocation` is true. There is a default value `My Location` set by MapView. **Note**: iOS only.
| `followsUserLocation` | `Boolean` | `false` | If `true` the map will focus on the user's location. This only works if `showsUserLocation` is true and the user has shared their location. **Note**: iOS only.
-| `showsMyLocationButton` | `Boolean` | `true` | `Android only` If `false` hide the button to move map to the current user's location.
+| `showsMyLocationButton` | `Boolean` | `true` | If `false` hide the button to move map to the current user's location.
| `showsPointsOfInterest` | `Boolean` | `true` | If `false` points of interest won't be displayed on the map.
| `showsCompass` | `Boolean` | `true` | If `false` compass won't be displayed on the map.
| `showsScale` | `Boolean` | `true` | A Boolean indicating whether the map shows scale information.
| `showsBuildings` | `Boolean` | `true` | A Boolean indicating whether the map displays extruded building information.
| `showsTraffic` | `Boolean` | `true` | A Boolean value indicating whether the map displays traffic information.
| `showsIndoors` | `Boolean` | `true` | A Boolean indicating whether indoor maps should be enabled.
+| `showsIndoorLevelPicker` | `Boolean` | `false` | A Boolean indicating whether indoor level picker should be enabled. **Note:** Google Maps only (either Android or iOS with `PROVIDER_GOOGLE`).
| `zoomEnabled` | `Boolean` | `true` | If `false` the user won't be able to pinch/zoom the map.
+| `minZoomLevel` | `Number` | `0` | Minimum zoom value for the map, must be between 0 and 20
+| `maxZoomLevel` | `Number` | `20` | Maximum zoom value for the map, must be between 0 and 20
| `rotateEnabled` | `Boolean` | `true` | If `false` the user won't be able to pinch/rotate the map.
| `scrollEnabled` | `Boolean` | `true` | If `false` the user won't be able to change the map region being displayed.
| `pitchEnabled` | `Boolean` | `true` | If `false` the user won't be able to adjust the camera’s pitch angle.
| `toolbarEnabled` | `Boolean` | `true` | `Android only` If `false` will hide 'Navigate' and 'Open in Maps' buttons on marker press
-| `cacheEnabled` | `Boolean` | `false` | If `true` map will be cached and displayed as a image instead of being interactable, for performance usage.
+| `cacheEnabled` | `Boolean` | `false` | If `true` map will be cached and displayed as an image instead of being interactable, for performance usage.
| `loadingEnabled` | `Boolean` | `false` | If `true` a loading indicator will show while the map is loading.
| `loadingIndicatorColor` | `Color` | `#606060` | Sets loading indicator color, default to `#606060`.
| `loadingBackgroundColor` | `Color` | `#FFFFFF` | Sets loading background color, default to `#FFFFFF`.
-
+| `moveOnMarkerPress` | `Boolean` | `true` | `Android only` If `false` the map won't move when a marker is pressed.
+| `legalLabelInsets` | `EdgeInsets` | | If set, changes the position of the "Legal" label link from the OS default. **Note:** iOS only.
## Events
+To access event data, you will need to use `e.nativeEvent`. For example, `onPress={e => console.log(e.nativeEvent)}` will log the entire event object to your console.
+
| Event Name | Returns | Notes
|---|---|---|
+| `onMapReady` | | Callback that is called once the map is fully loaded.
| `onRegionChange` | `Region` | Callback that is called continuously when the region changes, such as when a user is dragging the map.
| `onRegionChangeComplete` | `Region` | Callback that is called once when the region changes, such as when the user is done moving the map.
| `onPress` | `{ coordinate: LatLng, position: Point }` | Callback that is called when user taps on the map.
@@ -54,10 +63,13 @@
| Method Name | Arguments | Notes
|---|---|---|
| `animateToRegion` | `region: Region`, `duration: Number` |
-| `animateToCoordinate` | `region: Coordinate`, `duration: Number` |
+| `animateToCoordinate` | `coordinate: LatLng`, `duration: Number` |
+| `animateToBearing` | `bearing: Number`, `duration: Number` |
+| `animateToViewingAngle` | `angle: Number`, `duration: Number` |
+| `setMapBoundaries` | `northEast: LatLng`, `southWest: LatLng` | `GoogleMaps only`
| `fitToElements` | `animated: Boolean` |
-| `fitToSuppliedMarkers` | `markerIDs: String[]` | If you need to use this in `ComponentDidMount`, make sure you put it in a timeout or it will cause performance problems.
-| `fitToCoordinates` | `coordinates: Array, edgePadding: EdgePadding, animated: Boolean` |
+| `fitToSuppliedMarkers` | `markerIDs: String[]`, `animated: Boolean` | If you need to use this in `ComponentDidMount`, make sure you put it in a timeout or it will cause performance problems.
+| `fitToCoordinates` | `coordinates: Array, options: { edgePadding: EdgePadding, animated: Boolean }` | If called in `ComponentDidMount` in android, it will cause an exception. It is recommended to call it from the MapView `onLayout` event.
@@ -103,3 +115,12 @@ type EdgePadding {
left: Number
}
```
+
+```
+type EdgeInsets {
+ top: Number,
+ left: Number,
+ bottom: Number,
+ right: Number
+}
+```
diff --git a/docs/marker.md b/docs/marker.md
index 60da4c0f7..4214e4d6e 100644
--- a/docs/marker.md
+++ b/docs/marker.md
@@ -15,9 +15,13 @@
| `calloutAnchor` | `Point` | | Specifies the point in the marker image at which to anchor the callout when it is displayed. This is specified in the same coordinate system as the anchor. See the `anchor` prop for more details.
The default is the top middle of the image.
For ios, see the `calloutOffset` prop.
| `flat` | `Boolean` | | Sets whether this marker should be flat against the map true or a billboard facing the camera false.
| `identifier` | `String` | | An identifier used to reference this marker at a later date.
+| `rotation` | `Float` | | A float number indicating marker's rotation angle, in degrees.
+| `draggable` | `` | | This is a non-value based prop. Adding this allows the marker to be draggable (re-positioned).
## Events
+To access event data, you will need to use `e.nativeEvent`. For example, `onPress={e => console.log(e.nativeEvent)}` will log the entire event object to your console.
+
| Event Name | Returns | Notes
|---|---|---|
| `onPress` | `{ coordinate: LatLng, position: Point }` | Callback that is called when the user presses on the marker
diff --git a/docs/polygon.md b/docs/polygon.md
index 875327a81..085b31a18 100644
--- a/docs/polygon.md
+++ b/docs/polygon.md
@@ -6,8 +6,8 @@
|---|---|---|---|
| `coordinates` | `Array` | (Required) | An array of coordinates to describe the polygon
| `strokeWidth` | `Number` | `1` | The stroke width to use for the path.
-| `strokeColor` | `String` | `#000` | The stroke color to use for the path.
-| `fillColor` | `String` | | The fill color to use for the path.
+| `strokeColor` | `String` | `#000`, `rgba(r,g,b,0.5)` | The stroke color to use for the path.
+| `fillColor` | `String` | `#000`, `rgba(r,g,b,0.5)` | The fill color to use for the path.
| `lineCap` | `String` | `round` | The line cap style to apply to the open ends of the path.
| `lineJoin` | `Array` | | The line join style to apply to corners of the path.
| `miterLimit` | `Number` | | The limiting value that helps avoid spikes at junctions between connected line segments. The miter limit helps you avoid spikes in paths that use the `miter` `lineJoin` style. If the ratio of the miter length—that is, the diagonal length of the miter join—to the line thickness exceeds the miter limit, the joint is converted to a bevel join. The default miter limit is 10, which results in the conversion of miters whose angle at the joint is less than 11 degrees.
diff --git a/docs/polyline.md b/docs/polyline.md
index c542c4ce3..89ef9de25 100644
--- a/docs/polyline.md
+++ b/docs/polyline.md
@@ -4,7 +4,7 @@
| Prop | Type | Default | Note |
|---|---|---|---|
-| `coordinates` | `Array` | (Required) | An array of coordinates to describe the polygon
+| `coordinates` | `Array` | (Required) | An array of coordinates to describe the polyline
| `strokeWidth` | `Number` | `1` | The stroke width to use for the path.
| `strokeColor` | `String` | `#000` | The stroke color to use for the path.
| `lineCap` | `String` | `round` | The line cap style to apply to the open ends of the path.
diff --git a/example/App.js b/example/App.js
index abd02acd2..dadbea056 100644
--- a/example/App.js
+++ b/example/App.js
@@ -32,6 +32,10 @@ import CustomTiles from './examples/CustomTiles';
import ZIndexMarkers from './examples/ZIndexMarkers';
import StaticMap from './examples/StaticMap';
import MapStyle from './examples/MapStyle';
+import LegalLabel from './examples/LegalLabel';
+import SetNativePropsOverlays from './examples/SetNativePropsOverlays';
+import CustomOverlay from './examples/CustomOverlay';
+import BugMarkerWontUpdate from './examples/BugMarkerWontUpdate';
const IOS = Platform.OS === 'ios';
const ANDROID = Platform.OS === 'android';
@@ -142,6 +146,10 @@ class App extends React.Component {
[CustomTiles, 'Custom Tiles', true],
[ZIndexMarkers, 'Position Markers with Z-index', true],
[MapStyle, 'Customize the style of the map', true],
+ [LegalLabel, 'Reposition the legal label', true],
+ [SetNativePropsOverlays, 'Update native props', true],
+ [CustomOverlay, 'Custom Overlay Component', true],
+ [BugMarkerWontUpdate, 'BUG: Marker Won\'t Update (Android)', true],
]
// Filter out examples that are not yet supported for Google Maps on iOS.
.filter(example => ANDROID || (IOS && (example[2] || !this.state.useGoogleMaps)))
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
index c0fcb022f..7a8e8b7dd 100644
--- a/example/android/app/build.gradle
+++ b/example/android/app/build.gradle
@@ -59,7 +59,24 @@ import com.android.build.OutputFile
* ]
*/
-apply from: "react.gradle"
+project.ext.react = [
+ // the name of the generated asset file containing your JS bundle
+ bundleAssetName : "example.bundle",
+
+ // the entry file for bundle generation
+ entryFile : "index.js",
+
+ // the root of your project, i.e. where "package.json" lives
+ root : "../../../",
+
+ // supply additional arguments to the packager
+ extraPackagerArgs: []
+]
+
+
+apply from: "../../../node_modules/react-native/react.gradle"
+
+def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
@@ -67,8 +84,8 @@ apply from: "react.gradle"
def enableProguardInReleaseBuilds = false
android {
- compileSdkVersion 23
- buildToolsVersion "23.0.3"
+ compileSdkVersion 25
+ buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.airbnb.android.react.maps.example"
@@ -76,6 +93,17 @@ android {
targetSdkVersion 23
versionCode 1
versionName "1.0"
+ ndk {
+ abiFilters "armeabi-v7a", "x86"
+ }
+ }
+ splits {
+ abi {
+ reset()
+ enable enableSeparateBuildPerCPUArchitecture
+ universalApk false // If true, also generate a universal APK
+ include "armeabi-v7a", "x86"
+ }
}
buildTypes {
release {
@@ -99,5 +127,8 @@ android {
}
dependencies {
- compile project(':react-native-maps')
+ compile 'com.facebook.react:react-native:0.45.+'
+ compile 'com.android.support:appcompat-v7:25.3.0'
+ compile 'com.android.support:support-annotations:25.3.0'
+ compile project(':react-native-maps-lib')
}
diff --git a/example/android/app/react.gradle b/example/android/app/react.gradle
deleted file mode 100644
index 11a4f8b87..000000000
--- a/example/android/app/react.gradle
+++ /dev/null
@@ -1,97 +0,0 @@
-import org.apache.tools.ant.taskdefs.condition.Os
-
-def config = project.hasProperty("react") ? project.react : [];
-
-def bundleAssetName = config.bundleAssetName ?: "index.android.bundle"
-def entryFile = config.entryFile ?: "index.android.js"
-
-// because elvis operator
-def elvisFile(thing) {
- return thing ? file(thing) : null;
-}
-
-def reactRoot = elvisFile(config.root) ?: file("../../")
-def inputExcludes = config.inputExcludes ?: ["android/**", "ios/**"]
-
-void runBefore(String dependentTaskName, Task task) {
- Task dependentTask = tasks.findByPath(dependentTaskName);
- if (dependentTask != null) {
- dependentTask.dependsOn task
- }
-}
-
-gradle.projectsEvaluated {
- // Grab all build types and product flavors
- def buildTypes = android.buildTypes.collect { type -> type.name }
- def productFlavors = android.productFlavors.collect { flavor -> flavor.name }
-
- // When no product flavors defined, use empty
- if (!productFlavors) productFlavors.add('')
-
- productFlavors.each { productFlavorName ->
- buildTypes.each { buildTypeName ->
- // Create variant and target names
- def targetName = "${productFlavorName.capitalize()}${buildTypeName.capitalize()}"
- def targetPath = productFlavorName ?
- "${productFlavorName}/${buildTypeName}" :
- "${buildTypeName}"
-
- // React js bundle directories
- def jsBundleDirConfigName = "jsBundleDir${targetName}"
- def jsBundleDir = elvisFile(config."$jsBundleDirConfigName") ?:
- file("$buildDir/intermediates/assets/${targetPath}")
-
- def resourcesDirConfigName = "jsBundleDir${targetName}"
- def resourcesDir = elvisFile(config."${resourcesDirConfigName}") ?:
- file("$buildDir/intermediates/res/merged/${targetPath}")
- def jsBundleFile = file("$jsBundleDir/$bundleAssetName")
-
- // Bundle task name for variant
- def bundleJsAndAssetsTaskName = "bundle${targetName}JsAndAssets"
-
- def currentBundleTask = tasks.create(
- name: bundleJsAndAssetsTaskName,
- type: Exec) {
- group = "react"
- description = "bundle JS and assets for ${targetName}."
-
- // Create dirs if they are not there (e.g. the "clean" task just ran)
- doFirst {
- jsBundleDir.mkdirs()
- resourcesDir.mkdirs()
- }
-
- // Set up inputs and outputs so gradle can cache the result
- inputs.files fileTree(dir: reactRoot, excludes: inputExcludes)
- outputs.dir jsBundleDir
- outputs.dir resourcesDir
-
- // Set up the call to the react-native cli
- workingDir reactRoot
-
- // Set up dev mode
- def devEnabled = !targetName.toLowerCase().contains("release")
- if (Os.isFamily(Os.FAMILY_WINDOWS)) {
- commandLine "cmd", "/c", "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
- "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
- } else {
- commandLine "react-native", "bundle", "--platform", "android", "--dev", "${devEnabled}",
- "--entry-file", entryFile, "--bundle-output", jsBundleFile, "--assets-dest", resourcesDir
- }
-
- enabled config."bundleIn${targetName}" ||
- config."bundleIn${buildTypeName.capitalize()}" ?:
- targetName.toLowerCase().contains("release")
- }
-
- // Hook bundle${productFlavor}${buildType}JsAndAssets into the android build process
- currentBundleTask.dependsOn("merge${targetName}Resources")
- currentBundleTask.dependsOn("merge${targetName}Assets")
-
- runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask)
- runBefore("processX86${targetName}Resources", currentBundleTask)
- runBefore("processUniversal${targetName}Resources", currentBundleTask)
- runBefore("process${targetName}Resources", currentBundleTask)
- }
- }
-}
diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml
index 2742d5793..b111eef4a 100644
--- a/example/android/app/src/main/AndroidManifest.xml
+++ b/example/android/app/src/main/AndroidManifest.xml
@@ -1,6 +1,7 @@
+ getPackages() {
return Arrays.asList(
new MainReactPackage(),
@@ -28,4 +34,10 @@ public class ExampleApplication extends Application implements ReactApplication
public ReactNativeHost getReactNativeHost() {
return reactNativeHost;
}
-}
\ No newline at end of file
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ SoLoader.init(this, /* native exopackage */ false);
+ }
+}
diff --git a/example/android/app/src/main/java/com/airbnb/android/react/maps/example/MainActivity.java b/example/android/app/src/main/java/com/airbnb/android/react/maps/example/MainActivity.java
index eec2349a4..12149c20e 100644
--- a/example/android/app/src/main/java/com/airbnb/android/react/maps/example/MainActivity.java
+++ b/example/android/app/src/main/java/com/airbnb/android/react/maps/example/MainActivity.java
@@ -4,14 +4,12 @@
public class MainActivity extends ReactActivity {
-
- /**
- * Returns the name of the main component registered from JavaScript.
- * This is used to schedule rendering of the component.
- */
- @Override
- protected String getMainComponentName() {
- return "AirMapsExplorer";
- }
-
+ /**
+ * Returns the name of the main component registered from JavaScript.
+ * This is used to schedule rendering of the component.
+ */
+ @Override
+ protected String getMainComponentName() {
+ return "AirMapsExplorer";
+ }
}
diff --git a/example/android/build.gradle b/example/android/build.gradle
deleted file mode 100644
index b249b0409..000000000
--- a/example/android/build.gradle
+++ /dev/null
@@ -1,24 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
- repositories {
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:2.2.1'
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
-}
-
-allprojects {
- repositories {
- mavenLocal()
- jcenter()
- maven {
- // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
- url "$projectDir/../../node_modules/react-native/android"
- }
- }
-}
diff --git a/example/android/gradle.properties b/example/android/gradle.properties
deleted file mode 100644
index c04c048e8..000000000
--- a/example/android/gradle.properties
+++ /dev/null
@@ -1,19 +0,0 @@
-# Project-wide Gradle settings.
-
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-
-# For more details on how to configure your build environment visit
-# http://www.gradle.org/docs/current/userguide/build_environment.html
-
-# Specifies the JVM arguments used for the daemon process.
-# The setting is particularly useful for tweaking memory settings.
-# Default value: -Xmx10248m -XX:MaxPermSize=256m
-# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
-
-# When configured, Gradle will run in incubating parallel mode.
-# This option should only be used with decoupled projects. More details, visit
-# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
-# org.gradle.parallel=true
-
diff --git a/example/android/settings.gradle b/example/android/settings.gradle
deleted file mode 100644
index d9c3d2776..000000000
--- a/example/android/settings.gradle
+++ /dev/null
@@ -1,2 +0,0 @@
-include ':app', ':react-native-maps'
-project(':react-native-maps').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-maps/android')
diff --git a/example/examples/AnimatedViews.js b/example/examples/AnimatedViews.js
index eea711905..884f11a37 100644
--- a/example/examples/AnimatedViews.js
+++ b/example/examples/AnimatedViews.js
@@ -191,7 +191,7 @@ class AnimatedViews extends React.Component {
scale,
translateY,
markers,
- region: new Animated.Region({
+ region: new MapView.AnimatedRegion({
latitude: LATITUDE,
longitude: LONGITUDE,
latitudeDelta: LATITUDE_DELTA,
@@ -220,7 +220,7 @@ class AnimatedViews extends React.Component {
}).start();
}
- onStartShouldSetPanResponder(e) {
+ onStartShouldSetPanResponder = (e) => {
// we only want to move the view if they are starting the gesture on top
// of the view, so this calculates that and returns true if so. If we return
// false, the gesture should get passed to the map view appropriately.
@@ -232,7 +232,7 @@ class AnimatedViews extends React.Component {
return topOfTap < topOfMainWindow;
}
- onMoveShouldSetPanResponder(e) {
+ onMoveShouldSetPanResponder = (e) => {
const { panY } = this.state;
const { pageY } = e.nativeEvent;
const topOfMainWindow = ITEM_PREVIEW_HEIGHT + panY.__getValue();
@@ -241,7 +241,7 @@ class AnimatedViews extends React.Component {
return topOfTap < topOfMainWindow;
}
- onPanXChange({ value }) {
+ onPanXChange = ({ value }) => {
const { index } = this.state;
const newIndex = Math.floor(((-1 * value) + (SNAP_WIDTH / 2)) / SNAP_WIDTH);
if (index !== newIndex) {
@@ -249,7 +249,7 @@ class AnimatedViews extends React.Component {
}
}
- onPanYChange({ value }) {
+ onPanYChange = ({ value }) => {
const { canMoveHorizontal, region, scrollY, scrollX, markers, index } = this.state;
const shouldBeMovable = Math.abs(value) < 2;
if (shouldBeMovable !== canMoveHorizontal) {
diff --git a/example/examples/BugMarkerWontUpdate.js b/example/examples/BugMarkerWontUpdate.js
new file mode 100644
index 000000000..8bf62ffca
--- /dev/null
+++ b/example/examples/BugMarkerWontUpdate.js
@@ -0,0 +1,134 @@
+import React from 'react';
+import {
+ StyleSheet,
+ View,
+ Text,
+ Dimensions,
+ TouchableOpacity,
+} from 'react-native';
+import MapView from 'react-native-maps';
+import MyLocationMapMarker from './MyLocationMapMarker';
+
+const { width, height } = Dimensions.get('window');
+
+const ASPECT_RATIO = width / height;
+const LATITUDE = 37.78825;
+const LONGITUDE = -122.4324;
+const LATITUDE_DELTA = 0.0922;
+const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
+
+class BugMarkerWontUpdate extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ region: {
+ latitude: LATITUDE,
+ longitude: LONGITUDE,
+ latitudeDelta: LATITUDE_DELTA,
+ longitudeDelta: LONGITUDE_DELTA,
+ },
+ coordinate: {
+ latitude: LATITUDE,
+ longitude: LONGITUDE,
+ },
+ amount: 0,
+ enableHack: false,
+ };
+ }
+
+ increment() {
+ this.setState({ amount: this.state.amount + 10 });
+ }
+
+ decrement() {
+ this.setState({ amount: this.state.amount - 10 });
+ }
+
+ toggleHack() {
+ this.setState({ enableHack: !this.state.enableHack });
+ }
+
+ render() {
+ return (
+
+
+
+
+
+ this.toggleHack()}
+ style={[styles.bubble, styles.button, styles.hackButton]}
+ >
+
+ {this.state.enableHack ? 'Disable Hack' : 'Enable Hack'}
+
+
+
+
+ this.decrement()}
+ style={[styles.bubble, styles.button]}
+ >
+ -
+
+ this.increment()}
+ style={[styles.bubble, styles.button]}
+ >
+ +
+
+
+
+ );
+ }
+}
+
+BugMarkerWontUpdate.propTypes = {
+ provider: MapView.ProviderPropType,
+};
+
+const styles = StyleSheet.create({
+ container: {
+ ...StyleSheet.absoluteFillObject,
+ justifyContent: 'flex-end',
+ alignItems: 'center',
+ },
+ map: {
+ ...StyleSheet.absoluteFillObject,
+ },
+ bubble: {
+ backgroundColor: 'rgba(255,255,255,0.7)',
+ paddingHorizontal: 18,
+ paddingVertical: 12,
+ borderRadius: 20,
+ },
+ latlng: {
+ width: 200,
+ alignItems: 'stretch',
+ },
+ button: {
+ width: 80,
+ paddingHorizontal: 12,
+ alignItems: 'center',
+ marginHorizontal: 10,
+ },
+ hackButton: {
+ width: 200,
+ },
+ buttonContainer: {
+ flexDirection: 'row',
+ marginVertical: 20,
+ backgroundColor: 'transparent',
+ },
+});
+
+module.exports = BugMarkerWontUpdate;
diff --git a/example/examples/CustomOverlay.js b/example/examples/CustomOverlay.js
new file mode 100644
index 000000000..c57f83ff7
--- /dev/null
+++ b/example/examples/CustomOverlay.js
@@ -0,0 +1,85 @@
+import React from 'react';
+import {
+ StyleSheet,
+ View,
+ Dimensions,
+} from 'react-native';
+
+import MapView from 'react-native-maps';
+import XMarksTheSpot from './CustomOverlayXMarksTheSpot';
+
+const { width, height } = Dimensions.get('window');
+const ASPECT_RATIO = width / height;
+const LATITUDE = 37.78825;
+const LONGITUDE = -122.4324;
+const LATITUDE_DELTA = 0.0922;
+const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
+
+class CustomOverlay extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ region: {
+ latitude: LATITUDE,
+ longitude: LONGITUDE,
+ latitudeDelta: LATITUDE_DELTA,
+ longitudeDelta: LONGITUDE_DELTA,
+ },
+ coordinates: [
+ {
+ longitude: -122.442753,
+ latitude: 37.798790,
+ },
+ {
+ longitude: -122.424728,
+ latitude: 37.801232,
+ },
+ {
+ longitude: -122.422497,
+ latitude: 37.790651,
+ },
+ {
+ longitude: -122.440693,
+ latitude: 37.788209,
+ },
+ ],
+ center: {
+ longitude: -122.4326648935676,
+ latitude: 37.79418561114521,
+ },
+ };
+ }
+
+ render() {
+ const { coordinates, center, region } = this.state;
+ return (
+
+
+
+
+
+ );
+ }
+}
+
+CustomOverlay.propTypes = {
+ provider: MapView.ProviderPropType,
+};
+
+const styles = StyleSheet.create({
+ container: {
+ ...StyleSheet.absoluteFillObject,
+ justifyContent: 'flex-end',
+ alignItems: 'center',
+ },
+ map: {
+ ...StyleSheet.absoluteFillObject,
+ },
+});
+
+module.exports = CustomOverlay;
diff --git a/example/examples/CustomOverlayXMarksTheSpot.js b/example/examples/CustomOverlayXMarksTheSpot.js
new file mode 100644
index 000000000..ada19da9c
--- /dev/null
+++ b/example/examples/CustomOverlayXMarksTheSpot.js
@@ -0,0 +1,34 @@
+import React, { PropTypes } from 'react';
+import { View } from 'react-native';
+import MapView from 'react-native-maps';
+
+class XMarksTheSpot extends React.Component {
+ render() {
+ return (
+
+
+
+
+
+
+ );
+ }
+}
+
+XMarksTheSpot.propTypes = {
+ coordinates: PropTypes.array,
+ center: PropTypes.object,
+ zIndex: PropTypes.number,
+};
+
+export default XMarksTheSpot;
diff --git a/example/examples/DisplayLatLng.js b/example/examples/DisplayLatLng.js
index 573617d41..688427b35 100644
--- a/example/examples/DisplayLatLng.js
+++ b/example/examples/DisplayLatLng.js
@@ -43,15 +43,37 @@ class DisplayLatLng extends React.Component {
this.map.animateToRegion(this.randomRegion());
}
- randomRegion() {
- const { region } = this.state;
+ animateRandomCoordinate() {
+ this.map.animateToCoordinate(this.randomCoordinate());
+ }
+
+ animateToRandomBearing() {
+ this.map.animateToBearing(this.getRandomFloat(-360, 360));
+ }
+
+ animateToRandomViewingAngle() {
+ this.map.animateToViewingAngle(this.getRandomFloat(0, 90));
+ }
+
+ getRandomFloat(min, max) {
+ return (Math.random() * (max - min)) + min;
+ }
+
+ randomCoordinate() {
+ const region = this.state.region;
return {
- ...this.state.region,
latitude: region.latitude + ((Math.random() - 0.5) * (region.latitudeDelta / 2)),
longitude: region.longitude + ((Math.random() - 0.5) * (region.longitudeDelta / 2)),
};
}
+ randomRegion() {
+ return {
+ ...this.state.region,
+ ...this.randomCoordinate(),
+ };
+ }
+
render() {
return (
@@ -74,13 +96,31 @@ class DisplayLatLng extends React.Component {
onPress={() => this.jumpRandom()}
style={[styles.bubble, styles.button]}
>
- Jump
+ Jump this.animateRandom()}
style={[styles.bubble, styles.button]}
>
- Animate
+ Animate (Region)
+
+ this.animateRandomCoordinate()}
+ style={[styles.bubble, styles.button]}
+ >
+ Animate (Coordinate)
+
+ this.animateToRandomBearing()}
+ style={[styles.bubble, styles.button]}
+ >
+ Animate (Bearing)
+
+ this.animateToRandomViewingAngle()}
+ style={[styles.bubble, styles.button]}
+ >
+ Animate (View Angle)
@@ -112,16 +152,20 @@ const styles = StyleSheet.create({
alignItems: 'stretch',
},
button: {
- width: 80,
- paddingHorizontal: 12,
+ width: 100,
+ paddingHorizontal: 8,
alignItems: 'center',
- marginHorizontal: 10,
+ justifyContent: 'center',
+ marginHorizontal: 5,
},
buttonContainer: {
flexDirection: 'row',
marginVertical: 20,
backgroundColor: 'transparent',
},
+ buttonText: {
+ textAlign: 'center',
+ },
});
module.exports = DisplayLatLng;
diff --git a/example/examples/EventListener.js b/example/examples/EventListener.js
index 0f62fbc73..19a393063 100644
--- a/example/examples/EventListener.js
+++ b/example/examples/EventListener.js
@@ -1,5 +1,4 @@
import React, { PropTypes } from 'react';
-import SyntheticEvent from 'react/lib/SyntheticEvent';
import {
StyleSheet,
View,
@@ -7,6 +6,8 @@ import {
Dimensions,
ScrollView,
} from 'react-native';
+// eslint-disable-next-line max-len
+import SyntheticEvent from 'react-native/Libraries/Renderer/src/renderers/shared/shared/event/SyntheticEvent';
import MapView from 'react-native-maps';
import PriceMarker from './PriceMarker';
@@ -129,6 +130,7 @@ class EventListener extends React.Component {
{
+ this.setState({
+ legalLabelPositionY: value,
+ });
+ });
+ }
+
+ componentWillUnmount() {
+ this.state._legalLabelPositionY.removeAllListeners();
+ }
+
+ onPressAnimate = () => {
+ Animated.sequence([
+ Animated.spring(this.state._legalLabelPositionY, {
+ toValue: 100,
+ }),
+ Animated.spring(this.state._legalLabelPositionY, {
+ toValue: 10,
+ }),
+ ]).start();
+ }
+
+ render() {
+ const latlng = {
+ latitude: 37.78825,
+ longitude: -122.4324,
+ };
+
+ const ASPECT_RATIO = screen.width / screen.height;
+ const LATITUDE_DELTA = 0.0922;
+ const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
+
+ return (
+
+
+
+
+
+
+
+ Animate
+
+
+
+
+
+ Bio description lorem ipsum Ullamco exercitation
+ aliqua ullamco nostrud dolor et aliquip fugiat do
+ aute fugiat velit in aliqua sit.
+
+
+
+
+
+
+ Profile Photo
+
+
+
+
+ );
+ }
+}
+
+const padding = 10;
+const photoSize = 80;
+const mapHeight = screen.height - 130;
+const styles = StyleSheet.create({
+ bio: {
+ marginHorizontal: padding,
+ marginBottom: 0,
+ paddingVertical: padding / 2,
+ },
+ bioText: {
+ fontSize: 16,
+ lineHeight: 16 * 1.5,
+ },
+ username: {
+ paddingLeft: photoSize + padding + padding,
+ paddingTop: padding,
+ },
+ usernameText: {
+ fontSize: 36,
+ lineHeight: 36,
+ color: 'blue',
+ textDecorationLine: 'underline',
+ },
+ photo: {
+ padding: 2,
+ position: 'absolute',
+ top: mapHeight - (photoSize / 2),
+ left: padding,
+ borderRadius: 5,
+ borderWidth: StyleSheet.hairlineWidth,
+ backgroundColor: '#ccc',
+ width: photoSize,
+ height: photoSize,
+ },
+ photoInner: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ flex: 1,
+ },
+ photoText: {
+ fontSize: 9,
+ textAlign: 'center',
+ },
+ map: {
+ height: mapHeight,
+ },
+});
+
+module.exports = LegalLabel;
diff --git a/example/examples/MarkerTypes.js b/example/examples/MarkerTypes.js
index 7bf3a6465..76685d782 100644
--- a/example/examples/MarkerTypes.js
+++ b/example/examples/MarkerTypes.js
@@ -62,6 +62,17 @@ class MarkerTypes extends React.Component {
anchor={{ x: 0.84, y: 1 }}
image={this.state.marker2 ? flagBlueImg : flagPinkImg}
/>
+ this.setState({ marker2: !this.state.marker2 })}
+ coordinate={{
+ latitude: LATITUDE + SPACE,
+ longitude: LONGITUDE - SPACE,
+ }}
+ centerOffset={{ x: -42, y: -60 }}
+ anchor={{ x: 0.84, y: 1 }}
+ opacity={0.6}
+ image={this.state.marker2 ? flagBlueImg : flagPinkImg}
+ />
);
diff --git a/example/examples/MyLocationMapMarker.js b/example/examples/MyLocationMapMarker.js
new file mode 100644
index 000000000..fff3f2b37
--- /dev/null
+++ b/example/examples/MyLocationMapMarker.js
@@ -0,0 +1,179 @@
+import React, { PropTypes } from 'react';
+import {
+ StyleSheet,
+ Text,
+ View,
+ PermissionsAndroid,
+ Platform,
+} from 'react-native';
+import MapView from 'react-native-maps';
+import isEqual from 'lodash/isEqual';
+
+const GEOLOCATION_OPTIONS = { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 };
+const ANCHOR = { x: 0.5, y: 0.5 };
+
+const colorOfmyLocationMapMarker = 'blue';
+
+const propTypes = {
+ ...MapView.Marker.propTypes,
+ // override this prop to make it optional
+ coordinate: PropTypes.shape({
+ latitude: PropTypes.number.isRequired,
+ longitude: PropTypes.number.isRequired,
+ }),
+ children: PropTypes.node,
+ geolocationOptions: PropTypes.shape({
+ enableHighAccuracy: PropTypes.bool,
+ timeout: PropTypes.number,
+ maximumAge: PropTypes.number,
+ }),
+ heading: PropTypes.number,
+ enableHack: PropTypes.bool,
+};
+
+const defaultProps = {
+ enableHack: false,
+ geolocationOptions: GEOLOCATION_OPTIONS,
+};
+
+export default class MyLocationMapMarker extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ this.mounted = false;
+ this.state = {
+ myPosition: null,
+ };
+ }
+ componentDidMount() {
+ this.mounted = true;
+ // If you supply a coordinate prop, we won't try to track location automatically
+ if (this.props.coordinate) return;
+
+ if (Platform.OS === 'android') {
+ PermissionsAndroid.requestPermission(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION)
+ .then(granted => {
+ if (granted && this.mounted) this.watchLocation();
+ });
+ } else {
+ this.watchLocation();
+ }
+ }
+ watchLocation() {
+ // eslint-disable-next-line no-undef
+ this.watchID = navigator.geolocation.watchPosition((position) => {
+ const myLastPosition = this.state.myPosition;
+ const myPosition = position.coords;
+ if (!isEqual(myPosition, myLastPosition)) {
+ this.setState({ myPosition });
+ }
+ }, null, this.props.geolocationOptions);
+ }
+ componentWillUnmount() {
+ this.mounted = false;
+ // eslint-disable-next-line no-undef
+ if (this.watchID) navigator.geolocation.clearWatch(this.watchID);
+ }
+ render() {
+ let { heading, coordinate } = this.props;
+ if (!coordinate) {
+ const { myPosition } = this.state;
+ if (!myPosition) return null;
+ coordinate = myPosition;
+ heading = myPosition.heading;
+ }
+
+ const rotate = (typeof heading === 'number' && heading >= 0) ? `${heading}deg` : null;
+
+ return (
+
+
+
+ {rotate &&
+
+
+
+ }
+
+
+ {this.props.enableHack && rotate}
+
+
+
+ {this.props.children}
+
+ );
+ }
+}
+
+const SIZE = 35;
+const HALO_RADIUS = 6;
+const ARROW_SIZE = 7;
+const ARROW_DISTANCE = 6;
+const HALO_SIZE = SIZE + HALO_RADIUS;
+const HEADING_BOX_SIZE = HALO_SIZE + ARROW_SIZE + ARROW_DISTANCE;
+
+const styles = StyleSheet.create({
+ mapMarker: {
+ zIndex: 1000,
+ },
+ // The container is necessary to protect the markerHalo shadow from clipping
+ container: {
+ width: HEADING_BOX_SIZE,
+ height: HEADING_BOX_SIZE,
+ },
+ heading: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ width: HEADING_BOX_SIZE,
+ height: HEADING_BOX_SIZE,
+ alignItems: 'center',
+ },
+ headingPointer: {
+ width: 0,
+ height: 0,
+ backgroundColor: 'transparent',
+ borderStyle: 'solid',
+ borderTopWidth: 0,
+ borderRightWidth: ARROW_SIZE * 0.75,
+ borderBottomWidth: ARROW_SIZE,
+ borderLeftWidth: ARROW_SIZE * 0.75,
+ borderTopColor: 'transparent',
+ borderRightColor: 'transparent',
+ borderBottomColor: colorOfmyLocationMapMarker,
+ borderLeftColor: 'transparent',
+ },
+ markerHalo: {
+ position: 'absolute',
+ backgroundColor: 'white',
+ top: 0,
+ left: 0,
+ width: HALO_SIZE,
+ height: HALO_SIZE,
+ borderRadius: Math.ceil(HALO_SIZE / 2),
+ margin: (HEADING_BOX_SIZE - HALO_SIZE) / 2,
+ shadowColor: 'black',
+ shadowOpacity: 0.25,
+ shadowRadius: 2,
+ shadowOffset: {
+ height: 0,
+ width: 0,
+ },
+ },
+ marker: {
+ justifyContent: 'center',
+ backgroundColor: colorOfmyLocationMapMarker,
+ width: SIZE,
+ height: SIZE,
+ borderRadius: Math.ceil(SIZE / 2),
+ margin: (HEADING_BOX_SIZE - SIZE) / 2,
+ },
+});
+
+MyLocationMapMarker.propTypes = propTypes;
+MyLocationMapMarker.defaultProps = defaultProps;
diff --git a/example/examples/PolygonCreator.js b/example/examples/PolygonCreator.js
index 99b02809e..c0d1e44f5 100644
--- a/example/examples/PolygonCreator.js
+++ b/example/examples/PolygonCreator.js
@@ -31,6 +31,7 @@ class PolygonCreator extends React.Component {
},
polygons: [],
editing: null,
+ creatingHole: false,
};
}
@@ -39,19 +40,49 @@ class PolygonCreator extends React.Component {
this.setState({
polygons: [...polygons, editing],
editing: null,
+ creatingHole: false,
});
}
+ createHole() {
+ const { editing, creatingHole } = this.state;
+ if (!creatingHole) {
+ this.setState({
+ creatingHole: true,
+ editing: {
+ ...editing,
+ holes: [
+ ...editing.holes,
+ [],
+ ],
+ },
+ });
+ } else {
+ const holes = [...editing.holes];
+ if (holes[holes.length - 1].length === 0) {
+ holes.pop();
+ this.setState({
+ editing: {
+ ...editing,
+ holes,
+ },
+ });
+ }
+ this.setState({ creatingHole: false });
+ }
+ }
+
onPress(e) {
- const { editing } = this.state;
+ const { editing, creatingHole } = this.state;
if (!editing) {
this.setState({
editing: {
id: id++,
coordinates: [e.nativeEvent.coordinate],
+ holes: [],
},
});
- } else {
+ } else if (!creatingHole) {
this.setState({
editing: {
...editing,
@@ -61,6 +92,22 @@ class PolygonCreator extends React.Component {
],
},
});
+ } else {
+ const holes = [...editing.holes];
+ holes[holes.length - 1] = [
+ ...holes[holes.length - 1],
+ e.nativeEvent.coordinate,
+ ];
+ this.setState({
+ editing: {
+ ...editing,
+ id: id++, // keep incrementing id to trigger display refresh
+ coordinates: [
+ ...editing.coordinates,
+ ],
+ holes,
+ },
+ });
}
}
@@ -88,6 +135,7 @@ class PolygonCreator extends React.Component {
+ {this.state.editing && (
+ this.createHole()}
+ style={[styles.bubble, styles.button]}
+ >
+ {this.state.creatingHole ? 'Finish Hole' : 'Create Hole'}
+
+ )}
{this.state.editing && (
this.finish()}
diff --git a/example/examples/SetNativePropsOverlays.js b/example/examples/SetNativePropsOverlays.js
new file mode 100644
index 000000000..b0dac9a80
--- /dev/null
+++ b/example/examples/SetNativePropsOverlays.js
@@ -0,0 +1,162 @@
+import React from 'react';
+import {
+ StyleSheet,
+ View,
+ Text,
+ TouchableOpacity,
+ Dimensions,
+} from 'react-native';
+
+import MapView from 'react-native-maps';
+
+const { width, height } = Dimensions.get('window');
+
+const ASPECT_RATIO = width / height;
+const LATITUDE = 37.78825;
+const LONGITUDE = -122.4324;
+const LATITUDE_DELTA = 0.0922;
+const LONGITUDE_DELTA = LATITUDE_DELTA * ASPECT_RATIO;
+const SPACE = 0.01;
+
+class SetNativePropsOverlays extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ region: {
+ latitude: LATITUDE,
+ longitude: LONGITUDE,
+ latitudeDelta: LATITUDE_DELTA,
+ longitudeDelta: LONGITUDE_DELTA,
+ },
+ circle: {
+ center: {
+ latitude: LATITUDE + SPACE,
+ longitude: LONGITUDE + SPACE,
+ },
+ radius: 700,
+ },
+ polygon: [
+ {
+ latitude: LATITUDE + SPACE,
+ longitude: LONGITUDE + SPACE,
+ },
+ {
+ latitude: LATITUDE - SPACE,
+ longitude: LONGITUDE - SPACE,
+ },
+ {
+ latitude: LATITUDE - SPACE,
+ longitude: LONGITUDE + SPACE,
+ },
+ ],
+ polyline: [
+ {
+ latitude: LATITUDE + SPACE,
+ longitude: LONGITUDE - SPACE,
+ },
+ {
+ latitude: LATITUDE - (2 * SPACE),
+ longitude: LONGITUDE + (2 * SPACE),
+ },
+ {
+ latitude: LATITUDE - SPACE,
+ longitude: LONGITUDE - SPACE,
+ },
+ {
+ latitude: LATITUDE - (2 * SPACE),
+ longitude: LONGITUDE - SPACE,
+ },
+ ],
+ };
+ }
+
+ handleColorChange(color) {
+ const props = { strokeColor: color };
+ this.circle.setNativeProps(props);
+ this.polygon.setNativeProps(props);
+ this.polyline.setNativeProps(props);
+ }
+
+ render() {
+ const { region, circle, polygon, polyline } = this.state;
+ return (
+
+
+ { this.circle = ref; }}
+ center={circle.center}
+ radius={circle.radius}
+ fillColor="rgba(255, 255, 255, 0.6)"
+ strokeColor="green"
+ zIndex={3}
+ strokeWidth={3}
+ />
+ { this.polygon = ref; }}
+ coordinates={polygon}
+ fillColor="rgba(255, 255, 255, 0.6)"
+ strokeColor="green"
+ strokeWidth={2}
+ />
+ { this.polyline = ref; }}
+ coordinates={polyline}
+ strokeColor="green"
+ strokeWidth={3}
+ />
+
+
+ { this.handleColorChange('green'); }}>
+
+ Green
+
+
+ { this.handleColorChange('black'); }}>
+
+ Black
+
+
+ { this.handleColorChange('red'); }}>
+
+ Red
+
+
+
+
+ );
+ }
+}
+
+SetNativePropsOverlays.propTypes = {
+ provider: MapView.ProviderPropType,
+};
+
+const styles = StyleSheet.create({
+ container: {
+ ...StyleSheet.absoluteFillObject,
+ justifyContent: 'flex-end',
+ alignItems: 'center',
+ },
+ map: {
+ ...StyleSheet.absoluteFillObject,
+ },
+ bubble: {
+ flex: 1,
+ backgroundColor: 'rgba(255,255,255,0.7)',
+ paddingHorizontal: 18,
+ paddingVertical: 12,
+ borderRadius: 20,
+ },
+ buttonContainer: {
+ flexDirection: 'row',
+ marginVertical: 20,
+ backgroundColor: 'transparent',
+ },
+});
+
+module.exports = SetNativePropsOverlays;
diff --git a/example/index.android.js b/example/index.android.js
deleted file mode 100644
index 3d259cfd3..000000000
--- a/example/index.android.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import { AppRegistry } from 'react-native';
-import App from './App';
-
-class AirMapsExplorer extends React.Component {
- render() {
- return ;
- }
-}
-
-AppRegistry.registerComponent('AirMapsExplorer', () => AirMapsExplorer);
diff --git a/example/index.ios.js b/example/index.ios.js
deleted file mode 100644
index 3d259cfd3..000000000
--- a/example/index.ios.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import { AppRegistry } from 'react-native';
-import App from './App';
-
-class AirMapsExplorer extends React.Component {
- render() {
- return ;
- }
-}
-
-AppRegistry.registerComponent('AirMapsExplorer', () => AirMapsExplorer);
diff --git a/example/index.js b/example/index.js
new file mode 100644
index 000000000..1fe6aeea0
--- /dev/null
+++ b/example/index.js
@@ -0,0 +1,4 @@
+import { AppRegistry } from 'react-native';
+import App from './App';
+
+AppRegistry.registerComponent('AirMapsExplorer', () => App);
diff --git a/example/ios/AirMapsExplorer.xcodeproj/project.pbxproj b/example/ios/AirMapsExplorer.xcodeproj/project.pbxproj
index decbbec68..21d588c64 100644
--- a/example/ios/AirMapsExplorer.xcodeproj/project.pbxproj
+++ b/example/ios/AirMapsExplorer.xcodeproj/project.pbxproj
@@ -11,46 +11,14 @@
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
- 2166AB291D82EC56007538D7 /* AIRMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AAFC1D82EC56007538D7 /* AIRMap.m */; };
- 2166AB2A1D82EC56007538D7 /* AIRMapCallout.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AAFE1D82EC56007538D7 /* AIRMapCallout.m */; };
- 2166AB2B1D82EC56007538D7 /* AIRMapCalloutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB001D82EC56007538D7 /* AIRMapCalloutManager.m */; };
- 2166AB2C1D82EC56007538D7 /* AIRMapCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB021D82EC56007538D7 /* AIRMapCircle.m */; };
- 2166AB2D1D82EC56007538D7 /* AIRMapCircleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB041D82EC56007538D7 /* AIRMapCircleManager.m */; };
- 2166AB2E1D82EC56007538D7 /* AIRMapCoordinate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB061D82EC56007538D7 /* AIRMapCoordinate.m */; };
- 2166AB2F1D82EC56007538D7 /* AIRMapManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB081D82EC56007538D7 /* AIRMapManager.m */; };
- 2166AB301D82EC56007538D7 /* AIRMapMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB0A1D82EC56007538D7 /* AIRMapMarker.m */; };
- 2166AB311D82EC56007538D7 /* AIRMapMarkerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB0C1D82EC56007538D7 /* AIRMapMarkerManager.m */; };
- 2166AB321D82EC56007538D7 /* AIRMapPolygon.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB0E1D82EC56007538D7 /* AIRMapPolygon.m */; };
- 2166AB331D82EC56007538D7 /* AIRMapPolygonManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB101D82EC56007538D7 /* AIRMapPolygonManager.m */; };
- 2166AB341D82EC56007538D7 /* AIRMapPolyline.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB121D82EC56007538D7 /* AIRMapPolyline.m */; };
- 2166AB351D82EC56007538D7 /* AIRMapPolylineManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB141D82EC56007538D7 /* AIRMapPolylineManager.m */; };
- 2166AB361D82EC56007538D7 /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB171D82EC56007538D7 /* SMCalloutView.m */; };
- 2166AB3E1D82EC56007538D7 /* RCTConvert+MoreMapKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 2166AB281D82EC56007538D7 /* RCTConvert+MoreMapKit.m */; };
- 21D346651D933B8C002BAD8A /* AIRMapUrlTile.m in Sources */ = {isa = PBXBuildFile; fileRef = 21D346621D933B8C002BAD8A /* AIRMapUrlTile.m */; };
- 21D346661D933B8C002BAD8A /* AIRMapUrlTileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 21D346641D933B8C002BAD8A /* AIRMapUrlTileManager.m */; };
21E6570A1D77591400B75EE5 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21E657091D77591400B75EE5 /* SystemConfiguration.framework */; };
21E6570C1D77591A00B75EE5 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21E6570B1D77591A00B75EE5 /* MobileCoreServices.framework */; };
21E6570E1D77591F00B75EE5 /* MapKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21E6570D1D77591F00B75EE5 /* MapKit.framework */; };
21E657101D77594C00B75EE5 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21E6570F1D77594C00B75EE5 /* AudioToolbox.framework */; };
- 3E4E0B5921E01BC4043FD8CD /* Pods_AirMapsExplorer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3591658C00398534590C8751 /* Pods_AirMapsExplorer.framework */; };
- 8620CC871DBD814A00B79BFE /* AIRGMSMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC6E1DBD814A00B79BFE /* AIRGMSMarker.m */; };
- 8620CC881DBD814A00B79BFE /* AIRGoogleMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC701DBD814A00B79BFE /* AIRGoogleMap.m */; };
- 8620CC891DBD814A00B79BFE /* AIRGoogleMapCallout.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC721DBD814A00B79BFE /* AIRGoogleMapCallout.m */; };
- 8620CC8A1DBD814A00B79BFE /* AIRGoogleMapCalloutManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC741DBD814A00B79BFE /* AIRGoogleMapCalloutManager.m */; };
- 8620CC8B1DBD814A00B79BFE /* AIRGoogleMapManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC761DBD814A00B79BFE /* AIRGoogleMapManager.m */; };
- 8620CC8C1DBD814A00B79BFE /* AIRGoogleMapMarker.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC781DBD814A00B79BFE /* AIRGoogleMapMarker.m */; };
- 8620CC8D1DBD814A00B79BFE /* AIRGoogleMapMarkerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC7A1DBD814A00B79BFE /* AIRGoogleMapMarkerManager.m */; };
- 8620CC8E1DBD814A00B79BFE /* AIRGoogleMapPolygon.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC7C1DBD814A00B79BFE /* AIRGoogleMapPolygon.m */; };
- 8620CC8F1DBD814A00B79BFE /* AIRGoogleMapPolygonManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC7E1DBD814A00B79BFE /* AIRGoogleMapPolygonManager.m */; };
- 8620CC901DBD814A00B79BFE /* AIRGoogleMapPolyline.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC801DBD814A00B79BFE /* AIRGoogleMapPolyline.m */; };
- 8620CC911DBD814A00B79BFE /* AIRGoogleMapPolylineManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC821DBD814A00B79BFE /* AIRGoogleMapPolylineManager.m */; };
- 8620CC921DBD814A00B79BFE /* DummyView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC841DBD814A00B79BFE /* DummyView.m */; };
- 8620CC931DBD814A00B79BFE /* RCTConvert+GMSMapViewType.m in Sources */ = {isa = PBXBuildFile; fileRef = 8620CC861DBD814A00B79BFE /* RCTConvert+GMSMapViewType.m */; };
- 8697D6221DBEDE6100DB7D0F /* AIRGoogleMapCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 8697D6211DBEDE6100DB7D0F /* AIRGoogleMapCircle.m */; };
- 8697D6251DBEE22B00DB7D0F /* AIRGoogleMapCircleManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8697D6241DBEE22B00DB7D0F /* AIRGoogleMapCircleManager.m */; };
- 86DE6F881DCE7D21002A5053 /* AIRGoogleMapUrlTile.m in Sources */ = {isa = PBXBuildFile; fileRef = 86DE6F871DCE7D21002A5053 /* AIRGoogleMapUrlTile.m */; };
- 86DE6F8B1DCE8543002A5053 /* AIRGoogleMapURLTileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 86DE6F8A1DCE8543002A5053 /* AIRGoogleMapURLTileManager.m */; };
- C9315A21AD5A149EB5B40F29 /* Pods_AirMapsExplorer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24EB66BA0860A4DCD4CA3D77 /* Pods_AirMapsExplorer.framework */; };
+ 8490F2161E8879FB000099F8 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8490F2151E8879FB000099F8 /* CoreFoundation.framework */; };
+ 8490F21A1E887A8F000099F8 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8490F2191E887A8F000099F8 /* CFNetwork.framework */; };
+ 8490F21C1E887AAC000099F8 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8490F21B1E887AAC000099F8 /* Security.framework */; };
+ A622B8115793E41C70169A8B /* libPods-AirMapsExplorer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E5044A406006E7C2A53E05C /* libPods-AirMapsExplorer.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -66,6 +34,7 @@
/* Begin PBXFileReference section */
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = main.jsbundle; sourceTree = ""; };
00E356EE1AD99517003FC87E /* AirMapsExplorerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AirMapsExplorerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
+ 0E5044A406006E7C2A53E05C /* libPods-AirMapsExplorer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AirMapsExplorer.a"; sourceTree = BUILT_PRODUCTS_DIR; };
13B07F961A680F5B00A75B9A /* AirMapsExplorer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AirMapsExplorer.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = AirMapsExplorer/AppDelegate.h; sourceTree = ""; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = AirMapsExplorer/AppDelegate.m; sourceTree = ""; };
@@ -78,81 +47,16 @@
2166AAF41D823402007538D7 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
2166AAF61D823407007538D7 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
2166AAF81D82E9D0007538D7 /* React.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = React.framework; path = "Pods/../build/Debug-iphoneos/React.framework"; sourceTree = ""; };
- 2166AAFB1D82EC56007538D7 /* AIRMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMap.h; sourceTree = ""; };
- 2166AAFC1D82EC56007538D7 /* AIRMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMap.m; sourceTree = ""; };
- 2166AAFD1D82EC56007538D7 /* AIRMapCallout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapCallout.h; sourceTree = ""; };
- 2166AAFE1D82EC56007538D7 /* AIRMapCallout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapCallout.m; sourceTree = ""; };
- 2166AAFF1D82EC56007538D7 /* AIRMapCalloutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapCalloutManager.h; sourceTree = ""; };
- 2166AB001D82EC56007538D7 /* AIRMapCalloutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapCalloutManager.m; sourceTree = ""; };
- 2166AB011D82EC56007538D7 /* AIRMapCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapCircle.h; sourceTree = ""; };
- 2166AB021D82EC56007538D7 /* AIRMapCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapCircle.m; sourceTree = ""; };
- 2166AB031D82EC56007538D7 /* AIRMapCircleManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapCircleManager.h; sourceTree = ""; };
- 2166AB041D82EC56007538D7 /* AIRMapCircleManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapCircleManager.m; sourceTree = ""; };
- 2166AB051D82EC56007538D7 /* AIRMapCoordinate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapCoordinate.h; sourceTree = ""; };
- 2166AB061D82EC56007538D7 /* AIRMapCoordinate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapCoordinate.m; sourceTree = ""; };
- 2166AB071D82EC56007538D7 /* AIRMapManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapManager.h; sourceTree = ""; };
- 2166AB081D82EC56007538D7 /* AIRMapManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapManager.m; sourceTree = ""; };
- 2166AB091D82EC56007538D7 /* AIRMapMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapMarker.h; sourceTree = ""; };
- 2166AB0A1D82EC56007538D7 /* AIRMapMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapMarker.m; sourceTree = ""; };
- 2166AB0B1D82EC56007538D7 /* AIRMapMarkerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapMarkerManager.h; sourceTree = ""; };
- 2166AB0C1D82EC56007538D7 /* AIRMapMarkerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapMarkerManager.m; sourceTree = ""; };
- 2166AB0D1D82EC56007538D7 /* AIRMapPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapPolygon.h; sourceTree = ""; };
- 2166AB0E1D82EC56007538D7 /* AIRMapPolygon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapPolygon.m; sourceTree = ""; };
- 2166AB0F1D82EC56007538D7 /* AIRMapPolygonManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapPolygonManager.h; sourceTree = ""; };
- 2166AB101D82EC56007538D7 /* AIRMapPolygonManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapPolygonManager.m; sourceTree = ""; };
- 2166AB111D82EC56007538D7 /* AIRMapPolyline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapPolyline.h; sourceTree = ""; };
- 2166AB121D82EC56007538D7 /* AIRMapPolyline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapPolyline.m; sourceTree = ""; };
- 2166AB131D82EC56007538D7 /* AIRMapPolylineManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapPolylineManager.h; sourceTree = ""; };
- 2166AB141D82EC56007538D7 /* AIRMapPolylineManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapPolylineManager.m; sourceTree = ""; };
- 2166AB161D82EC56007538D7 /* SMCalloutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SMCalloutView.h; sourceTree = ""; };
- 2166AB171D82EC56007538D7 /* SMCalloutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SMCalloutView.m; sourceTree = ""; };
- 2166AB271D82EC56007538D7 /* RCTConvert+MoreMapKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+MoreMapKit.h"; sourceTree = ""; };
- 2166AB281D82EC56007538D7 /* RCTConvert+MoreMapKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+MoreMapKit.m"; sourceTree = ""; };
- 21D346611D933B8C002BAD8A /* AIRMapUrlTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapUrlTile.h; sourceTree = ""; };
- 21D346621D933B8C002BAD8A /* AIRMapUrlTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapUrlTile.m; sourceTree = ""; };
- 21D346631D933B8C002BAD8A /* AIRMapUrlTileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapUrlTileManager.h; sourceTree = ""; };
- 21D346641D933B8C002BAD8A /* AIRMapUrlTileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapUrlTileManager.m; sourceTree = ""; };
21E657091D77591400B75EE5 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
21E6570B1D77591A00B75EE5 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
21E6570D1D77591F00B75EE5 /* MapKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MapKit.framework; path = System/Library/Frameworks/MapKit.framework; sourceTree = SDKROOT; };
21E6570F1D77594C00B75EE5 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
- 3591658C00398534590C8751 /* Pods_AirMapsExplorer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AirMapsExplorer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 8620CC6D1DBD814A00B79BFE /* AIRGMSMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGMSMarker.h; sourceTree = ""; };
- 8620CC6E1DBD814A00B79BFE /* AIRGMSMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGMSMarker.m; sourceTree = ""; };
- 8620CC6F1DBD814A00B79BFE /* AIRGoogleMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMap.h; sourceTree = ""; };
- 8620CC701DBD814A00B79BFE /* AIRGoogleMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMap.m; sourceTree = ""; };
- 8620CC711DBD814A00B79BFE /* AIRGoogleMapCallout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapCallout.h; sourceTree = ""; };
- 8620CC721DBD814A00B79BFE /* AIRGoogleMapCallout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapCallout.m; sourceTree = ""; };
- 8620CC731DBD814A00B79BFE /* AIRGoogleMapCalloutManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapCalloutManager.h; sourceTree = ""; };
- 8620CC741DBD814A00B79BFE /* AIRGoogleMapCalloutManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapCalloutManager.m; sourceTree = ""; };
- 8620CC751DBD814A00B79BFE /* AIRGoogleMapManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapManager.h; sourceTree = ""; };
- 8620CC761DBD814A00B79BFE /* AIRGoogleMapManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapManager.m; sourceTree = ""; };
- 8620CC771DBD814A00B79BFE /* AIRGoogleMapMarker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapMarker.h; sourceTree = ""; };
- 8620CC781DBD814A00B79BFE /* AIRGoogleMapMarker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapMarker.m; sourceTree = ""; };
- 8620CC791DBD814A00B79BFE /* AIRGoogleMapMarkerManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapMarkerManager.h; sourceTree = ""; };
- 8620CC7A1DBD814A00B79BFE /* AIRGoogleMapMarkerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapMarkerManager.m; sourceTree = ""; };
- 8620CC7B1DBD814A00B79BFE /* AIRGoogleMapPolygon.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapPolygon.h; sourceTree = ""; };
- 8620CC7C1DBD814A00B79BFE /* AIRGoogleMapPolygon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapPolygon.m; sourceTree = ""; };
- 8620CC7D1DBD814A00B79BFE /* AIRGoogleMapPolygonManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapPolygonManager.h; sourceTree = ""; };
- 8620CC7E1DBD814A00B79BFE /* AIRGoogleMapPolygonManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapPolygonManager.m; sourceTree = ""; };
- 8620CC7F1DBD814A00B79BFE /* AIRGoogleMapPolyline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapPolyline.h; sourceTree = ""; };
- 8620CC801DBD814A00B79BFE /* AIRGoogleMapPolyline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapPolyline.m; sourceTree = ""; };
- 8620CC811DBD814A00B79BFE /* AIRGoogleMapPolylineManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapPolylineManager.h; sourceTree = ""; };
- 8620CC821DBD814A00B79BFE /* AIRGoogleMapPolylineManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapPolylineManager.m; sourceTree = ""; };
- 8620CC831DBD814A00B79BFE /* DummyView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DummyView.h; sourceTree = ""; };
- 8620CC841DBD814A00B79BFE /* DummyView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DummyView.m; sourceTree = ""; };
- 8620CC851DBD814A00B79BFE /* RCTConvert+GMSMapViewType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+GMSMapViewType.h"; sourceTree = ""; };
- 8620CC861DBD814A00B79BFE /* RCTConvert+GMSMapViewType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+GMSMapViewType.m"; sourceTree = ""; };
- 8697D6201DBEDE6100DB7D0F /* AIRGoogleMapCircle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapCircle.h; sourceTree = ""; };
- 8697D6211DBEDE6100DB7D0F /* AIRGoogleMapCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapCircle.m; sourceTree = ""; };
- 8697D6231DBEE22B00DB7D0F /* AIRGoogleMapCircleManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapCircleManager.h; sourceTree = ""; };
- 8697D6241DBEE22B00DB7D0F /* AIRGoogleMapCircleManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapCircleManager.m; sourceTree = ""; };
+ 8490F2151E8879FB000099F8 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
+ 8490F2171E887A36000099F8 /* libicucore.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libicucore.tbd; path = usr/lib/libicucore.tbd; sourceTree = SDKROOT; };
+ 8490F2191E887A8F000099F8 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
+ 8490F21B1E887AAC000099F8 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
BE5DE1E9AE25978F88CD940A /* Pods-AirMapsExplorer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AirMapsExplorer.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AirMapsExplorer/Pods-AirMapsExplorer.debug.xcconfig"; sourceTree = ""; };
E138AD0CDB08FE57B09B18F8 /* Pods-AirMapsExplorer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AirMapsExplorer.release.xcconfig"; path = "Pods/Target Support Files/Pods-AirMapsExplorer/Pods-AirMapsExplorer.release.xcconfig"; sourceTree = ""; };
- 86DE6F861DCE7D21002A5053 /* AIRGoogleMapUrlTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapUrlTile.h; sourceTree = ""; };
- 86DE6F871DCE7D21002A5053 /* AIRGoogleMapUrlTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapUrlTile.m; sourceTree = ""; };
- 86DE6F891DCE8543002A5053 /* AIRGoogleMapUrlTileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRGoogleMapUrlTileManager.h; sourceTree = ""; };
- 86DE6F8A1DCE8543002A5053 /* AIRGoogleMapURLTileManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRGoogleMapURLTileManager.m; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -167,11 +71,14 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ 8490F21C1E887AAC000099F8 /* Security.framework in Frameworks */,
+ 8490F21A1E887A8F000099F8 /* CFNetwork.framework in Frameworks */,
+ 8490F2161E8879FB000099F8 /* CoreFoundation.framework in Frameworks */,
21E657101D77594C00B75EE5 /* AudioToolbox.framework in Frameworks */,
21E6570E1D77591F00B75EE5 /* MapKit.framework in Frameworks */,
21E6570C1D77591A00B75EE5 /* MobileCoreServices.framework in Frameworks */,
21E6570A1D77591400B75EE5 /* SystemConfiguration.framework in Frameworks */,
- 3E4E0B5921E01BC4043FD8CD /* Pods_AirMapsExplorer.framework in Frameworks */,
+ A622B8115793E41C70169A8B /* libPods-AirMapsExplorer.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -181,6 +88,10 @@
051AB288C799B62BE091B88A /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 8490F21B1E887AAC000099F8 /* Security.framework */,
+ 8490F2191E887A8F000099F8 /* CFNetwork.framework */,
+ 8490F2171E887A36000099F8 /* libicucore.tbd */,
+ 8490F2151E8879FB000099F8 /* CoreFoundation.framework */,
2166AAF81D82E9D0007538D7 /* React.framework */,
2166AAF61D823407007538D7 /* CoreGraphics.framework */,
2166AAF41D823402007538D7 /* CoreText.framework */,
@@ -190,7 +101,7 @@
21E6570D1D77591F00B75EE5 /* MapKit.framework */,
21E6570B1D77591A00B75EE5 /* MobileCoreServices.framework */,
21E657091D77591400B75EE5 /* SystemConfiguration.framework */,
- 3591658C00398534590C8751 /* Pods_AirMapsExplorer.framework */,
+ 0E5044A406006E7C2A53E05C /* libPods-AirMapsExplorer.a */,
);
name = Frameworks;
sourceTree = "";
@@ -209,56 +120,6 @@
name = AirMapsExplorer;
sourceTree = "";
};
- 2166AAFA1D82EC56007538D7 /* AirMaps */ = {
- isa = PBXGroup;
- children = (
- 2166AAFB1D82EC56007538D7 /* AIRMap.h */,
- 2166AAFC1D82EC56007538D7 /* AIRMap.m */,
- 2166AAFD1D82EC56007538D7 /* AIRMapCallout.h */,
- 2166AAFE1D82EC56007538D7 /* AIRMapCallout.m */,
- 2166AAFF1D82EC56007538D7 /* AIRMapCalloutManager.h */,
- 2166AB001D82EC56007538D7 /* AIRMapCalloutManager.m */,
- 2166AB011D82EC56007538D7 /* AIRMapCircle.h */,
- 2166AB021D82EC56007538D7 /* AIRMapCircle.m */,
- 2166AB031D82EC56007538D7 /* AIRMapCircleManager.h */,
- 2166AB041D82EC56007538D7 /* AIRMapCircleManager.m */,
- 2166AB051D82EC56007538D7 /* AIRMapCoordinate.h */,
- 2166AB061D82EC56007538D7 /* AIRMapCoordinate.m */,
- 2166AB071D82EC56007538D7 /* AIRMapManager.h */,
- 2166AB081D82EC56007538D7 /* AIRMapManager.m */,
- 2166AB091D82EC56007538D7 /* AIRMapMarker.h */,
- 2166AB0A1D82EC56007538D7 /* AIRMapMarker.m */,
- 2166AB0B1D82EC56007538D7 /* AIRMapMarkerManager.h */,
- 2166AB0C1D82EC56007538D7 /* AIRMapMarkerManager.m */,
- 2166AB0D1D82EC56007538D7 /* AIRMapPolygon.h */,
- 2166AB0E1D82EC56007538D7 /* AIRMapPolygon.m */,
- 2166AB0F1D82EC56007538D7 /* AIRMapPolygonManager.h */,
- 2166AB101D82EC56007538D7 /* AIRMapPolygonManager.m */,
- 2166AB111D82EC56007538D7 /* AIRMapPolyline.h */,
- 2166AB121D82EC56007538D7 /* AIRMapPolyline.m */,
- 2166AB131D82EC56007538D7 /* AIRMapPolylineManager.h */,
- 2166AB141D82EC56007538D7 /* AIRMapPolylineManager.m */,
- 21D346611D933B8C002BAD8A /* AIRMapUrlTile.h */,
- 21D346621D933B8C002BAD8A /* AIRMapUrlTile.m */,
- 21D346631D933B8C002BAD8A /* AIRMapUrlTileManager.h */,
- 21D346641D933B8C002BAD8A /* AIRMapUrlTileManager.m */,
- 2166AB151D82EC56007538D7 /* Callout */,
- 2166AB271D82EC56007538D7 /* RCTConvert+MoreMapKit.h */,
- 2166AB281D82EC56007538D7 /* RCTConvert+MoreMapKit.m */,
- );
- name = AirMaps;
- path = ../../ios/AirMaps;
- sourceTree = "";
- };
- 2166AB151D82EC56007538D7 /* Callout */ = {
- isa = PBXGroup;
- children = (
- 2166AB161D82EC56007538D7 /* SMCalloutView.h */,
- 2166AB171D82EC56007538D7 /* SMCalloutView.m */,
- );
- path = Callout;
- sourceTree = "";
- };
2BAA8C4A80B44CFBB3F83458 /* Libraries */ = {
isa = PBXGroup;
children = (
@@ -269,8 +130,6 @@
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
- 8620CC6C1DBD814A00B79BFE /* AirGoogleMaps */,
- 2166AAFA1D82EC56007538D7 /* AirMaps */,
13B07FAE1A68108700A75B9A /* AirMapsExplorer */,
83CBBA001A601CBA00E9B192 /* Products */,
051AB288C799B62BE091B88A /* Frameworks */,
@@ -290,48 +149,6 @@
name = Products;
sourceTree = "";
};
- 8620CC6C1DBD814A00B79BFE /* AirGoogleMaps */ = {
- isa = PBXGroup;
- children = (
- 8620CC6D1DBD814A00B79BFE /* AIRGMSMarker.h */,
- 8620CC6E1DBD814A00B79BFE /* AIRGMSMarker.m */,
- 8620CC6F1DBD814A00B79BFE /* AIRGoogleMap.h */,
- 8620CC701DBD814A00B79BFE /* AIRGoogleMap.m */,
- 8620CC711DBD814A00B79BFE /* AIRGoogleMapCallout.h */,
- 8620CC721DBD814A00B79BFE /* AIRGoogleMapCallout.m */,
- 8620CC731DBD814A00B79BFE /* AIRGoogleMapCalloutManager.h */,
- 8620CC741DBD814A00B79BFE /* AIRGoogleMapCalloutManager.m */,
- 8620CC751DBD814A00B79BFE /* AIRGoogleMapManager.h */,
- 8620CC761DBD814A00B79BFE /* AIRGoogleMapManager.m */,
- 8620CC771DBD814A00B79BFE /* AIRGoogleMapMarker.h */,
- 8620CC781DBD814A00B79BFE /* AIRGoogleMapMarker.m */,
- 8620CC791DBD814A00B79BFE /* AIRGoogleMapMarkerManager.h */,
- 8620CC7A1DBD814A00B79BFE /* AIRGoogleMapMarkerManager.m */,
- 8620CC7B1DBD814A00B79BFE /* AIRGoogleMapPolygon.h */,
- 8620CC7C1DBD814A00B79BFE /* AIRGoogleMapPolygon.m */,
- 8620CC7D1DBD814A00B79BFE /* AIRGoogleMapPolygonManager.h */,
- 8620CC7E1DBD814A00B79BFE /* AIRGoogleMapPolygonManager.m */,
- 8620CC7F1DBD814A00B79BFE /* AIRGoogleMapPolyline.h */,
- 8620CC801DBD814A00B79BFE /* AIRGoogleMapPolyline.m */,
- 8620CC811DBD814A00B79BFE /* AIRGoogleMapPolylineManager.h */,
- 8620CC821DBD814A00B79BFE /* AIRGoogleMapPolylineManager.m */,
- 8620CC831DBD814A00B79BFE /* DummyView.h */,
- 8620CC841DBD814A00B79BFE /* DummyView.m */,
- 8620CC851DBD814A00B79BFE /* RCTConvert+GMSMapViewType.h */,
- 8620CC861DBD814A00B79BFE /* RCTConvert+GMSMapViewType.m */,
- 8697D6201DBEDE6100DB7D0F /* AIRGoogleMapCircle.h */,
- 8697D6211DBEDE6100DB7D0F /* AIRGoogleMapCircle.m */,
- 8697D6231DBEE22B00DB7D0F /* AIRGoogleMapCircleManager.h */,
- 8697D6241DBEE22B00DB7D0F /* AIRGoogleMapCircleManager.m */,
- 86DE6F861DCE7D21002A5053 /* AIRGoogleMapUrlTile.h */,
- 86DE6F871DCE7D21002A5053 /* AIRGoogleMapUrlTile.m */,
- 86DE6F891DCE8543002A5053 /* AIRGoogleMapUrlTileManager.h */,
- 86DE6F8A1DCE8543002A5053 /* AIRGoogleMapURLTileManager.m */,
- );
- name = AirGoogleMaps;
- path = ../../ios/AirGoogleMaps;
- sourceTree = "";
- };
C2ED0F349F22CC794F9BC33F /* Pods */ = {
isa = PBXGroup;
children = (
@@ -449,7 +266,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "../node_modules/react-native/packager/react-native-xcode.sh";
+ shellScript = "../../node_modules/react-native/packager/react-native-xcode.sh";
};
17E7BB4CEC38ABB7449E144E /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
@@ -472,9 +289,12 @@
files = (
);
inputPaths = (
+ "${SRCROOT}/Pods/Target Support Files/Pods-AirMapsExplorer/Pods-AirMapsExplorer-resources.sh",
+ "${PODS_ROOT}/GoogleMaps/Maps/Frameworks/GoogleMaps.framework/Versions/A/Resources/GoogleMaps.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -487,13 +307,16 @@
files = (
);
inputPaths = (
+ "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
+ "${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputPaths = (
+ "$(DERIVED_FILE_DIR)/Pods-AirMapsExplorer-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n";
+ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -510,42 +333,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 8620CC891DBD814A00B79BFE /* AIRGoogleMapCallout.m in Sources */,
- 8620CC8D1DBD814A00B79BFE /* AIRGoogleMapMarkerManager.m in Sources */,
- 8620CC881DBD814A00B79BFE /* AIRGoogleMap.m in Sources */,
- 2166AB2D1D82EC56007538D7 /* AIRMapCircleManager.m in Sources */,
- 21D346651D933B8C002BAD8A /* AIRMapUrlTile.m in Sources */,
- 2166AB2A1D82EC56007538D7 /* AIRMapCallout.m in Sources */,
- 8620CC8E1DBD814A00B79BFE /* AIRGoogleMapPolygon.m in Sources */,
- 8620CC8C1DBD814A00B79BFE /* AIRGoogleMapMarker.m in Sources */,
- 8620CC8F1DBD814A00B79BFE /* AIRGoogleMapPolygonManager.m in Sources */,
- 8620CC8A1DBD814A00B79BFE /* AIRGoogleMapCalloutManager.m in Sources */,
- 8620CC8B1DBD814A00B79BFE /* AIRGoogleMapManager.m in Sources */,
- 2166AB2C1D82EC56007538D7 /* AIRMapCircle.m in Sources */,
- 8620CC871DBD814A00B79BFE /* AIRGMSMarker.m in Sources */,
- 21D346661D933B8C002BAD8A /* AIRMapUrlTileManager.m in Sources */,
- 8620CC931DBD814A00B79BFE /* RCTConvert+GMSMapViewType.m in Sources */,
- 2166AB301D82EC56007538D7 /* AIRMapMarker.m in Sources */,
- 8697D6221DBEDE6100DB7D0F /* AIRGoogleMapCircle.m in Sources */,
- 2166AB321D82EC56007538D7 /* AIRMapPolygon.m in Sources */,
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
- 2166AB3E1D82EC56007538D7 /* RCTConvert+MoreMapKit.m in Sources */,
- 8697D6251DBEE22B00DB7D0F /* AIRGoogleMapCircleManager.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
- 86DE6F8B1DCE8543002A5053 /* AIRGoogleMapURLTileManager.m in Sources */,
- 86DE6F881DCE7D21002A5053 /* AIRGoogleMapUrlTile.m in Sources */,
- 2166AB331D82EC56007538D7 /* AIRMapPolygonManager.m in Sources */,
- 8620CC901DBD814A00B79BFE /* AIRGoogleMapPolyline.m in Sources */,
- 2166AB2B1D82EC56007538D7 /* AIRMapCalloutManager.m in Sources */,
- 8620CC921DBD814A00B79BFE /* DummyView.m in Sources */,
- 2166AB361D82EC56007538D7 /* SMCalloutView.m in Sources */,
- 2166AB351D82EC56007538D7 /* AIRMapPolylineManager.m in Sources */,
- 8620CC911DBD814A00B79BFE /* AIRGoogleMapPolylineManager.m in Sources */,
- 2166AB291D82EC56007538D7 /* AIRMap.m in Sources */,
- 2166AB2E1D82EC56007538D7 /* AIRMapCoordinate.m in Sources */,
- 2166AB341D82EC56007538D7 /* AIRMapPolyline.m in Sources */,
- 2166AB2F1D82EC56007538D7 /* AIRMapManager.m in Sources */,
- 2166AB311D82EC56007538D7 /* AIRMapMarkerManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -618,6 +407,7 @@
baseConfigurationReference = BE5DE1E9AE25978F88CD940A /* Pods-AirMapsExplorer.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = NO;
DEAD_CODE_STRIPPING = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -627,7 +417,6 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
- "$(SRCROOT)/../node_modules/react-native/React/**",
);
INFOPLIST_FILE = AirMapsExplorer/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -641,6 +430,7 @@
baseConfigurationReference = E138AD0CDB08FE57B09B18F8 /* Pods-AirMapsExplorer.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CLANG_ENABLE_MODULES = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/build/Debug-iphoneos",
@@ -649,7 +439,6 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
- "$(SRCROOT)/../node_modules/react-native/React/**",
);
INFOPLIST_FILE = AirMapsExplorer/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -696,7 +485,6 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
- "$(SRCROOT)/../node_modules/react-native/React/**",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
@@ -736,7 +524,6 @@
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
- "$(SRCROOT)/../node_modules/react-native/React/**",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
diff --git a/example/ios/AirMapsExplorer/AppDelegate.m b/example/ios/AirMapsExplorer/AppDelegate.m
index 91ae54c48..a3b8f5bb9 100644
--- a/example/ios/AirMapsExplorer/AppDelegate.m
+++ b/example/ios/AirMapsExplorer/AppDelegate.m
@@ -9,7 +9,7 @@
#import "AppDelegate.h"
-#import "RCTRootView.h"
+#import
#import
@@ -35,7 +35,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(
* on the same Wi-Fi network.
*/
- jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
+ jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/example/index.bundle?platform=ios&dev=true"];
/**
* OPTION 2
diff --git a/example/ios/AirMapsExplorer/Images.xcassets/AppIcon.appiconset/Contents.json b/example/ios/AirMapsExplorer/Images.xcassets/AppIcon.appiconset/Contents.json
index 118c98f74..b8236c653 100644
--- a/example/ios/AirMapsExplorer/Images.xcassets/AppIcon.appiconset/Contents.json
+++ b/example/ios/AirMapsExplorer/Images.xcassets/AppIcon.appiconset/Contents.json
@@ -1,5 +1,15 @@
{
"images" : [
+ {
+ "idiom" : "iphone",
+ "size" : "20x20",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "iphone",
+ "size" : "20x20",
+ "scale" : "3x"
+ },
{
"idiom" : "iphone",
"size" : "29x29",
diff --git a/example/ios/AirMapsExplorerTests/AirMapsExplorerTests.m b/example/ios/AirMapsExplorerTests/AirMapsExplorerTests.m
index 31dab00aa..a93b699bd 100644
--- a/example/ios/AirMapsExplorerTests/AirMapsExplorerTests.m
+++ b/example/ios/AirMapsExplorerTests/AirMapsExplorerTests.m
@@ -10,8 +10,8 @@
#import
#import
-#import "RCTLog.h"
-#import "RCTRootView.h"
+#import
+#import
#define TIMEOUT_SECONDS 240
#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
diff --git a/example/ios/Gemfile b/example/ios/Gemfile
deleted file mode 100644
index b9ec3be2d..000000000
--- a/example/ios/Gemfile
+++ /dev/null
@@ -1,2 +0,0 @@
-source 'https://rubygems.org'
-gem 'cocoapods', '~>1.1.1'
diff --git a/example/ios/Podfile b/example/ios/Podfile
index 085aad454..aeefe611a 100644
--- a/example/ios/Podfile
+++ b/example/ios/Podfile
@@ -1,17 +1,17 @@
-# You Podfile should look similar to this file. Whether you use_frameworks! or not, the following configuration should work.
-#
-# However if you DO NOT use_frameworks! and you prefer to install pods instead of
-# dragging the AirMaps directory into your project, refer to the comments below (steps 1~4)
-
+# You Podfile should look similar to this file. React Native currently does not support use_frameworks!
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
-use_frameworks!
+# Change 'AirMapsExplorer' to match the target in your Xcode project.
target 'AirMapsExplorer' do
- pod 'React', path: '../node_modules/react-native', :subspecs => [
+ rn_path = '../../node_modules/react-native'
+
+ pod 'yoga', path: "#{rn_path}/ReactCommon/yoga/yoga.podspec"
+ pod 'React', path: rn_path, subspecs: [
'Core',
'RCTActionSheet',
+ 'RCTAnimation',
'RCTGeolocation',
'RCTImage',
'RCTLinkingIOS',
@@ -19,32 +19,21 @@ target 'AirMapsExplorer' do
'RCTSettings',
'RCTText',
'RCTVibration',
- 'RCTWebSocket'
+ 'RCTWebSocket',
+ 'BatchedBridge'
]
-# when not using frameworks we can do this instead of including the source files in our project (1/4):
-# pod 'react-native-maps', path: '../../'
-# pod 'react-native-google-maps', path: '../../' # <~~ if you need GoogleMaps support on iOS
-
-# when not using frameworks we can remove this line (2/4):
- pod 'GoogleMaps' # <~~ remove this line if you do not want to support GoogleMaps on iOS
+ pod 'GoogleMaps' # Remove this line if you don't want to support GoogleMaps on iOS
+ pod 'react-native-maps', path: '../../'
+ pod 'react-native-google-maps', path: '../../' # If you need GoogleMaps support on iOS
end
-# when not using frameworks this might be necessary, but try without it first and see if `pod install` works (3/4):
-# THIS IS ONLY NECESSARY IF YOU NEED GoogleMaps SUPPORT
-# pre_install do |installer|
- # # copied from https://github.com/CocoaPods/CocoaPods/issues/2926
- # # workaround for https://github.com/CocoaPods/CocoaPods/issues/3289
- # def installer.verify_no_static_framework_transitive_dependencies; end
-# end
-
-# when not using frameworks (4/4):
-# THIS IS ONLY NECESSARY IF YOU NEED GoogleMaps SUPPORT
-# #Crud, this shouldn't be necessary, but https://github.com/CocoaPods/CocoaPods/issues/5429
-# post_install do |installer|
-# installer.pods_project.targets.each do |target|
-# target.build_configurations.each do |config|
-# config.build_settings['CLANG_ENABLE_MODULES'] = 'NO'
-# end
-# end
-# end
+post_install do |installer|
+ installer.pods_project.targets.each do |target|
+ if target.name == 'react-native-google-maps'
+ target.build_configurations.each do |config|
+ config.build_settings['CLANG_ENABLE_MODULES'] = 'No'
+ end
+ end
+ end
+end
diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock
index 1f4c2d9a6..b17a261de 100644
--- a/example/ios/Podfile.lock
+++ b/example/ios/Podfile.lock
@@ -1,51 +1,82 @@
PODS:
- - GoogleMaps (2.1.0):
- - GoogleMaps/Maps (= 2.1.0)
- - GoogleMaps/Base (2.1.0)
- - GoogleMaps/Maps (2.1.0):
- - GoogleMaps/Base (= 2.1.0)
- - React/Core (0.35.0)
- - React/RCTActionSheet (0.35.0):
+ - GoogleMaps (2.1.1):
+ - GoogleMaps/Maps (= 2.1.1)
+ - GoogleMaps/Base (2.1.1)
+ - GoogleMaps/Maps (2.1.1):
+ - GoogleMaps/Base
+ - React (0.45.1):
+ - React/Core (= 0.45.1)
+ - react-native-google-maps (0.18.3):
+ - GoogleMaps (= 2.1.1)
+ - React
+ - react-native-maps (0.18.3):
+ - React
+ - React/BatchedBridge (0.45.1):
- React/Core
- - React/RCTGeolocation (0.35.0):
+ - React/cxxreact_legacy
+ - React/Core (0.45.1):
+ - Yoga (= 0.45.1.React)
+ - React/cxxreact_legacy (0.45.1):
+ - React/jschelpers_legacy
+ - React/jschelpers_legacy (0.45.1)
+ - React/RCTActionSheet (0.45.1):
- React/Core
- - React/RCTImage (0.35.0):
+ - React/RCTAnimation (0.45.1):
+ - React/Core
+ - React/RCTGeolocation (0.45.1):
+ - React/Core
+ - React/RCTImage (0.45.1):
- React/Core
- React/RCTNetwork
- - React/RCTLinkingIOS (0.35.0):
+ - React/RCTLinkingIOS (0.45.1):
- React/Core
- - React/RCTNetwork (0.35.0):
+ - React/RCTNetwork (0.45.1):
- React/Core
- - React/RCTSettings (0.35.0):
+ - React/RCTSettings (0.45.1):
- React/Core
- - React/RCTText (0.35.0):
+ - React/RCTText (0.45.1):
- React/Core
- - React/RCTVibration (0.35.0):
+ - React/RCTVibration (0.45.1):
- React/Core
- - React/RCTWebSocket (0.35.0):
+ - React/RCTWebSocket (0.45.1):
- React/Core
+ - Yoga (0.45.1.React)
DEPENDENCIES:
- GoogleMaps
- - React/Core (from `../node_modules/react-native`)
- - React/RCTActionSheet (from `../node_modules/react-native`)
- - React/RCTGeolocation (from `../node_modules/react-native`)
- - React/RCTImage (from `../node_modules/react-native`)
- - React/RCTLinkingIOS (from `../node_modules/react-native`)
- - React/RCTNetwork (from `../node_modules/react-native`)
- - React/RCTSettings (from `../node_modules/react-native`)
- - React/RCTText (from `../node_modules/react-native`)
- - React/RCTVibration (from `../node_modules/react-native`)
- - React/RCTWebSocket (from `../node_modules/react-native`)
+ - react-native-google-maps (from `../../`)
+ - react-native-maps (from `../../`)
+ - React/BatchedBridge (from `../../node_modules/react-native`)
+ - React/Core (from `../../node_modules/react-native`)
+ - React/RCTActionSheet (from `../../node_modules/react-native`)
+ - React/RCTAnimation (from `../../node_modules/react-native`)
+ - React/RCTGeolocation (from `../../node_modules/react-native`)
+ - React/RCTImage (from `../../node_modules/react-native`)
+ - React/RCTLinkingIOS (from `../../node_modules/react-native`)
+ - React/RCTNetwork (from `../../node_modules/react-native`)
+ - React/RCTSettings (from `../../node_modules/react-native`)
+ - React/RCTText (from `../../node_modules/react-native`)
+ - React/RCTVibration (from `../../node_modules/react-native`)
+ - React/RCTWebSocket (from `../../node_modules/react-native`)
+ - Yoga (from `../../node_modules/react-native/ReactCommon/yoga/Yoga.podspec`)
EXTERNAL SOURCES:
React:
- :path: "../node_modules/react-native"
+ :path: ../../node_modules/react-native
+ react-native-google-maps:
+ :path: ../../
+ react-native-maps:
+ :path: ../../
+ Yoga:
+ :path: ../../node_modules/react-native/ReactCommon/yoga/Yoga.podspec
SPEC CHECKSUMS:
- GoogleMaps: 06589b9a38097bce0cd6e90f0fd9b5e4b4a9344c
- React: d80af5410aa500d0cb1bce2cc4493a584cf2ec92
+ GoogleMaps: a5b5bbe47734e2443bde781a6aa64e69fdb6d785
+ React: 0c9191a8b0c843d7004f950ac6b5f6cba9d125c7
+ react-native-google-maps: 73a7f74a00d36c74df41388ebb8394ceba81ef0e
+ react-native-maps: ee0bb36520eb49dfc2bf11754a486a4fa5c5f883
+ Yoga: 89c8738d42a0b46a113acb4e574336d61cba2985
-PODFILE CHECKSUM: be65689c848eff5d4099a483239b72acab62f6a4
+PODFILE CHECKSUM: c069397afd4c9ecf6886b7c00e7d7264dced43a4
-COCOAPODS: 1.1.1
+COCOAPODS: 1.3.1
diff --git a/example/ios/bundler b/example/ios/bundler
new file mode 100755
index 000000000..905387619
--- /dev/null
+++ b/example/ios/bundler
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'bundler' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("bundler", "bundler")
diff --git a/example/ios/fuzzy_match b/example/ios/fuzzy_match
new file mode 100755
index 000000000..f71547393
--- /dev/null
+++ b/example/ios/fuzzy_match
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'fuzzy_match' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("fuzzy_match", "fuzzy_match")
diff --git a/example/ios/pod b/example/ios/pod
new file mode 100755
index 000000000..3c4a4d04c
--- /dev/null
+++ b/example/ios/pod
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'pod' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("cocoapods", "pod")
diff --git a/example/package.json b/example/package.json
deleted file mode 100644
index a303d3cff..000000000
--- a/example/package.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "name": "AirMapsExplorer",
- "version": "0.0.1",
- "private": true,
- "scripts": {
- "start": "react-native start",
- "watch": "node ./scripts/watch-and-copy-src.js",
- "packager": "sh ./node_modules/react-native/packager/packager.sh --root ./node_modules/react-native-maps",
- "dev": "concurrently 'npm run watch' 'npm run packager'"
- },
- "dependencies": {
- "react": "^15.3.1",
- "react-native": "^0.35.0",
- "react-native-maps": "../"
- },
- "devDependencies": {
- "concurrently": "^2.2.0",
- "fs-extra": "^0.30.0",
- "minimatch": "^3.0.2",
- "node-watch": "^0.4.0",
- "rimraf": "^2.5.4"
- }
-}
diff --git a/example/scripts/.eslintrc b/example/scripts/.eslintrc
deleted file mode 100644
index 3c1eaf35a..000000000
--- a/example/scripts/.eslintrc
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "rules": {
- // Scripts can import things in devDependencies
- "import/no-extraneous-dependencies": [2, {"devDependencies": true}]
- }
-}
diff --git a/example/scripts/watch-and-copy-src.js b/example/scripts/watch-and-copy-src.js
deleted file mode 100644
index ed8684894..000000000
--- a/example/scripts/watch-and-copy-src.js
+++ /dev/null
@@ -1,51 +0,0 @@
-const path = require('path');
-const fs = require('fs-extra');
-const watch = require('node-watch');
-const rimraf = require('rimraf');
-const minimatch = require('minimatch');
-
-function copyAndWatch(source, destination, fileGlob) {
- console.log(`Cleaning "${destination}"`);
- rimraf(destination, () => {
- console.log(`Copying "${source}" to "${destination}"`);
- fs.copy(source, destination, (err) => {
- if (err) console.error(err);
- });
-
- console.log(`Watching "${source}"`);
- watch(source, (filename) => {
- const localPath = filename.split(source).pop();
- if (matchesFile(localPath, fileGlob)) {
- const destinationPath = `${destination}${localPath}`;
- console.log(`Copying "${filename}" to "${destinationPath}"`);
- fs.copy(filename, destinationPath, (err) => {
- if (err) console.error(err);
- });
- }
- });
- });
-}
-
-function matchesFile(filename, fileGlob) {
- if (fileGlob == null) return true;
- return minimatch(path.basename(filename), fileGlob);
-}
-
-// JavaScript
-copyAndWatch(
- '../components',
- 'node_modules/react-native-maps/components'
-);
-
-// Android
-copyAndWatch(
- '../android',
- 'node_modules/react-native-maps/android'
-);
-
-// iOS
-copyAndWatch(
- '../ios',
- 'node_modules/react-native-maps/ios',
- '{*.m,*.h,*.swift}'
-);
diff --git a/examples/ios/bundler b/examples/ios/bundler
new file mode 100755
index 000000000..905387619
--- /dev/null
+++ b/examples/ios/bundler
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'bundler' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("bundler", "bundler")
diff --git a/examples/ios/fuzzy_match b/examples/ios/fuzzy_match
new file mode 100755
index 000000000..f71547393
--- /dev/null
+++ b/examples/ios/fuzzy_match
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'fuzzy_match' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("fuzzy_match", "fuzzy_match")
diff --git a/examples/ios/pod b/examples/ios/pod
new file mode 100755
index 000000000..3c4a4d04c
--- /dev/null
+++ b/examples/ios/pod
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'pod' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("cocoapods", "pod")
diff --git a/examples/ios/sandbox-pod b/examples/ios/sandbox-pod
new file mode 100755
index 000000000..c76cfd0a5
--- /dev/null
+++ b/examples/ios/sandbox-pod
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'sandbox-pod' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("cocoapods", "sandbox-pod")
diff --git a/examples/ios/xcodeproj b/examples/ios/xcodeproj
new file mode 100755
index 000000000..3c3452c17
--- /dev/null
+++ b/examples/ios/xcodeproj
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'xcodeproj' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("xcodeproj", "xcodeproj")
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..4f308ee04
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..e5fa88cc4
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon May 08 11:03:28 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
diff --git a/example/android/gradlew b/gradlew
similarity index 83%
rename from example/android/gradlew
rename to gradlew
index 91a7e269e..4453ccea3 100755
--- a/example/android/gradlew
+++ b/gradlew
@@ -1,4 +1,4 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
##############################################################################
##
@@ -6,12 +6,30 @@
##
##############################################################################
-# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
@@ -30,6 +48,7 @@ die ( ) {
cygwin=false
msys=false
darwin=false
+nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
@@ -40,31 +59,11 @@ case "`uname`" in
MINGW* )
msys=true
;;
+ NONSTOP* )
+ nonstop=true
+ ;;
esac
-# For Cygwin, ensure paths are in UNIX format before anything is touched.
-if $cygwin ; then
- [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
-fi
-
-# Attempt to set APP_HOME
-# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
-done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >&-
-APP_HOME="`pwd -P`"
-cd "$SAVED" >&-
-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
@@ -90,7 +89,7 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
@@ -114,6 +113,7 @@ fi
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
@@ -154,11 +154,19 @@ if $cygwin ; then
esac
fi
-# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
-function splitJvmOpts() {
- JVM_OPTS=("$@")
+# Escape application args
+save ( ) {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
}
-eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
-JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
-exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
+exec "$JAVACMD" "$@"
diff --git a/example/android/gradlew.bat b/gradlew.bat
similarity index 88%
rename from example/android/gradlew.bat
rename to gradlew.bat
index aec99730b..e95643d6a 100644
--- a/example/android/gradlew.bat
+++ b/gradlew.bat
@@ -8,14 +8,14 @@
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
-@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
-
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
@@ -46,10 +46,9 @@ echo location of your Java installation.
goto fail
:init
-@rem Get command-line arguments, handling Windowz variants
+@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
-if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
-goto execute
-
-:4NT_args
-@rem Get arguments from the 4NT Shell from JP Software
-set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
diff --git a/index.d.ts b/index.d.ts
new file mode 100644
index 000000000..bdc2075e4
--- /dev/null
+++ b/index.d.ts
@@ -0,0 +1,158 @@
+import * as React from 'react';
+
+interface MapViewProps {
+ provider?: 'google';
+ style: any;
+ customMapStyle?: any[];
+ customMapStyleString?: string;
+ showsUserLocation?: boolean;
+ userLocationAnnotationTitle?: string;
+ showsMyLocationButton?: boolean;
+ followsUserLocation?: boolean;
+ showsPointsOfInterest?: boolean;
+ showsCompass?: boolean;
+ zoomEnabled?: boolean;
+ rotateEnabled?: boolean;
+ cacheEnabled?: boolean;
+ loadingEnabled?: boolean;
+ loadingBackgroundColor?: any;
+ loadingIndicatorColor?: any;
+ scrollEnabled?: boolean;
+ pitchEnabled?: boolean;
+ toolbarEnabled?: boolean;
+ moveOnMarkerPress?: boolean;
+ showsScale?: boolean;
+ showsBuildings?: boolean;
+ showsTraffic?: boolean;
+ showsIndoors?: boolean;
+ showsIndoorLevelPicker?: boolean;
+ mapType?: 'standard' | 'satellite' | 'hybrid' | 'terrain' | 'none' | 'mutedStandard';
+ region?: { latitude: number; longitude: number; latitudeDelta: number; longitudeDelta: number; };
+ initialRegion?: { latitude: number; longitude: number; latitudeDelta: number; longitudeDelta: number; };
+ liteMode?: boolean;
+ maxDelta?: number;
+ minDelta?: number;
+ legalLabelInsets?: any;
+ onChange?: Function;
+ onMapReady?: Function;
+ onRegionChange?: Function;
+ onRegionChangeComplete?: Function;
+ onPress?: Function;
+ onLayout?: Function;
+ onLongPress?: Function;
+ onPanDrag?: Function;
+ onMarkerPress?: Function;
+ onMarkerSelect?: Function;
+ onMarkerDeselect?: Function;
+ onCalloutPress?: Function;
+ onMarkerDragStart?: Function;
+ onMarkerDrag?: Function;
+ onMarkerDragEnd?: Function;
+ minZoomLevel?: number;
+ maxZoomLevel?: number;
+}
+
+declare class MapView extends React.Component {
+ static Animated: any;
+ static AnimatedRegion: any;
+}
+
+declare namespace MapView {
+
+ type LineCapType = 'butt' | 'round' | 'square';
+ type LineJoinType = 'miter' | 'round' | 'bevel';
+
+ interface MarkerProps {
+ identifier?: string;
+ reuseIdentifier?: string;
+ title?: string;
+ description?: string;
+ image?: any;
+ opacity?: number;
+ pinColor?: string;
+ coordinate: { latitude: number; longitude: number };
+ centerOffset?: { x: number; y: number };
+ calloutOffset?: { x: number; y: number };
+ anchor?: { x: number; y: number };
+ calloutAnchor?: { x: number; y: number };
+ flat?: boolean;
+ draggable?: boolean;
+ onPress?: Function;
+ onSelect?: Function;
+ onDeselect?: Function;
+ onCalloutPress?: Function;
+ onDragStart?: Function;
+ onDrag?: Function;
+ onDragEnd?: Function;
+ zIndex?: number;
+ style?: any;
+ }
+
+ interface MapPolylineProps {
+ coordinates?: { latitude: number; longitude: number; }[];
+ onPress?: Function;
+ tappable?: boolean;
+ fillColor?: string;
+ strokeWidth?: number;
+ strokeColor?: string;
+ zIndex?: number;
+ lineCap?: LineCapType;
+ lineJoin?: LineJoinType;
+ miterLimit?: number;
+ geodesic?: boolean;
+ lineDashPhase?: number;
+ lineDashPattern?: number[];
+ }
+
+ interface MapPolygonProps {
+ coordinates?: { latitude: number; longitude: number; }[];
+ holes?: { latitude: number; longitude: number; }[][];
+ onPress?: Function;
+ tappable?: boolean;
+ strokeWidth?: number;
+ strokeColor?: string;
+ fillColor?: string;
+ zIndex?: number;
+ lineCap?: LineCapType;
+ lineJoin?: LineJoinType;
+ miterLimit?: number;
+ geodesic?: boolean;
+ lineDashPhase?: number;
+ lineDashPattern?: number[];
+ }
+
+ interface MapCircleProps {
+ center: { latitude: number; longitude: number };
+ radius: number;
+ onPress?: Function;
+ strokeWidth?: number;
+ strokeColor?: string;
+ fillColor?: string;
+ zIndex?: number;
+ lineCap?: LineCapType;
+ lineJoin?: LineJoinType;
+ miterLimit?: number;
+ lineDashPhase?: number;
+ lineDashPattern?: number[];
+ }
+
+ interface MapUrlTitleProps {
+ urlTemplate: string;
+ zIndex?: number;
+ }
+
+ interface MapCalloutProps {
+ tooltip?: boolean;
+ onPress?: Function;
+ style?: any;
+ }
+
+ export class Marker extends React.Component {}
+ export class Polyline extends React.Component {}
+ export class Polygon extends React.Component {}
+ export class Circle extends React.Component {}
+ export class UrlTile extends React.Component {}
+ export class Callout extends React.Component {}
+}
+
+export = MapView;
diff --git a/index.js b/index.js
index b2d7d79e1..207d0119d 100644
--- a/index.js
+++ b/index.js
@@ -1,3 +1,3 @@
-import MapView from './components/MapView';
+import MapView from './lib/components/MapView';
module.exports = MapView;
diff --git a/ios/AirMaps/AIRMapManager.h b/ios/AirMaps/AIRMapManager.h
deleted file mode 100644
index f3ffd4515..000000000
--- a/ios/AirMaps/AIRMapManager.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Copyright (c) 2015-present, Facebook, Inc.
- * All rights reserved.
- *
- * This source code is licensed under the BSD-style license found in the
- * LICENSE file in the root directory of this source tree. An additional grant
- * of patent rights can be found in the PATENTS file in the same directory.
- */
-
-#import "RCTViewManager.h"
-
-@interface AIRMapManager : RCTViewManager
-
-@end
diff --git a/ios/AirMaps/RCTConvert+MoreMapKit.h b/ios/AirMaps/RCTConvert+MoreMapKit.h
deleted file mode 100644
index 96c99a599..000000000
--- a/ios/AirMaps/RCTConvert+MoreMapKit.h
+++ /dev/null
@@ -1,12 +0,0 @@
-//
-// Created by Leland Richardson on 12/27/15.
-// Copyright (c) 2015 Facebook. All rights reserved.
-//
-
-#import
-#import
-#import "RCTConvert.h"
-
-@interface RCTConvert (MoreMapKit)
-
-@end
\ No newline at end of file
diff --git a/ios/AirMaps/RCTConvert+MoreMapKit.m b/ios/AirMaps/RCTConvert+MoreMapKit.m
deleted file mode 100644
index 2292cb878..000000000
--- a/ios/AirMaps/RCTConvert+MoreMapKit.m
+++ /dev/null
@@ -1,27 +0,0 @@
-//
-// Created by Leland Richardson on 12/27/15.
-// Copyright (c) 2015 Facebook. All rights reserved.
-//
-
-#import "RCTConvert+MoreMapKit.h"
-#import "AIRMapCoordinate.h"
-#import "RCTConvert+CoreLocation.h"
-
-
-@implementation RCTConvert (MoreMapKit)
-
-// NOTE(lmr):
-// This is a bit of a hack, but I'm using this class to simply wrap
-// around a `CLLocationCoordinate2D`, since I was unable to figure out
-// how to handle an array of structs like CLLocationCoordinate2D. Would love
-// to get rid of this if someone can show me how...
-+ (AIRMapCoordinate *)AIRMapCoordinate:(id)json
-{
- AIRMapCoordinate *coord = [AIRMapCoordinate new];
- coord.coordinate = [self CLLocationCoordinate2D:json];
- return coord;
-}
-
-RCT_ARRAY_CONVERTER(AIRMapCoordinate)
-
-@end
\ No newline at end of file
diff --git a/lib/android/build.gradle b/lib/android/build.gradle
new file mode 100644
index 000000000..fde55416f
--- /dev/null
+++ b/lib/android/build.gradle
@@ -0,0 +1,41 @@
+apply plugin: 'com.android.library'
+apply from: 'gradle-maven-push.gradle'
+
+android {
+ compileSdkVersion 25
+ buildToolsVersion "25.0.3"
+
+ defaultConfig {
+ minSdkVersion 16
+ targetSdkVersion 25
+ }
+
+ packagingOptions {
+ exclude 'META-INF/LICENSE'
+ exclude 'META-INF/DEPENDENCIES.txt'
+ exclude 'META-INF/LICENSE.txt'
+ exclude 'META-INF/NOTICE.txt'
+ exclude 'META-INF/NOTICE'
+ exclude 'META-INF/DEPENDENCIES'
+ exclude 'META-INF/notice.txt'
+ exclude 'META-INF/license.txt'
+ exclude 'META-INF/dependencies.txt'
+ exclude 'META-INF/LGPL2.1'
+ }
+
+ lintOptions {
+ disable 'InvalidPackage'
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_7
+ targetCompatibility JavaVersion.VERSION_1_7
+ }
+}
+
+dependencies {
+ provided "com.facebook.react:react-native:+"
+ compile "com.google.android.gms:play-services-base:10.2.4"
+ compile "com.google.android.gms:play-services-maps:10.2.4"
+ compile "com.google.maps.android:android-maps-utils:0.4+"
+}
diff --git a/android/gradle-maven-push.gradle b/lib/android/gradle-maven-push.gradle
similarity index 100%
rename from android/gradle-maven-push.gradle
rename to lib/android/gradle-maven-push.gradle
diff --git a/android/gradle.properties b/lib/android/gradle.properties
similarity index 94%
rename from android/gradle.properties
rename to lib/android/gradle.properties
index ff024eb51..e4ea9f69d 100644
--- a/android/gradle.properties
+++ b/lib/android/gradle.properties
@@ -1,5 +1,5 @@
-VERSION_CODE=2
-VERSION_NAME=0.11.0
+VERSION_CODE=4
+VERSION_NAME=0.18.3
GROUP=com.airbnb.android
POM_DESCRIPTION=React Native Map view component for Android
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/lib/android/gradle/wrapper/gradle-wrapper.jar
similarity index 100%
rename from android/gradle/wrapper/gradle-wrapper.jar
rename to lib/android/gradle/wrapper/gradle-wrapper.jar
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/lib/android/gradle/wrapper/gradle-wrapper.properties
similarity index 100%
rename from android/gradle/wrapper/gradle-wrapper.properties
rename to lib/android/gradle/wrapper/gradle-wrapper.properties
diff --git a/android/gradlew b/lib/android/gradlew
similarity index 100%
rename from android/gradlew
rename to lib/android/gradlew
diff --git a/android/gradlew.bat b/lib/android/gradlew.bat
similarity index 100%
rename from android/gradlew.bat
rename to lib/android/gradlew.bat
diff --git a/android/src/main/AndroidManifest.xml b/lib/android/src/main/AndroidManifest.xml
similarity index 87%
rename from android/src/main/AndroidManifest.xml
rename to lib/android/src/main/AndroidManifest.xml
index e07e0af89..071ed0a39 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/lib/android/src/main/AndroidManifest.xml
@@ -1,6 +1,7 @@
+
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCallout.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCallout.java
new file mode 100644
index 000000000..6f96e15da
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCallout.java
@@ -0,0 +1,23 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+
+import com.facebook.react.views.view.ReactViewGroup;
+
+public class AirMapCallout extends ReactViewGroup {
+ private boolean tooltip = false;
+ public int width;
+ public int height;
+
+ public AirMapCallout(Context context) {
+ super(context);
+ }
+
+ public void setTooltip(boolean tooltip) {
+ this.tooltip = tooltip;
+ }
+
+ public boolean getTooltip() {
+ return this.tooltip;
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCalloutManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCalloutManager.java
new file mode 100644
index 000000000..b63ea29ff
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCalloutManager.java
@@ -0,0 +1,56 @@
+package com.airbnb.android.react.maps;
+
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.LayoutShadowNode;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.uimanager.annotations.ReactProp;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+public class AirMapCalloutManager extends ViewGroupManager {
+
+ @Override
+ public String getName() {
+ return "AIRMapCallout";
+ }
+
+ @Override
+ public AirMapCallout createViewInstance(ThemedReactContext context) {
+ return new AirMapCallout(context);
+ }
+
+ @ReactProp(name = "tooltip", defaultBoolean = false)
+ public void setTooltip(AirMapCallout view, boolean tooltip) {
+ view.setTooltip(tooltip);
+ }
+
+ @Override
+ @Nullable
+ public Map getExportedCustomDirectEventTypeConstants() {
+ return MapBuilder.of("onPress", MapBuilder.of("registrationName", "onPress"));
+ }
+
+ @Override
+ public LayoutShadowNode createShadowNodeInstance() {
+ // we use a custom shadow node that emits the width/height of the view
+ // after layout with the updateExtraData method. Without this, we can't generate
+ // a bitmap of the appropriate width/height of the rendered view.
+ return new SizeReportingShadowNode();
+ }
+
+ @Override
+ public void updateExtraData(AirMapCallout view, Object extraData) {
+ // This method is called from the shadow node with the width/height of the rendered
+ // marker view.
+ //noinspection unchecked
+ Map data = (Map) extraData;
+ float width = data.get("width");
+ float height = data.get("height");
+ view.width = (int) width;
+ view.height = (int) height;
+ }
+
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircle.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircle.java
new file mode 100644
index 000000000..a70d9146a
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircle.java
@@ -0,0 +1,100 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.model.Circle;
+import com.google.android.gms.maps.model.CircleOptions;
+import com.google.android.gms.maps.model.LatLng;
+
+public class AirMapCircle extends AirMapFeature {
+
+ private CircleOptions circleOptions;
+ private Circle circle;
+
+ private LatLng center;
+ private double radius;
+ private int strokeColor;
+ private int fillColor;
+ private float strokeWidth;
+ private float zIndex;
+
+ public AirMapCircle(Context context) {
+ super(context);
+ }
+
+ public void setCenter(LatLng center) {
+ this.center = center;
+ if (circle != null) {
+ circle.setCenter(this.center);
+ }
+ }
+
+ public void setRadius(double radius) {
+ this.radius = radius;
+ if (circle != null) {
+ circle.setRadius(this.radius);
+ }
+ }
+
+ public void setFillColor(int color) {
+ this.fillColor = color;
+ if (circle != null) {
+ circle.setFillColor(color);
+ }
+ }
+
+ public void setStrokeColor(int color) {
+ this.strokeColor = color;
+ if (circle != null) {
+ circle.setStrokeColor(color);
+ }
+ }
+
+ public void setStrokeWidth(float width) {
+ this.strokeWidth = width;
+ if (circle != null) {
+ circle.setStrokeWidth(width);
+ }
+ }
+
+ public void setZIndex(float zIndex) {
+ this.zIndex = zIndex;
+ if (circle != null) {
+ circle.setZIndex(zIndex);
+ }
+ }
+
+ public CircleOptions getCircleOptions() {
+ if (circleOptions == null) {
+ circleOptions = createCircleOptions();
+ }
+ return circleOptions;
+ }
+
+ private CircleOptions createCircleOptions() {
+ CircleOptions options = new CircleOptions();
+ options.center(center);
+ options.radius(radius);
+ options.fillColor(fillColor);
+ options.strokeColor(strokeColor);
+ options.strokeWidth(strokeWidth);
+ options.zIndex(zIndex);
+ return options;
+ }
+
+ @Override
+ public Object getFeature() {
+ return circle;
+ }
+
+ @Override
+ public void addToMap(GoogleMap map) {
+ circle = map.addCircle(getCircleOptions());
+ }
+
+ @Override
+ public void removeFromMap(GoogleMap map) {
+ circle.remove();
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircleManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircleManager.java
new file mode 100644
index 000000000..c8eabf2d1
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircleManager.java
@@ -0,0 +1,72 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.google.android.gms.maps.model.LatLng;
+
+public class AirMapCircleManager extends ViewGroupManager {
+ private final DisplayMetrics metrics;
+
+ public AirMapCircleManager(ReactApplicationContext reactContext) {
+ super();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ metrics = new DisplayMetrics();
+ ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay()
+ .getRealMetrics(metrics);
+ } else {
+ metrics = reactContext.getResources().getDisplayMetrics();
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "AIRMapCircle";
+ }
+
+ @Override
+ public AirMapCircle createViewInstance(ThemedReactContext context) {
+ return new AirMapCircle(context);
+ }
+
+ @ReactProp(name = "center")
+ public void setCenter(AirMapCircle view, ReadableMap center) {
+ view.setCenter(new LatLng(center.getDouble("latitude"), center.getDouble("longitude")));
+ }
+
+ @ReactProp(name = "radius", defaultDouble = 0)
+ public void setRadius(AirMapCircle view, double radius) {
+ view.setRadius(radius);
+ }
+
+ @ReactProp(name = "strokeWidth", defaultFloat = 1f)
+ public void setStrokeWidth(AirMapCircle view, float widthInPoints) {
+ float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
+ view.setStrokeWidth(widthInScreenPx);
+ }
+
+ @ReactProp(name = "fillColor", defaultInt = Color.RED, customType = "Color")
+ public void setFillColor(AirMapCircle view, int color) {
+ view.setFillColor(color);
+ }
+
+ @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
+ public void setStrokeColor(AirMapCircle view, int color) {
+ view.setStrokeColor(color);
+ }
+
+ @ReactProp(name = "zIndex", defaultFloat = 1.0f)
+ public void setZIndex(AirMapCircle view, float zIndex) {
+ view.setZIndex(zIndex);
+ }
+
+}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapFeature.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapFeature.java
similarity index 52%
rename from android/src/main/java/com/airbnb/android/react/maps/AirMapFeature.java
rename to lib/android/src/main/java/com/airbnb/android/react/maps/AirMapFeature.java
index 1c15ade5f..70484c1a4 100644
--- a/android/src/main/java/com/airbnb/android/react/maps/AirMapFeature.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapFeature.java
@@ -6,13 +6,13 @@
import com.google.android.gms.maps.GoogleMap;
public abstract class AirMapFeature extends ReactViewGroup {
- public AirMapFeature(Context context) {
- super(context);
- }
+ public AirMapFeature(Context context) {
+ super(context);
+ }
- public abstract void addToMap(GoogleMap map);
+ public abstract void addToMap(GoogleMap map);
- public abstract void removeFromMap(GoogleMap map);
+ public abstract void removeFromMap(GoogleMap map);
- public abstract Object getFeature();
+ public abstract Object getFeature();
}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapGeoJSON.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapGeoJSON.java
similarity index 100%
rename from android/src/main/java/com/airbnb/android/react/maps/AirMapGeoJSON.java
rename to lib/android/src/main/java/com/airbnb/android/react/maps/AirMapGeoJSON.java
diff --git a/android/src/main/java/com/airbnb/android/react/maps/AirMapGeoJSONManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapGeoJSONManager.java
similarity index 100%
rename from android/src/main/java/com/airbnb/android/react/maps/AirMapGeoJSONManager.java
rename to lib/android/src/main/java/com/airbnb/android/react/maps/AirMapGeoJSONManager.java
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapLiteManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapLiteManager.java
new file mode 100644
index 000000000..619e36435
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapLiteManager.java
@@ -0,0 +1,20 @@
+package com.airbnb.android.react.maps;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.google.android.gms.maps.GoogleMapOptions;
+
+public class AirMapLiteManager extends AirMapManager {
+
+ private static final String REACT_CLASS = "AIRMapLite";
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+
+ public AirMapLiteManager(ReactApplicationContext context) {
+ super(context);
+ this.googleMapOptions = new GoogleMapOptions().liteMode(true);
+ }
+
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java
new file mode 100644
index 000000000..03e4597bb
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java
@@ -0,0 +1,379 @@
+package com.airbnb.android.react.maps;
+
+import android.view.View;
+
+import com.facebook.react.bridge.Arguments;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.modules.core.DeviceEventManagerModule;
+import com.facebook.react.uimanager.LayoutShadowNode;
+import com.facebook.react.uimanager.ThemedReactContext;
+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.maps.GoogleMap;
+import com.google.android.gms.maps.GoogleMapOptions;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
+import com.google.android.gms.maps.model.MapStyleOptions;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+public class AirMapManager extends ViewGroupManager {
+
+ private static final String REACT_CLASS = "AIRMap";
+ private static final int ANIMATE_TO_REGION = 1;
+ private static final int ANIMATE_TO_COORDINATE = 2;
+ private static final int ANIMATE_TO_VIEWING_ANGLE = 3;
+ private static final int ANIMATE_TO_BEARING = 4;
+ private static final int FIT_TO_ELEMENTS = 5;
+ private static final int FIT_TO_SUPPLIED_MARKERS = 6;
+ private static final int FIT_TO_COORDINATES = 7;
+ private static final int SET_MAP_BOUNDARIES = 8;
+
+
+ private final Map MAP_TYPES = MapBuilder.of(
+ "standard", GoogleMap.MAP_TYPE_NORMAL,
+ "satellite", GoogleMap.MAP_TYPE_SATELLITE,
+ "hybrid", GoogleMap.MAP_TYPE_HYBRID,
+ "terrain", GoogleMap.MAP_TYPE_TERRAIN,
+ "none", GoogleMap.MAP_TYPE_NONE
+ );
+
+ private final ReactApplicationContext appContext;
+
+ protected GoogleMapOptions googleMapOptions;
+
+ public AirMapManager(ReactApplicationContext context) {
+ this.appContext = context;
+ this.googleMapOptions = new GoogleMapOptions();
+ }
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+
+ @Override
+ protected AirMapView createViewInstance(ThemedReactContext context) {
+ return new AirMapView(context, this.appContext, this, googleMapOptions);
+ }
+
+ private void emitMapError(ThemedReactContext context, String message, String type) {
+ WritableMap error = Arguments.createMap();
+ error.putString("message", message);
+ error.putString("type", type);
+
+ context
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
+ .emit("onError", error);
+ }
+
+ @ReactProp(name = "region")
+ public void setRegion(AirMapView view, ReadableMap region) {
+ view.setRegion(region);
+ }
+
+ @ReactProp(name = "initialRegion")
+ public void setInitialRegion(AirMapView view, ReadableMap initialRegion) {
+ view.setInitialRegion(initialRegion);
+ }
+
+ @ReactProp(name = "mapType")
+ public void setMapType(AirMapView view, @Nullable String mapType) {
+ int typeId = MAP_TYPES.get(mapType);
+ view.map.setMapType(typeId);
+ }
+
+ @ReactProp(name = "customMapStyleString")
+ public void setMapStyle(AirMapView view, @Nullable String customMapStyleString) {
+ view.map.setMapStyle(new MapStyleOptions(customMapStyleString));
+ }
+
+ @ReactProp(name = "mapPadding")
+ public void setMapPadding(AirMapView view, @Nullable ReadableMap padding) {
+ int left = 0;
+ int top = 0;
+ int right = 0;
+ int bottom = 0;
+ double density = (double) view.getResources().getDisplayMetrics().density;
+
+ if (padding != null) {
+ if (padding.hasKey("left")) {
+ left = (int) (padding.getDouble("left") * density);
+ }
+
+ if (padding.hasKey("top")) {
+ top = (int) (padding.getDouble("top") * density);
+ }
+
+ if (padding.hasKey("right")) {
+ right = (int) (padding.getDouble("right") * density);
+ }
+
+ if (padding.hasKey("bottom")) {
+ bottom = (int) (padding.getDouble("bottom") * density);
+ }
+ }
+
+ view.map.setPadding(left, top, right, bottom);
+ }
+
+ @ReactProp(name = "showsUserLocation", defaultBoolean = false)
+ public void setShowsUserLocation(AirMapView view, boolean showUserLocation) {
+ view.setShowsUserLocation(showUserLocation);
+ }
+
+ @ReactProp(name = "showsMyLocationButton", defaultBoolean = true)
+ public void setShowsMyLocationButton(AirMapView view, boolean showMyLocationButton) {
+ view.setShowsMyLocationButton(showMyLocationButton);
+ }
+
+ @ReactProp(name = "toolbarEnabled", defaultBoolean = true)
+ public void setToolbarEnabled(AirMapView view, boolean toolbarEnabled) {
+ view.setToolbarEnabled(toolbarEnabled);
+ }
+
+ // This is a private prop to improve performance of panDrag by disabling it when the callback
+ // is not set
+ @ReactProp(name = "handlePanDrag", defaultBoolean = false)
+ public void setHandlePanDrag(AirMapView view, boolean handlePanDrag) {
+ view.setHandlePanDrag(handlePanDrag);
+ }
+
+ @ReactProp(name = "showsTraffic", defaultBoolean = false)
+ public void setShowTraffic(AirMapView view, boolean showTraffic) {
+ view.map.setTrafficEnabled(showTraffic);
+ }
+
+ @ReactProp(name = "showsBuildings", defaultBoolean = false)
+ public void setShowBuildings(AirMapView view, boolean showBuildings) {
+ view.map.setBuildingsEnabled(showBuildings);
+ }
+
+ @ReactProp(name = "showsIndoors", defaultBoolean = false)
+ public void setShowIndoors(AirMapView view, boolean showIndoors) {
+ view.map.setIndoorEnabled(showIndoors);
+ }
+
+ @ReactProp(name = "showsIndoorLevelPicker", defaultBoolean = false)
+ public void setShowsIndoorLevelPicker(AirMapView view, boolean showsIndoorLevelPicker) {
+ view.map.getUiSettings().setIndoorLevelPickerEnabled(showsIndoorLevelPicker);
+ }
+
+ @ReactProp(name = "showsCompass", defaultBoolean = false)
+ public void setShowsCompass(AirMapView view, boolean showsCompass) {
+ view.map.getUiSettings().setCompassEnabled(showsCompass);
+ }
+
+ @ReactProp(name = "scrollEnabled", defaultBoolean = false)
+ public void setScrollEnabled(AirMapView view, boolean scrollEnabled) {
+ view.map.getUiSettings().setScrollGesturesEnabled(scrollEnabled);
+ }
+
+ @ReactProp(name = "zoomEnabled", defaultBoolean = false)
+ public void setZoomEnabled(AirMapView view, boolean zoomEnabled) {
+ view.map.getUiSettings().setZoomGesturesEnabled(zoomEnabled);
+ }
+
+ @ReactProp(name = "rotateEnabled", defaultBoolean = false)
+ public void setRotateEnabled(AirMapView view, boolean rotateEnabled) {
+ view.map.getUiSettings().setRotateGesturesEnabled(rotateEnabled);
+ }
+
+ @ReactProp(name = "cacheEnabled", defaultBoolean = false)
+ public void setCacheEnabled(AirMapView view, boolean cacheEnabled) {
+ view.setCacheEnabled(cacheEnabled);
+ }
+
+ @ReactProp(name = "loadingEnabled", defaultBoolean = false)
+ public void setLoadingEnabled(AirMapView view, boolean loadingEnabled) {
+ view.enableMapLoading(loadingEnabled);
+ }
+
+ @ReactProp(name = "moveOnMarkerPress", defaultBoolean = true)
+ public void setMoveOnMarkerPress(AirMapView view, boolean moveOnPress) {
+ view.setMoveOnMarkerPress(moveOnPress);
+ }
+
+ @ReactProp(name = "loadingBackgroundColor", customType = "Color")
+ public void setLoadingBackgroundColor(AirMapView view, @Nullable Integer loadingBackgroundColor) {
+ view.setLoadingBackgroundColor(loadingBackgroundColor);
+ }
+
+ @ReactProp(name = "loadingIndicatorColor", customType = "Color")
+ public void setLoadingIndicatorColor(AirMapView view, @Nullable Integer loadingIndicatorColor) {
+ view.setLoadingIndicatorColor(loadingIndicatorColor);
+ }
+
+ @ReactProp(name = "pitchEnabled", defaultBoolean = false)
+ public void setPitchEnabled(AirMapView view, boolean pitchEnabled) {
+ view.map.getUiSettings().setTiltGesturesEnabled(pitchEnabled);
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ public void setMinZoomLevel(AirMapView view, float minZoomLevel) {
+ view.map.setMinZoomPreference(minZoomLevel);
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ public void setMaxZoomLevel(AirMapView view, float maxZoomLevel) {
+ view.map.setMaxZoomPreference(maxZoomLevel);
+ }
+
+ @Override
+ public void receiveCommand(AirMapView view, int commandId, @Nullable ReadableArray args) {
+ Integer duration;
+ Double lat;
+ Double lng;
+ Double lngDelta;
+ Double latDelta;
+ float bearing;
+ float angle;
+ ReadableMap region;
+
+ switch (commandId) {
+ case ANIMATE_TO_REGION:
+ region = args.getMap(0);
+ duration = args.getInt(1);
+ lng = region.getDouble("longitude");
+ lat = region.getDouble("latitude");
+ lngDelta = region.getDouble("longitudeDelta");
+ latDelta = region.getDouble("latitudeDelta");
+ LatLngBounds bounds = new LatLngBounds(
+ new LatLng(lat - latDelta / 2, lng - lngDelta / 2), // southwest
+ new LatLng(lat + latDelta / 2, lng + lngDelta / 2) // northeast
+ );
+ view.animateToRegion(bounds, duration);
+ break;
+
+ case ANIMATE_TO_COORDINATE:
+ region = args.getMap(0);
+ duration = args.getInt(1);
+ lng = region.getDouble("longitude");
+ lat = region.getDouble("latitude");
+ view.animateToCoordinate(new LatLng(lat, lng), duration);
+ break;
+
+ case ANIMATE_TO_VIEWING_ANGLE:
+ angle = (float)args.getDouble(0);
+ duration = args.getInt(1);
+ view.animateToViewingAngle(angle, duration);
+ break;
+
+ case ANIMATE_TO_BEARING:
+ bearing = (float)args.getDouble(0);
+ duration = args.getInt(1);
+ view.animateToBearing(bearing, duration);
+ break;
+
+ case FIT_TO_ELEMENTS:
+ view.fitToElements(args.getBoolean(0));
+ break;
+
+ case FIT_TO_SUPPLIED_MARKERS:
+ view.fitToSuppliedMarkers(args.getArray(0), args.getBoolean(1));
+ break;
+
+ case FIT_TO_COORDINATES:
+ view.fitToCoordinates(args.getArray(0), args.getMap(1), args.getBoolean(2));
+ break;
+
+ case SET_MAP_BOUNDARIES:
+ view.setMapBoundaries(args.getMap(0), args.getMap(1));
+ break;
+ }
+ }
+
+ @Override
+ @Nullable
+ public Map getExportedCustomDirectEventTypeConstants() {
+ Map> map = MapBuilder.of(
+ "onMapReady", MapBuilder.of("registrationName", "onMapReady"),
+ "onPress", MapBuilder.of("registrationName", "onPress"),
+ "onLongPress", MapBuilder.of("registrationName", "onLongPress"),
+ "onMarkerPress", MapBuilder.of("registrationName", "onMarkerPress"),
+ "onMarkerSelect", MapBuilder.of("registrationName", "onMarkerSelect"),
+ "onMarkerDeselect", MapBuilder.of("registrationName", "onMarkerDeselect"),
+ "onCalloutPress", MapBuilder.of("registrationName", "onCalloutPress")
+ );
+
+ map.putAll(MapBuilder.of(
+ "onMarkerDragStart", MapBuilder.of("registrationName", "onMarkerDragStart"),
+ "onMarkerDrag", MapBuilder.of("registrationName", "onMarkerDrag"),
+ "onMarkerDragEnd", MapBuilder.of("registrationName", "onMarkerDragEnd"),
+ "onPanDrag", MapBuilder.of("registrationName", "onPanDrag")
+ ));
+
+ return map;
+ }
+
+ @Nullable
+ @Override
+ public Map getCommandsMap() {
+ Map map = MapBuilder.of(
+ "animateToRegion", ANIMATE_TO_REGION,
+ "animateToCoordinate", ANIMATE_TO_COORDINATE,
+ "animateToViewingAngle", ANIMATE_TO_VIEWING_ANGLE,
+ "animateToBearing", ANIMATE_TO_BEARING,
+ "fitToElements", FIT_TO_ELEMENTS,
+ "fitToSuppliedMarkers", FIT_TO_SUPPLIED_MARKERS,
+ "fitToCoordinates", FIT_TO_COORDINATES
+ );
+
+ map.putAll(MapBuilder.of(
+ "setMapBoundaries", SET_MAP_BOUNDARIES
+ ));
+
+ return map;
+ }
+
+ @Override
+ public LayoutShadowNode createShadowNodeInstance() {
+ // A custom shadow node is needed in order to pass back the width/height of the map to the
+ // view manager so that it can start applying camera moves with bounds.
+ return new SizeReportingShadowNode();
+ }
+
+ @Override
+ public void addView(AirMapView parent, View child, int index) {
+ parent.addFeature(child, index);
+ }
+
+ @Override
+ public int getChildCount(AirMapView view) {
+ return view.getFeatureCount();
+ }
+
+ @Override
+ public View getChildAt(AirMapView view, int index) {
+ return view.getFeatureAt(index);
+ }
+
+ @Override
+ public void removeViewAt(AirMapView parent, int index) {
+ parent.removeFeatureAt(index);
+ }
+
+ @Override
+ public void updateExtraData(AirMapView view, Object extraData) {
+ view.updateExtraData(extraData);
+ }
+
+ void pushEvent(ThemedReactContext context, View view, String name, WritableMap data) {
+ context.getJSModule(RCTEventEmitter.class)
+ .receiveEvent(view.getId(), name, data);
+ }
+
+ @Override
+ public void onDropViewInstance(AirMapView view) {
+ view.doDestroy();
+ super.onDropViewInstance(view);
+ }
+
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarker.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarker.java
new file mode 100644
index 000000000..cb0274bfa
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarker.java
@@ -0,0 +1,434 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.drawable.Animatable;
+import android.net.Uri;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.facebook.common.references.CloseableReference;
+import com.facebook.datasource.DataSource;
+import com.facebook.drawee.backends.pipeline.Fresco;
+import com.facebook.drawee.controller.BaseControllerListener;
+import com.facebook.drawee.controller.ControllerListener;
+import com.facebook.drawee.drawable.ScalingUtils;
+import com.facebook.drawee.generic.GenericDraweeHierarchy;
+import com.facebook.drawee.generic.GenericDraweeHierarchyBuilder;
+import com.facebook.drawee.interfaces.DraweeController;
+import com.facebook.drawee.view.DraweeHolder;
+import com.facebook.imagepipeline.core.ImagePipeline;
+import com.facebook.imagepipeline.image.CloseableImage;
+import com.facebook.imagepipeline.image.CloseableStaticBitmap;
+import com.facebook.imagepipeline.image.ImageInfo;
+import com.facebook.imagepipeline.request.ImageRequest;
+import com.facebook.imagepipeline.request.ImageRequestBuilder;
+import com.facebook.react.bridge.ReadableMap;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.model.BitmapDescriptor;
+import com.google.android.gms.maps.model.BitmapDescriptorFactory;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Marker;
+import com.google.android.gms.maps.model.MarkerOptions;
+
+import javax.annotation.Nullable;
+
+public class AirMapMarker extends AirMapFeature {
+
+ private MarkerOptions markerOptions;
+ private Marker marker;
+ private int width;
+ private int height;
+ private String identifier;
+
+ private LatLng position;
+ private String title;
+ private String snippet;
+
+ private boolean anchorIsSet;
+ private float anchorX;
+ private float anchorY;
+
+ private AirMapCallout calloutView;
+ private View wrappedCalloutView;
+ private final Context context;
+
+ private float markerHue = 0.0f; // should be between 0 and 360
+ private BitmapDescriptor iconBitmapDescriptor;
+ private Bitmap iconBitmap;
+
+ private float rotation = 0.0f;
+ private boolean flat = false;
+ private boolean draggable = false;
+ private int zIndex = 0;
+ private float opacity = 1.0f;
+
+ private float calloutAnchorX;
+ private float calloutAnchorY;
+ private boolean calloutAnchorIsSet;
+
+ private boolean hasCustomMarkerView = false;
+
+ private final DraweeHolder> logoHolder;
+ private DataSource> dataSource;
+ private final ControllerListener mLogoControllerListener =
+ new BaseControllerListener() {
+ @Override
+ public void onFinalImageSet(
+ String id,
+ @Nullable final ImageInfo imageInfo,
+ @Nullable Animatable animatable) {
+ CloseableReference imageReference = null;
+ try {
+ imageReference = dataSource.getResult();
+ if (imageReference != null) {
+ CloseableImage image = imageReference.get();
+ if (image != null && image instanceof CloseableStaticBitmap) {
+ CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image;
+ Bitmap bitmap = closeableStaticBitmap.getUnderlyingBitmap();
+ if (bitmap != null) {
+ bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
+ iconBitmap = bitmap;
+ iconBitmapDescriptor = BitmapDescriptorFactory.fromBitmap(bitmap);
+ }
+ }
+ }
+ } finally {
+ dataSource.close();
+ if (imageReference != null) {
+ CloseableReference.closeSafely(imageReference);
+ }
+ }
+ update();
+ }
+ };
+
+ public AirMapMarker(Context context) {
+ super(context);
+ this.context = context;
+ logoHolder = DraweeHolder.create(createDraweeHierarchy(), context);
+ logoHolder.onAttach();
+ }
+
+ private GenericDraweeHierarchy createDraweeHierarchy() {
+ return new GenericDraweeHierarchyBuilder(getResources())
+ .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
+ .setFadeDuration(0)
+ .build();
+ }
+
+ public void setCoordinate(ReadableMap coordinate) {
+ position = new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude"));
+ if (marker != null) {
+ marker.setPosition(position);
+ }
+ update();
+ }
+
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ update();
+ }
+
+ public String getIdentifier() {
+ return this.identifier;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ if (marker != null) {
+ marker.setTitle(title);
+ }
+ update();
+ }
+
+ public void setSnippet(String snippet) {
+ this.snippet = snippet;
+ if (marker != null) {
+ marker.setSnippet(snippet);
+ }
+ update();
+ }
+
+ public void setRotation(float rotation) {
+ this.rotation = rotation;
+ if (marker != null) {
+ marker.setRotation(rotation);
+ }
+ update();
+ }
+
+ public void setFlat(boolean flat) {
+ this.flat = flat;
+ if (marker != null) {
+ marker.setFlat(flat);
+ }
+ update();
+ }
+
+ public void setDraggable(boolean draggable) {
+ this.draggable = draggable;
+ if (marker != null) {
+ marker.setDraggable(draggable);
+ }
+ update();
+ }
+
+ public void setZIndex(int zIndex) {
+ this.zIndex = zIndex;
+ if (marker != null) {
+ marker.setZIndex(zIndex);
+ }
+ update();
+ }
+
+ public void setOpacity(float opacity) {
+ this.opacity = opacity;
+ if (marker != null) {
+ marker.setAlpha(opacity);
+ }
+ update();
+ }
+
+ public void setMarkerHue(float markerHue) {
+ this.markerHue = markerHue;
+ update();
+ }
+
+ public void setAnchor(double x, double y) {
+ anchorIsSet = true;
+ anchorX = (float) x;
+ anchorY = (float) y;
+ if (marker != null) {
+ marker.setAnchor(anchorX, anchorY);
+ }
+ update();
+ }
+
+ public void setCalloutAnchor(double x, double y) {
+ calloutAnchorIsSet = true;
+ calloutAnchorX = (float) x;
+ calloutAnchorY = (float) y;
+ if (marker != null) {
+ marker.setInfoWindowAnchor(calloutAnchorX, calloutAnchorY);
+ }
+ update();
+ }
+
+ public void setImage(String uri) {
+ if (uri == null) {
+ iconBitmapDescriptor = null;
+ update();
+ } else if (uri.startsWith("http://") || uri.startsWith("https://") ||
+ uri.startsWith("file://")) {
+ ImageRequest imageRequest = ImageRequestBuilder
+ .newBuilderWithSource(Uri.parse(uri))
+ .build();
+
+ ImagePipeline imagePipeline = Fresco.getImagePipeline();
+ dataSource = imagePipeline.fetchDecodedImage(imageRequest, this);
+ DraweeController controller = Fresco.newDraweeControllerBuilder()
+ .setImageRequest(imageRequest)
+ .setControllerListener(mLogoControllerListener)
+ .setOldController(logoHolder.getController())
+ .build();
+ logoHolder.setController(controller);
+ } else {
+ iconBitmapDescriptor = getBitmapDescriptorByName(uri);
+ if (iconBitmapDescriptor != null) {
+ iconBitmap = BitmapFactory.decodeResource(getResources(), getDrawableResourceByName(uri));
+ }
+ update();
+ }
+ }
+
+ public MarkerOptions getMarkerOptions() {
+ if (markerOptions == null) {
+ markerOptions = createMarkerOptions();
+ }
+ return markerOptions;
+ }
+
+ @Override
+ public void addView(View child, int index) {
+ super.addView(child, index);
+ // if children are added, it means we are rendering a custom marker
+ if (!(child instanceof AirMapCallout)) {
+ hasCustomMarkerView = true;
+ }
+ update();
+ }
+
+ @Override
+ public Object getFeature() {
+ return marker;
+ }
+
+ @Override
+ public void addToMap(GoogleMap map) {
+ marker = map.addMarker(getMarkerOptions());
+ }
+
+ @Override
+ public void removeFromMap(GoogleMap map) {
+ marker.remove();
+ marker = null;
+ }
+
+ private BitmapDescriptor getIcon() {
+ if (hasCustomMarkerView) {
+ // creating a bitmap from an arbitrary view
+ if (iconBitmapDescriptor != null) {
+ Bitmap viewBitmap = createDrawable();
+ int width = Math.max(iconBitmap.getWidth(), viewBitmap.getWidth());
+ int height = Math.max(iconBitmap.getHeight(), viewBitmap.getHeight());
+ Bitmap combinedBitmap = Bitmap.createBitmap(width, height, iconBitmap.getConfig());
+ Canvas canvas = new Canvas(combinedBitmap);
+ canvas.drawBitmap(iconBitmap, 0, 0, null);
+ canvas.drawBitmap(viewBitmap, 0, 0, null);
+ return BitmapDescriptorFactory.fromBitmap(combinedBitmap);
+ } else {
+ return BitmapDescriptorFactory.fromBitmap(createDrawable());
+ }
+ } else if (iconBitmapDescriptor != null) {
+ // use local image as a marker
+ return iconBitmapDescriptor;
+ } else {
+ // render the default marker pin
+ return BitmapDescriptorFactory.defaultMarker(this.markerHue);
+ }
+ }
+
+ private MarkerOptions createMarkerOptions() {
+ MarkerOptions options = new MarkerOptions().position(position);
+ if (anchorIsSet) options.anchor(anchorX, anchorY);
+ if (calloutAnchorIsSet) options.infoWindowAnchor(calloutAnchorX, calloutAnchorY);
+ options.title(title);
+ options.snippet(snippet);
+ options.rotation(rotation);
+ options.flat(flat);
+ options.draggable(draggable);
+ options.zIndex(zIndex);
+ options.alpha(opacity);
+ options.icon(getIcon());
+ return options;
+ }
+
+ public void update() {
+ if (marker == null) {
+ return;
+ }
+
+ marker.setIcon(getIcon());
+
+ if (anchorIsSet) {
+ marker.setAnchor(anchorX, anchorY);
+ } else {
+ marker.setAnchor(0.5f, 1.0f);
+ }
+
+ if (calloutAnchorIsSet) {
+ marker.setInfoWindowAnchor(calloutAnchorX, calloutAnchorY);
+ } else {
+ marker.setInfoWindowAnchor(0.5f, 0);
+ }
+ }
+
+ public void update(int width, int height) {
+ this.width = width;
+ this.height = height;
+ update();
+ }
+
+ private Bitmap createDrawable() {
+ int width = this.width <= 0 ? 100 : this.width;
+ int height = this.height <= 0 ? 100 : this.height;
+ this.buildDrawingCache();
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+
+ Canvas canvas = new Canvas(bitmap);
+ this.draw(canvas);
+
+ return bitmap;
+ }
+
+ public void setCalloutView(AirMapCallout view) {
+ this.calloutView = view;
+ }
+
+ public AirMapCallout getCalloutView() {
+ return this.calloutView;
+ }
+
+ public View getCallout() {
+ if (this.calloutView == null) return null;
+
+ if (this.wrappedCalloutView == null) {
+ this.wrapCalloutView();
+ }
+
+ if (this.calloutView.getTooltip()) {
+ return this.wrappedCalloutView;
+ } else {
+ return null;
+ }
+ }
+
+ public View getInfoContents() {
+ if (this.calloutView == null) return null;
+
+ if (this.wrappedCalloutView == null) {
+ this.wrapCalloutView();
+ }
+
+ if (this.calloutView.getTooltip()) {
+ return null;
+ } else {
+ return this.wrappedCalloutView;
+ }
+ }
+
+ private void wrapCalloutView() {
+ // some hackery is needed to get the arbitrary infowindow view to render centered, and
+ // with only the width/height that it needs.
+ if (this.calloutView == null || this.calloutView.getChildCount() == 0) {
+ return;
+ }
+
+ LinearLayout LL = new LinearLayout(context);
+ LL.setOrientation(LinearLayout.VERTICAL);
+ LL.setLayoutParams(new LinearLayout.LayoutParams(
+ this.calloutView.width,
+ this.calloutView.height,
+ 0f
+ ));
+
+
+ LinearLayout LL2 = new LinearLayout(context);
+ LL2.setOrientation(LinearLayout.HORIZONTAL);
+ LL2.setLayoutParams(new LinearLayout.LayoutParams(
+ this.calloutView.width,
+ this.calloutView.height,
+ 0f
+ ));
+
+ LL.addView(LL2);
+ LL2.addView(this.calloutView);
+
+ this.wrappedCalloutView = LL;
+ }
+
+ private int getDrawableResourceByName(String name) {
+ return getResources().getIdentifier(
+ name,
+ "drawable",
+ getContext().getPackageName());
+ }
+
+ private BitmapDescriptor getBitmapDescriptorByName(String name) {
+ return BitmapDescriptorFactory.fromResource(getDrawableResourceByName(name));
+ }
+
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarkerManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarkerManager.java
new file mode 100644
index 000000000..3aef3148c
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarkerManager.java
@@ -0,0 +1,211 @@
+package com.airbnb.android.react.maps;
+
+import android.graphics.Color;
+import android.view.View;
+
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.LayoutShadowNode;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.google.android.gms.maps.model.Marker;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+public class AirMapMarkerManager extends ViewGroupManager {
+
+ private static final int SHOW_INFO_WINDOW = 1;
+ private static final int HIDE_INFO_WINDOW = 2;
+
+ public AirMapMarkerManager() {
+ }
+
+ @Override
+ public String getName() {
+ return "AIRMapMarker";
+ }
+
+ @Override
+ public AirMapMarker createViewInstance(ThemedReactContext context) {
+ return new AirMapMarker(context);
+ }
+
+ @ReactProp(name = "coordinate")
+ public void setCoordinate(AirMapMarker view, ReadableMap map) {
+ view.setCoordinate(map);
+ }
+
+ @ReactProp(name = "title")
+ public void setTitle(AirMapMarker view, String title) {
+ view.setTitle(title);
+ }
+
+ @ReactProp(name = "identifier")
+ public void setIdentifier(AirMapMarker view, String identifier) {
+ view.setIdentifier(identifier);
+ }
+
+ @ReactProp(name = "description")
+ public void setDescription(AirMapMarker view, String description) {
+ view.setSnippet(description);
+ }
+
+ // NOTE(lmr):
+ // android uses normalized coordinate systems for this, and is provided through the
+ // `anchor` property and `calloutAnchor` instead. Perhaps some work could be done
+ // to normalize iOS and android to use just one of the systems.
+// @ReactProp(name = "centerOffset")
+// public void setCenterOffset(AirMapMarker view, ReadableMap map) {
+//
+// }
+//
+// @ReactProp(name = "calloutOffset")
+// public void setCalloutOffset(AirMapMarker view, ReadableMap map) {
+//
+// }
+
+ @ReactProp(name = "anchor")
+ public void setAnchor(AirMapMarker view, ReadableMap map) {
+ // should default to (0.5, 1) (bottom middle)
+ double x = map != null && map.hasKey("x") ? map.getDouble("x") : 0.5;
+ double y = map != null && map.hasKey("y") ? map.getDouble("y") : 1.0;
+ view.setAnchor(x, y);
+ }
+
+ @ReactProp(name = "calloutAnchor")
+ public void setCalloutAnchor(AirMapMarker view, ReadableMap map) {
+ // should default to (0.5, 0) (top middle)
+ double x = map != null && map.hasKey("x") ? map.getDouble("x") : 0.5;
+ double y = map != null && map.hasKey("y") ? map.getDouble("y") : 0.0;
+ view.setCalloutAnchor(x, y);
+ }
+
+ @ReactProp(name = "image")
+ public void setImage(AirMapMarker view, @Nullable String source) {
+ view.setImage(source);
+ }
+// public void setImage(AirMapMarker view, ReadableMap image) {
+// view.setImage(image);
+// }
+
+ @ReactProp(name = "pinColor", defaultInt = Color.RED, customType = "Color")
+ public void setPinColor(AirMapMarker view, int pinColor) {
+ float[] hsv = new float[3];
+ Color.colorToHSV(pinColor, hsv);
+ // NOTE: android only supports a hue
+ view.setMarkerHue(hsv[0]);
+ }
+
+ @ReactProp(name = "rotation", defaultFloat = 0.0f)
+ public void setMarkerRotation(AirMapMarker view, float rotation) {
+ view.setRotation(rotation);
+ }
+
+ @ReactProp(name = "flat", defaultBoolean = false)
+ public void setFlat(AirMapMarker view, boolean flat) {
+ view.setFlat(flat);
+ }
+
+ @ReactProp(name = "draggable", defaultBoolean = false)
+ public void setDraggable(AirMapMarker view, boolean draggable) {
+ view.setDraggable(draggable);
+ }
+
+ @Override
+ @ReactProp(name = "zIndex", defaultFloat = 0.0f)
+ public void setZIndex(AirMapMarker view, float zIndex) {
+ super.setZIndex(view, zIndex);
+ int integerZIndex = Math.round(zIndex);
+ view.setZIndex(integerZIndex);
+ }
+
+ @Override
+ @ReactProp(name = "opacity", defaultFloat = 1.0f)
+ public void setOpacity(AirMapMarker view, float opacity) {
+ super.setOpacity(view, opacity);
+ view.setOpacity(opacity);
+ }
+
+ @Override
+ public void addView(AirMapMarker parent, View child, int index) {
+ // if an component is a child, then it is a callout view, NOT part of the
+ // marker.
+ if (child instanceof AirMapCallout) {
+ parent.setCalloutView((AirMapCallout) child);
+ } else {
+ super.addView(parent, child, index);
+ parent.update();
+ }
+ }
+
+ @Override
+ public void removeViewAt(AirMapMarker parent, int index) {
+ super.removeViewAt(parent, index);
+ parent.update();
+ }
+
+ @Override
+ @Nullable
+ public Map getCommandsMap() {
+ return MapBuilder.of(
+ "showCallout", SHOW_INFO_WINDOW,
+ "hideCallout", HIDE_INFO_WINDOW
+ );
+ }
+
+ @Override
+ public void receiveCommand(AirMapMarker view, int commandId, @Nullable ReadableArray args) {
+ switch (commandId) {
+ case SHOW_INFO_WINDOW:
+ ((Marker) view.getFeature()).showInfoWindow();
+ break;
+
+ case HIDE_INFO_WINDOW:
+ ((Marker) view.getFeature()).hideInfoWindow();
+ break;
+ }
+ }
+
+ @Override
+ @Nullable
+ public Map getExportedCustomDirectEventTypeConstants() {
+ Map> map = MapBuilder.of(
+ "onPress", MapBuilder.of("registrationName", "onPress"),
+ "onCalloutPress", MapBuilder.of("registrationName", "onCalloutPress"),
+ "onDragStart", MapBuilder.of("registrationName", "onDragStart"),
+ "onDrag", MapBuilder.of("registrationName", "onDrag"),
+ "onDragEnd", MapBuilder.of("registrationName", "onDragEnd")
+ );
+
+ map.putAll(MapBuilder.of(
+ "onDragStart", MapBuilder.of("registrationName", "onDragStart"),
+ "onDrag", MapBuilder.of("registrationName", "onDrag"),
+ "onDragEnd", MapBuilder.of("registrationName", "onDragEnd")
+ ));
+
+ return map;
+ }
+
+ @Override
+ public LayoutShadowNode createShadowNodeInstance() {
+ // we use a custom shadow node that emits the width/height of the view
+ // after layout with the updateExtraData method. Without this, we can't generate
+ // a bitmap of the appropriate width/height of the rendered view.
+ return new SizeReportingShadowNode();
+ }
+
+ @Override
+ public void updateExtraData(AirMapMarker view, Object extraData) {
+ // This method is called from the shadow node with the width/height of the rendered
+ // marker view.
+ HashMap data = (HashMap) extraData;
+ float width = data.get("width");
+ float height = data.get("height");
+ view.update((int) width, (int) height);
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapModule.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapModule.java
new file mode 100644
index 000000000..dfc71d6d9
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapModule.java
@@ -0,0 +1,138 @@
+package com.airbnb.android.react.maps;
+
+import android.app.Activity;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.util.Base64;
+import android.util.DisplayMetrics;
+
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.uimanager.NativeViewHierarchyManager;
+import com.facebook.react.uimanager.UIBlock;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.common.GoogleApiAvailability;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import java.util.Map;
+import java.util.HashMap;
+
+import javax.annotation.Nullable;
+
+public class AirMapModule extends ReactContextBaseJavaModule {
+
+ private static final String SNAPSHOT_RESULT_FILE = "file";
+ private static final String SNAPSHOT_RESULT_BASE64 = "base64";
+ private static final String SNAPSHOT_FORMAT_PNG = "png";
+ private static final String SNAPSHOT_FORMAT_JPG = "jpg";
+
+ public AirMapModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ }
+
+ @Override
+ public String getName() {
+ return "AirMapModule";
+ }
+
+ @Override
+ public Map getConstants() {
+ final Map constants = new HashMap<>();
+ constants.put("legalNotice", "This license information is displayed in Settings > Google > Open Source on any device running Google Play services.");
+ return constants;
+ }
+
+ public Activity getActivity() {
+ return getCurrentActivity();
+ }
+
+ public static void closeQuietly(Closeable closeable) {
+ if (closeable == null) return;
+ try {
+ closeable.close();
+ } catch (IOException ignored) {
+ }
+ }
+
+ @ReactMethod
+ public void takeSnapshot(final int tag, final ReadableMap options, final Promise promise) {
+
+ // Parse and verity options
+ final ReactApplicationContext context = getReactApplicationContext();
+ final String format = options.hasKey("format") ? options.getString("format") : "png";
+ final Bitmap.CompressFormat compressFormat =
+ format.equals(SNAPSHOT_FORMAT_PNG) ? Bitmap.CompressFormat.PNG :
+ format.equals(SNAPSHOT_FORMAT_JPG) ? Bitmap.CompressFormat.JPEG : null;
+ final double quality = options.hasKey("quality") ? options.getDouble("quality") : 1.0;
+ final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ final Integer width =
+ options.hasKey("width") ? (int) (displayMetrics.density * options.getDouble("width")) : 0;
+ final Integer height =
+ options.hasKey("height") ? (int) (displayMetrics.density * options.getDouble("height")) : 0;
+ final String result = options.hasKey("result") ? options.getString("result") : "file";
+
+ // Add UI-block so we can get a valid reference to the map-view
+ UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
+ uiManager.addUIBlock(new UIBlock() {
+ public void execute(NativeViewHierarchyManager nvhm) {
+ AirMapView view = (AirMapView) nvhm.resolveView(tag);
+ if (view == null) {
+ promise.reject("AirMapView not found");
+ return;
+ }
+ if (view.map == null) {
+ promise.reject("AirMapView.map is not valid");
+ return;
+ }
+ view.map.snapshot(new GoogleMap.SnapshotReadyCallback() {
+ public void onSnapshotReady(@Nullable Bitmap snapshot) {
+
+ // Convert image to requested width/height if necessary
+ if (snapshot == null) {
+ promise.reject("Failed to generate bitmap, snapshot = null");
+ return;
+ }
+ if ((width != 0) && (height != 0) &&
+ (width != snapshot.getWidth() || height != snapshot.getHeight())) {
+ snapshot = Bitmap.createScaledBitmap(snapshot, width, height, true);
+ }
+
+ // Save the snapshot to disk
+ if (result.equals(SNAPSHOT_RESULT_FILE)) {
+ File tempFile;
+ FileOutputStream outputStream;
+ try {
+ tempFile =
+ File.createTempFile("AirMapSnapshot", "." + format, context.getCacheDir());
+ outputStream = new FileOutputStream(tempFile);
+ } catch (Exception e) {
+ promise.reject(e);
+ return;
+ }
+ snapshot.compress(compressFormat, (int) (100.0 * quality), outputStream);
+ closeQuietly(outputStream);
+ String uri = Uri.fromFile(tempFile).toString();
+ promise.resolve(uri);
+ } else if (result.equals(SNAPSHOT_RESULT_BASE64)) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ snapshot.compress(compressFormat, (int) (100.0 * quality), outputStream);
+ closeQuietly(outputStream);
+ byte[] bytes = outputStream.toByteArray();
+ String data = Base64.encodeToString(bytes, Base64.NO_WRAP);
+ promise.resolve(data);
+ }
+ }
+ });
+ }
+ });
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygon.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygon.java
new file mode 100644
index 000000000..41257b32e
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygon.java
@@ -0,0 +1,112 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Polygon;
+import com.google.android.gms.maps.model.PolygonOptions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AirMapPolygon extends AirMapFeature {
+
+ private PolygonOptions polygonOptions;
+ private Polygon polygon;
+
+ private List coordinates;
+ private int strokeColor;
+ private int fillColor;
+ private float strokeWidth;
+ private boolean geodesic;
+ private float zIndex;
+
+ public AirMapPolygon(Context context) {
+ super(context);
+ }
+
+ public void setCoordinates(ReadableArray coordinates) {
+ // it's kind of a bummer that we can't run map() or anything on the ReadableArray
+ this.coordinates = new ArrayList<>(coordinates.size());
+ for (int i = 0; i < coordinates.size(); i++) {
+ ReadableMap coordinate = coordinates.getMap(i);
+ this.coordinates.add(i,
+ new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude")));
+ }
+ if (polygon != null) {
+ polygon.setPoints(this.coordinates);
+ }
+ }
+
+ public void setFillColor(int color) {
+ this.fillColor = color;
+ if (polygon != null) {
+ polygon.setFillColor(color);
+ }
+ }
+
+ public void setStrokeColor(int color) {
+ this.strokeColor = color;
+ if (polygon != null) {
+ polygon.setStrokeColor(color);
+ }
+ }
+
+ public void setStrokeWidth(float width) {
+ this.strokeWidth = width;
+ if (polygon != null) {
+ polygon.setStrokeWidth(width);
+ }
+ }
+
+ public void setGeodesic(boolean geodesic) {
+ this.geodesic = geodesic;
+ if (polygon != null) {
+ polygon.setGeodesic(geodesic);
+ }
+ }
+
+ public void setZIndex(float zIndex) {
+ this.zIndex = zIndex;
+ if (polygon != null) {
+ polygon.setZIndex(zIndex);
+ }
+ }
+
+ public PolygonOptions getPolygonOptions() {
+ if (polygonOptions == null) {
+ polygonOptions = createPolygonOptions();
+ }
+ return polygonOptions;
+ }
+
+ private PolygonOptions createPolygonOptions() {
+ PolygonOptions options = new PolygonOptions();
+ options.addAll(coordinates);
+ options.fillColor(fillColor);
+ options.strokeColor(strokeColor);
+ options.strokeWidth(strokeWidth);
+ options.geodesic(geodesic);
+ options.zIndex(zIndex);
+ return options;
+ }
+
+ @Override
+ public Object getFeature() {
+ return polygon;
+ }
+
+ @Override
+ public void addToMap(GoogleMap map) {
+ polygon = map.addPolygon(getPolygonOptions());
+ polygon.setClickable(true);
+ }
+
+ @Override
+ public void removeFromMap(GoogleMap map) {
+ polygon.remove();
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygonManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygonManager.java
new file mode 100644
index 000000000..6f1605758
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygonManager.java
@@ -0,0 +1,83 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.uimanager.annotations.ReactProp;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+public class AirMapPolygonManager extends ViewGroupManager {
+ private final DisplayMetrics metrics;
+
+ public AirMapPolygonManager(ReactApplicationContext reactContext) {
+ super();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ metrics = new DisplayMetrics();
+ ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay()
+ .getRealMetrics(metrics);
+ } else {
+ metrics = reactContext.getResources().getDisplayMetrics();
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "AIRMapPolygon";
+ }
+
+ @Override
+ public AirMapPolygon createViewInstance(ThemedReactContext context) {
+ return new AirMapPolygon(context);
+ }
+
+ @ReactProp(name = "coordinates")
+ public void setCoordinate(AirMapPolygon view, ReadableArray coordinates) {
+ view.setCoordinates(coordinates);
+ }
+
+ @ReactProp(name = "strokeWidth", defaultFloat = 1f)
+ public void setStrokeWidth(AirMapPolygon view, float widthInPoints) {
+ float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
+ view.setStrokeWidth(widthInScreenPx);
+ }
+
+ @ReactProp(name = "fillColor", defaultInt = Color.RED, customType = "Color")
+ public void setFillColor(AirMapPolygon view, int color) {
+ view.setFillColor(color);
+ }
+
+ @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
+ public void setStrokeColor(AirMapPolygon view, int color) {
+ view.setStrokeColor(color);
+ }
+
+ @ReactProp(name = "geodesic", defaultBoolean = false)
+ public void setGeodesic(AirMapPolygon view, boolean geodesic) {
+ view.setGeodesic(geodesic);
+ }
+
+ @ReactProp(name = "zIndex", defaultFloat = 1.0f)
+ public void setZIndex(AirMapPolygon view, float zIndex) {
+ view.setZIndex(zIndex);
+ }
+
+ @Override
+ @Nullable
+ public Map getExportedCustomDirectEventTypeConstants() {
+ return MapBuilder.of(
+ "onPress", MapBuilder.of("registrationName", "onPress")
+ );
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolyline.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolyline.java
new file mode 100644
index 000000000..488e2972f
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolyline.java
@@ -0,0 +1,102 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.Polyline;
+import com.google.android.gms.maps.model.PolylineOptions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AirMapPolyline extends AirMapFeature {
+
+ private PolylineOptions polylineOptions;
+ private Polyline polyline;
+
+ private List coordinates;
+ private int color;
+ private float width;
+ private boolean geodesic;
+ private float zIndex;
+
+ public AirMapPolyline(Context context) {
+ super(context);
+ }
+
+ public void setCoordinates(ReadableArray coordinates) {
+ this.coordinates = new ArrayList<>(coordinates.size());
+ for (int i = 0; i < coordinates.size(); i++) {
+ ReadableMap coordinate = coordinates.getMap(i);
+ this.coordinates.add(i,
+ new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude")));
+ }
+ if (polyline != null) {
+ polyline.setPoints(this.coordinates);
+ }
+ }
+
+ public void setColor(int color) {
+ this.color = color;
+ if (polyline != null) {
+ polyline.setColor(color);
+ }
+ }
+
+ public void setWidth(float width) {
+ this.width = width;
+ if (polyline != null) {
+ polyline.setWidth(width);
+ }
+ }
+
+ public void setZIndex(float zIndex) {
+ this.zIndex = zIndex;
+ if (polyline != null) {
+ polyline.setZIndex(zIndex);
+ }
+ }
+
+ public void setGeodesic(boolean geodesic) {
+ this.geodesic = geodesic;
+ if (polyline != null) {
+ polyline.setGeodesic(geodesic);
+ }
+ }
+
+ public PolylineOptions getPolylineOptions() {
+ if (polylineOptions == null) {
+ polylineOptions = createPolylineOptions();
+ }
+ return polylineOptions;
+ }
+
+ private PolylineOptions createPolylineOptions() {
+ PolylineOptions options = new PolylineOptions();
+ options.addAll(coordinates);
+ options.color(color);
+ options.width(width);
+ options.geodesic(geodesic);
+ options.zIndex(zIndex);
+ return options;
+ }
+
+ @Override
+ public Object getFeature() {
+ return polyline;
+ }
+
+ @Override
+ public void addToMap(GoogleMap map) {
+ polyline = map.addPolyline(getPolylineOptions());
+ polyline.setClickable(true);
+ }
+
+ @Override
+ public void removeFromMap(GoogleMap map) {
+ polyline.remove();
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolylineManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolylineManager.java
new file mode 100644
index 000000000..be80acfbc
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolylineManager.java
@@ -0,0 +1,78 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.uimanager.annotations.ReactProp;
+
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+public class AirMapPolylineManager extends ViewGroupManager {
+ private final DisplayMetrics metrics;
+
+ public AirMapPolylineManager(ReactApplicationContext reactContext) {
+ super();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ metrics = new DisplayMetrics();
+ ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay()
+ .getRealMetrics(metrics);
+ } else {
+ metrics = reactContext.getResources().getDisplayMetrics();
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "AIRMapPolyline";
+ }
+
+ @Override
+ public AirMapPolyline createViewInstance(ThemedReactContext context) {
+ return new AirMapPolyline(context);
+ }
+
+ @ReactProp(name = "coordinates")
+ public void setCoordinate(AirMapPolyline view, ReadableArray coordinates) {
+ view.setCoordinates(coordinates);
+ }
+
+ @ReactProp(name = "strokeWidth", defaultFloat = 1f)
+ public void setStrokeWidth(AirMapPolyline view, float widthInPoints) {
+ float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
+ view.setWidth(widthInScreenPx);
+ }
+
+ @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
+ public void setStrokeColor(AirMapPolyline view, int color) {
+ view.setColor(color);
+ }
+
+ @ReactProp(name = "geodesic", defaultBoolean = false)
+ public void setGeodesic(AirMapPolyline view, boolean geodesic) {
+ view.setGeodesic(geodesic);
+ }
+
+ @ReactProp(name = "zIndex", defaultFloat = 1.0f)
+ public void setZIndex(AirMapPolyline view, float zIndex) {
+ view.setZIndex(zIndex);
+ }
+
+ @Override
+ @Nullable
+ public Map getExportedCustomDirectEventTypeConstants() {
+ return MapBuilder.of(
+ "onPress", MapBuilder.of("registrationName", "onPress")
+ );
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTile.java
new file mode 100644
index 000000000..ae51a63b4
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTile.java
@@ -0,0 +1,101 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.model.TileOverlay;
+import com.google.android.gms.maps.model.TileOverlayOptions;
+import com.google.android.gms.maps.model.UrlTileProvider;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class AirMapUrlTile extends AirMapFeature {
+
+ class AIRMapUrlTileProvider extends UrlTileProvider {
+ private String urlTemplate;
+
+ public AIRMapUrlTileProvider(int width, int height, String urlTemplate) {
+ super(width, height);
+ this.urlTemplate = urlTemplate;
+ }
+
+ @Override
+ public synchronized URL getTileUrl(int x, int y, int zoom) {
+
+ String s = this.urlTemplate
+ .replace("{x}", Integer.toString(x))
+ .replace("{y}", Integer.toString(y))
+ .replace("{z}", Integer.toString(zoom));
+ URL url = null;
+ try {
+ url = new URL(s);
+ } catch (MalformedURLException e) {
+ throw new AssertionError(e);
+ }
+ return url;
+ }
+
+ public void setUrlTemplate(String urlTemplate) {
+ this.urlTemplate = urlTemplate;
+ }
+ }
+
+ private TileOverlayOptions tileOverlayOptions;
+ private TileOverlay tileOverlay;
+ private AIRMapUrlTileProvider tileProvider;
+
+ private String urlTemplate;
+ private float zIndex;
+
+ public AirMapUrlTile(Context context) {
+ super(context);
+ }
+
+ public void setUrlTemplate(String urlTemplate) {
+ this.urlTemplate = urlTemplate;
+ if (tileProvider != null) {
+ tileProvider.setUrlTemplate(urlTemplate);
+ }
+ if (tileOverlay != null) {
+ tileOverlay.clearTileCache();
+ }
+ }
+
+ public void setZIndex(float zIndex) {
+ this.zIndex = zIndex;
+ if (tileOverlay != null) {
+ tileOverlay.setZIndex(zIndex);
+ }
+ }
+
+ public TileOverlayOptions getTileOverlayOptions() {
+ if (tileOverlayOptions == null) {
+ tileOverlayOptions = createTileOverlayOptions();
+ }
+ return tileOverlayOptions;
+ }
+
+ private TileOverlayOptions createTileOverlayOptions() {
+ TileOverlayOptions options = new TileOverlayOptions();
+ options.zIndex(zIndex);
+ this.tileProvider = new AIRMapUrlTileProvider(256, 256, this.urlTemplate);
+ options.tileProvider(this.tileProvider);
+ return options;
+ }
+
+ @Override
+ public Object getFeature() {
+ return tileOverlay;
+ }
+
+ @Override
+ public void addToMap(GoogleMap map) {
+ this.tileOverlay = map.addTileOverlay(getTileOverlayOptions());
+ }
+
+ @Override
+ public void removeFromMap(GoogleMap map) {
+ tileOverlay.remove();
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTileManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTileManager.java
new file mode 100644
index 000000000..68bf07342
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTileManager.java
@@ -0,0 +1,48 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewGroupManager;
+import com.facebook.react.uimanager.annotations.ReactProp;
+
+public class AirMapUrlTileManager extends ViewGroupManager {
+ private DisplayMetrics metrics;
+
+ public AirMapUrlTileManager(ReactApplicationContext reactContext) {
+ super();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ metrics = new DisplayMetrics();
+ ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay()
+ .getRealMetrics(metrics);
+ } else {
+ metrics = reactContext.getResources().getDisplayMetrics();
+ }
+ }
+
+ @Override
+ public String getName() {
+ return "AIRMapUrlTile";
+ }
+
+ @Override
+ public AirMapUrlTile createViewInstance(ThemedReactContext context) {
+ return new AirMapUrlTile(context);
+ }
+
+ @ReactProp(name = "urlTemplate")
+ public void setUrlTemplate(AirMapUrlTile view, String urlTemplate) {
+ view.setUrlTemplate(urlTemplate);
+ }
+
+ @ReactProp(name = "zIndex", defaultFloat = -1.0f)
+ public void setZIndex(AirMapUrlTile view, float zIndex) {
+ view.setZIndex(zIndex);
+ }
+
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java
new file mode 100644
index 000000000..9858b7d80
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java
@@ -0,0 +1,895 @@
+package com.airbnb.android.react.maps;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.os.Build;
+import android.os.Handler;
+import android.support.v4.view.GestureDetectorCompat;
+import android.support.v4.view.MotionEventCompat;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+import android.util.Log;
+
+import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableArray;
+import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.bridge.WritableNativeArray;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.UIManagerModule;
+import com.facebook.react.uimanager.events.EventDispatcher;
+import com.google.android.gms.maps.CameraUpdate;
+import com.google.android.gms.maps.CameraUpdateFactory;
+import com.google.android.gms.maps.GoogleMap;
+import com.google.android.gms.maps.GoogleMapOptions;
+import com.google.android.gms.maps.MapView;
+import com.google.android.gms.maps.OnMapReadyCallback;
+import com.google.android.gms.maps.Projection;
+import com.google.android.gms.maps.model.CameraPosition;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
+import com.google.android.gms.maps.model.Marker;
+import com.google.android.gms.maps.model.Polygon;
+import com.google.android.gms.maps.model.Polyline;
+import com.google.android.gms.maps.model.VisibleRegion;
+
+import com.google.maps.android.geojson.GeoJsonFeature;
+import com.google.maps.android.geojson.GeoJsonLayer;
+import com.google.maps.android.geojson.GeoJsonGeometry;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static android.support.v4.content.PermissionChecker.checkSelfPermission;
+
+public class AirMapView extends MapView implements GoogleMap.InfoWindowAdapter,
+ GoogleMap.OnMarkerDragListener, OnMapReadyCallback {
+ public GoogleMap map;
+ private ProgressBar mapLoadingProgressBar;
+ private RelativeLayout mapLoadingLayout;
+ private ImageView cacheImageView;
+ private Boolean isMapLoaded = false;
+ private Integer loadingBackgroundColor = null;
+ private Integer loadingIndicatorColor = null;
+ private final int baseMapPadding = 50;
+
+ private LatLngBounds boundsToMove;
+ private boolean showUserLocation = false;
+ private boolean handlePanDrag = false;
+ private boolean moveOnMarkerPress = true;
+ private boolean cacheEnabled = false;
+ private boolean initialRegionSet = false;
+ private LatLngBounds cameraLastIdleBounds;
+ private int cameraMoveReason = 0;
+
+ private static final String[] PERMISSIONS = new String[]{
+ "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION"};
+
+ private final List features = new ArrayList<>();
+ private final Map markerMap = new HashMap<>();
+ private final Map polylineMap = new HashMap<>();
+ private final Map polygonMap = new HashMap<>();
+ private final GestureDetectorCompat gestureDetector;
+ private final AirMapManager manager;
+ private LifecycleEventListener lifecycleListener;
+ private boolean paused = false;
+ private boolean destroyed = false;
+ private final ThemedReactContext context;
+ private final EventDispatcher eventDispatcher;
+
+ private static boolean contextHasBug(Context context) {
+ return context == null ||
+ context.getResources() == null ||
+ context.getResources().getConfiguration() == null;
+ }
+
+ // We do this to fix this bug:
+ // https://github.com/airbnb/react-native-maps/issues/271
+ //
+ // which conflicts with another bug regarding the passed in context:
+ // https://github.com/airbnb/react-native-maps/issues/1147
+ //
+ // Doing this allows us to avoid both bugs.
+ private static Context getNonBuggyContext(ThemedReactContext reactContext,
+ ReactApplicationContext appContext) {
+ Context superContext = reactContext;
+ if (!contextHasBug(appContext.getCurrentActivity())) {
+ superContext = appContext.getCurrentActivity();
+ } else if (contextHasBug(superContext)) {
+ // we have the bug! let's try to find a better context to use
+ if (!contextHasBug(reactContext.getCurrentActivity())) {
+ superContext = reactContext.getCurrentActivity();
+ } else if (!contextHasBug(reactContext.getApplicationContext())) {
+ superContext = reactContext.getApplicationContext();
+ } else {
+ // ¯\_(ツ)_/¯
+ }
+ }
+ return superContext;
+ }
+
+ public AirMapView(ThemedReactContext reactContext, ReactApplicationContext appContext,
+ AirMapManager manager,
+ GoogleMapOptions googleMapOptions) {
+ super(getNonBuggyContext(reactContext, appContext), googleMapOptions);
+
+ this.manager = manager;
+ this.context = reactContext;
+
+ super.onCreate(null);
+ // TODO(lmr): what about onStart????
+ super.onResume();
+ super.getMapAsync(this);
+
+ final AirMapView view = this;
+
+ gestureDetector =
+ new GestureDetectorCompat(reactContext, new GestureDetector.SimpleOnGestureListener() {
+
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
+ float distanceY) {
+ if (handlePanDrag) {
+ onPanDrag(e2);
+ }
+ return false;
+ }
+ });
+
+ this.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ @Override public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ if (!paused) {
+ AirMapView.this.cacheView();
+ }
+ }
+ });
+
+ eventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
+ }
+
+ @Override
+ public void onMapReady(final GoogleMap map) {
+ if (destroyed) {
+ return;
+ }
+ this.map = map;
+ this.map.setInfoWindowAdapter(this);
+ this.map.setOnMarkerDragListener(this);
+
+ manager.pushEvent(context, this, "onMapReady", new WritableNativeMap());
+
+ final AirMapView view = this;
+
+ map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
+ @Override
+ public boolean onMarkerClick(Marker marker) {
+ WritableMap event;
+ AirMapMarker airMapMarker = markerMap.get(marker);
+
+ event = makeClickEventData(marker.getPosition());
+ event.putString("action", "marker-press");
+ event.putString("id", airMapMarker.getIdentifier());
+ manager.pushEvent(context, view, "onMarkerPress", event);
+
+ // Return false to open the callout info window and center on the marker
+ // https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap
+ // .OnMarkerClickListener
+ if (view.moveOnMarkerPress) {
+ return false;
+ } else {
+ marker.showInfoWindow();
+ return true;
+ }
+ }
+ });
+
+ map.setOnPolygonClickListener(new GoogleMap.OnPolygonClickListener() {
+ @Override
+ public void onPolygonClick (Polygon polygon) {
+ WritableMap event = makePolygonClickEventData(polygon);
+ event.putString("action", "press");
+ manager.pushEvent(context, view, "onPress", event);
+ }
+ });
+
+ map.setOnPolylineClickListener(new GoogleMap.OnPolylineClickListener(){
+ @Override
+ public void onPolylineClick(Polyline polyline) {
+ WritableMap event = makeLineClickEventData(polyline);
+ event.putString("action", "press");
+ manager.pushEvent(context, view, "onPress", event);
+ }
+ });
+
+ map.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
+ @Override
+ public void onInfoWindowClick(Marker marker) {
+ WritableMap event;
+
+ event = makeClickEventData(marker.getPosition());
+ event.putString("action", "callout-press");
+ manager.pushEvent(context, view, "onCalloutPress", event);
+
+ event = makeClickEventData(marker.getPosition());
+ event.putString("action", "callout-press");
+ AirMapMarker markerView = markerMap.get(marker);
+ manager.pushEvent(context, markerView, "onCalloutPress", event);
+
+ event = makeClickEventData(marker.getPosition());
+ event.putString("action", "callout-press");
+ AirMapCallout infoWindow = markerView.getCalloutView();
+ if (infoWindow != null) manager.pushEvent(context, infoWindow, "onPress", event);
+ }
+ });
+
+ map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
+ @Override
+ public void onMapClick(LatLng point) {
+ WritableMap event = makeClickEventData(point);
+ event.putString("action", "press");
+ manager.pushEvent(context, view, "onPress", event);
+ }
+ });
+
+ map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
+ @Override
+ public void onMapLongClick(LatLng point) {
+ WritableMap event = makeClickEventData(point);
+ event.putString("action", "long-press");
+ manager.pushEvent(context, view, "onLongPress", makeClickEventData(point));
+ }
+ });
+
+ map.setOnCameraMoveStartedListener(new GoogleMap.OnCameraMoveStartedListener() {
+ @Override
+ public void onCameraMoveStarted(int reason) {
+ cameraMoveReason = reason;
+ }
+ });
+
+ map.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
+ @Override
+ public void onCameraMove() {
+ LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds;
+ cameraLastIdleBounds = null;
+ eventDispatcher.dispatchEvent(new RegionChangeEvent(getId(), bounds, true));
+ }
+ });
+
+ map.setOnCameraIdleListener(new GoogleMap.OnCameraIdleListener() {
+ @Override
+ public void onCameraIdle() {
+ LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds;
+ if ((cameraMoveReason != 0) &&
+ ((cameraLastIdleBounds == null) ||
+ LatLngBoundsUtils.BoundsAreDifferent(bounds, cameraLastIdleBounds))) {
+ cameraLastIdleBounds = bounds;
+ eventDispatcher.dispatchEvent(new RegionChangeEvent(getId(), bounds, false));
+ }
+ }
+ });
+
+ map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
+ @Override public void onMapLoaded() {
+ isMapLoaded = true;
+ AirMapView.this.cacheView();
+ }
+ });
+
+ // We need to be sure to disable location-tracking when app enters background, in-case some
+ // other module
+ // has acquired a wake-lock and is controlling location-updates, otherwise, location-manager
+ // will be left
+ // updating location constantly, killing the battery, even though some other location-mgmt
+ // module may
+ // desire to shut-down location-services.
+ lifecycleListener = new LifecycleEventListener() {
+ @Override
+ public void onHostResume() {
+ if (hasPermissions()) {
+ //noinspection MissingPermission
+ map.setMyLocationEnabled(showUserLocation);
+ }
+ synchronized (AirMapView.this) {
+ if (!destroyed) {
+ AirMapView.this.onResume();
+ }
+ paused = false;
+ }
+ }
+
+ @Override
+ public void onHostPause() {
+ if (hasPermissions()) {
+ //noinspection MissingPermission
+ map.setMyLocationEnabled(false);
+ }
+ synchronized (AirMapView.this) {
+ if (!destroyed) {
+ AirMapView.this.onPause();
+ }
+ paused = true;
+ }
+ }
+
+ @Override
+ public void onHostDestroy() {
+ AirMapView.this.doDestroy();
+ }
+ };
+
+ context.addLifecycleEventListener(lifecycleListener);
+ }
+
+ private boolean hasPermissions() {
+ return checkSelfPermission(getContext(), PERMISSIONS[0]) == PackageManager.PERMISSION_GRANTED ||
+ checkSelfPermission(getContext(), PERMISSIONS[1]) == PackageManager.PERMISSION_GRANTED;
+ }
+
+
+ public WritableMap makePolygonClickEventData(Polygon feature){
+ WritableMap event = new WritableNativeMap();
+ WritableArray points = new WritableNativeArray();
+ List pointList = feature.getPoints();
+ for(LatLng point : pointList){
+ WritableMap position = new WritableNativeMap();
+ position.putDouble("latitude", point.latitude);
+ position.putDouble("longitude", point.longitude);
+ points.pushMap(position);
+ }
+ event.putArray("polygon", points);
+ //event.putMap("feature", feature);
+
+ return event;
+ }
+
+ public WritableMap makeLineClickEventData(Polyline feature){
+ WritableMap event = new WritableNativeMap();
+ WritableArray points = new WritableNativeArray();
+ List pointList = feature.getPoints();
+ for(LatLng point : pointList){
+ WritableMap position = new WritableNativeMap();
+ position.putDouble("latitude", point.latitude);
+ position.putDouble("longitude", point.longitude);
+ points.pushMap(position);
+ }
+ event.putArray("line", points);
+ //event.putMap("feature", feature);
+
+ return event;
+ }
+
+ /*
+ onDestroy is final method so I can't override it.
+ */
+ public synchronized void doDestroy() {
+ if (destroyed) {
+ return;
+ }
+ destroyed = true;
+
+ if (lifecycleListener != null && context != null) {
+ context.removeLifecycleEventListener(lifecycleListener);
+ lifecycleListener = null;
+ }
+ if (!paused) {
+ onPause();
+ paused = true;
+ }
+ onDestroy();
+ }
+
+ public void setInitialRegion(ReadableMap initialRegion) {
+ if (!initialRegionSet && initialRegion != null) {
+ setRegion(initialRegion);
+ initialRegionSet = true;
+ }
+ }
+
+ public void setRegion(ReadableMap region) {
+ if (region == null) return;
+
+ Double lng = region.getDouble("longitude");
+ Double lat = region.getDouble("latitude");
+ Double lngDelta = region.getDouble("longitudeDelta");
+ Double latDelta = region.getDouble("latitudeDelta");
+ LatLngBounds bounds = new LatLngBounds(
+ new LatLng(lat - latDelta / 2, lng - lngDelta / 2), // southwest
+ new LatLng(lat + latDelta / 2, lng + lngDelta / 2) // northeast
+ );
+ if (super.getHeight() <= 0 || super.getWidth() <= 0) {
+ // in this case, our map has not been laid out yet, so we save the bounds in a local
+ // variable, and make a guess of zoomLevel 10. Not to worry, though: as soon as layout
+ // occurs, we will move the camera to the saved bounds. Note that if we tried to move
+ // to the bounds now, it would trigger an exception.
+ map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lng), 10));
+ boundsToMove = bounds;
+ } else {
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0));
+ boundsToMove = null;
+ }
+ }
+
+ public void setShowsUserLocation(boolean showUserLocation) {
+ this.showUserLocation = showUserLocation; // hold onto this for lifecycle handling
+ if (hasPermissions()) {
+ //noinspection MissingPermission
+ map.setMyLocationEnabled(showUserLocation);
+ }
+ }
+
+ public void setShowsMyLocationButton(boolean showMyLocationButton) {
+ if (hasPermissions()) {
+ map.getUiSettings().setMyLocationButtonEnabled(showMyLocationButton);
+ }
+ }
+
+ public void setToolbarEnabled(boolean toolbarEnabled) {
+ if (hasPermissions()) {
+ map.getUiSettings().setMapToolbarEnabled(toolbarEnabled);
+ }
+ }
+
+ public void setCacheEnabled(boolean cacheEnabled) {
+ this.cacheEnabled = cacheEnabled;
+ this.cacheView();
+ }
+
+ public void enableMapLoading(boolean loadingEnabled) {
+ if (loadingEnabled && !this.isMapLoaded) {
+ this.getMapLoadingLayoutView().setVisibility(View.VISIBLE);
+ }
+ }
+
+ public void setMoveOnMarkerPress(boolean moveOnPress) {
+ this.moveOnMarkerPress = moveOnPress;
+ }
+
+ public void setLoadingBackgroundColor(Integer loadingBackgroundColor) {
+ this.loadingBackgroundColor = loadingBackgroundColor;
+
+ if (this.mapLoadingLayout != null) {
+ if (loadingBackgroundColor == null) {
+ this.mapLoadingLayout.setBackgroundColor(Color.WHITE);
+ } else {
+ this.mapLoadingLayout.setBackgroundColor(this.loadingBackgroundColor);
+ }
+ }
+ }
+
+ public void setLoadingIndicatorColor(Integer loadingIndicatorColor) {
+ this.loadingIndicatorColor = loadingIndicatorColor;
+ if (this.mapLoadingProgressBar != null) {
+ Integer color = loadingIndicatorColor;
+ if (color == null) {
+ color = Color.parseColor("#606060");
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ ColorStateList progressTintList = ColorStateList.valueOf(loadingIndicatorColor);
+ ColorStateList secondaryProgressTintList = ColorStateList.valueOf(loadingIndicatorColor);
+ ColorStateList indeterminateTintList = ColorStateList.valueOf(loadingIndicatorColor);
+
+ this.mapLoadingProgressBar.setProgressTintList(progressTintList);
+ this.mapLoadingProgressBar.setSecondaryProgressTintList(secondaryProgressTintList);
+ this.mapLoadingProgressBar.setIndeterminateTintList(indeterminateTintList);
+ } else {
+ PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN;
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
+ mode = PorterDuff.Mode.MULTIPLY;
+ }
+ if (this.mapLoadingProgressBar.getIndeterminateDrawable() != null)
+ this.mapLoadingProgressBar.getIndeterminateDrawable().setColorFilter(color, mode);
+ if (this.mapLoadingProgressBar.getProgressDrawable() != null)
+ this.mapLoadingProgressBar.getProgressDrawable().setColorFilter(color, mode);
+ }
+ }
+ }
+
+ public void setHandlePanDrag(boolean handlePanDrag) {
+ this.handlePanDrag = handlePanDrag;
+ }
+
+ public void addFeature(View child, int index) {
+ // Our desired API is to pass up annotations/overlays as children to the mapview component.
+ // This is where we intercept them and do the appropriate underlying mapview action.
+ if (child instanceof AirMapMarker) {
+ AirMapMarker annotation = (AirMapMarker) child;
+ annotation.addToMap(map);
+ features.add(index, annotation);
+ Marker marker = (Marker) annotation.getFeature();
+ markerMap.put(marker, annotation);
+ } else if (child instanceof AirMapPolyline) {
+ AirMapPolyline polylineView = (AirMapPolyline) child;
+ polylineView.addToMap(map);
+ features.add(index, polylineView);
+ Polyline polyline = (Polyline) polylineView.getFeature();
+ polylineMap.put(polyline, polylineView);
+ } else if (child instanceof AirMapPolygon) {
+ AirMapPolygon polygonView = (AirMapPolygon) child;
+ polygonView.addToMap(map);
+ features.add(index, polygonView);
+ Polygon polygon = (Polygon) polygonView.getFeature();
+ polygonMap.put(polygon, polygonView);
+ } else if (child instanceof AirMapCircle) {
+ AirMapCircle circleView = (AirMapCircle) child;
+ circleView.addToMap(map);
+ features.add(index, circleView);
+ } else if (child instanceof AirMapUrlTile) {
+ AirMapUrlTile urlTileView = (AirMapUrlTile) child;
+ urlTileView.addToMap(map);
+ features.add(index, urlTileView);
+ } else if (child instanceof AirMapGeoJSON) {
+ AirMapGeoJSON geoJsonView = (AirMapGeoJSON) child;
+ geoJsonView.addToMap(map);
+ features.add(index, geoJsonView);
+ } else {
+ ViewGroup children = (ViewGroup) child;
+ for (int i = 0; i < children.getChildCount(); i++) {
+ addFeature(children.getChildAt(i), index);
+ }
+ }
+ }
+
+ public int getFeatureCount() {
+ return features.size();
+ }
+
+ public View getFeatureAt(int index) {
+ return features.get(index);
+ }
+
+ public void removeFeatureAt(int index) {
+ AirMapFeature feature = features.remove(index);
+ if (feature instanceof AirMapMarker) {
+ markerMap.remove(feature.getFeature());
+ } else if(feature instanceof AirMapPolyline){
+ polylineMap.remove(feature.getFeature());
+ } else if(feature instanceof AirMapPolygon){
+ polygonMap.remove(feature.getFeature());
+ }
+ feature.removeFromMap(map);
+ }
+
+
+ public WritableMap makeClickEventData(LatLng point) {
+ WritableMap event = new WritableNativeMap();
+
+ WritableMap coordinate = new WritableNativeMap();
+ coordinate.putDouble("latitude", point.latitude);
+ coordinate.putDouble("longitude", point.longitude);
+ event.putMap("coordinate", coordinate);
+
+ Projection projection = map.getProjection();
+ Point screenPoint = projection.toScreenLocation(point);
+
+ WritableMap position = new WritableNativeMap();
+ position.putDouble("x", screenPoint.x);
+ position.putDouble("y", screenPoint.y);
+ event.putMap("position", position);
+
+ return event;
+ }
+
+ public void updateExtraData(Object extraData) {
+ // if boundsToMove is not null, we now have the MapView's width/height, so we can apply
+ // a proper camera move
+ if (boundsToMove != null) {
+ HashMap data = (HashMap) extraData;
+ int width = data.get("width") == null ? 0 : data.get("width").intValue();
+ int height = data.get("height") == null ? 0 : data.get("height").intValue();
+
+ //fix for https://github.com/airbnb/react-native-maps/issues/245,
+ //it's not guaranteed the passed-in height and width would be greater than 0.
+ if (width <= 0 || height <= 0) {
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(boundsToMove, 0));
+ } else {
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(boundsToMove, width, height, 0));
+ }
+
+ boundsToMove = null;
+ }
+ }
+
+ public void animateToRegion(LatLngBounds bounds, int duration) {
+ if (map == null) return;
+ map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0), duration, null);
+ }
+
+ public void animateToViewingAngle(float angle, int duration) {
+ if (map == null) return;
+
+ CameraPosition cameraPosition = new CameraPosition.Builder(map.getCameraPosition())
+ .tilt(angle)
+ .build();
+ map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), duration, null);
+ }
+
+ public void animateToBearing(float bearing, int duration) {
+ if (map == null) return;
+ CameraPosition cameraPosition = new CameraPosition.Builder(map.getCameraPosition())
+ .bearing(bearing)
+ .build();
+ map.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), duration, null);
+ }
+
+ public void animateToCoordinate(LatLng coordinate, int duration) {
+ if (map == null) return;
+ map.animateCamera(CameraUpdateFactory.newLatLng(coordinate), duration, null);
+ }
+
+ public void fitToElements(boolean animated) {
+ if (map == null) return;
+
+ LatLngBounds.Builder builder = new LatLngBounds.Builder();
+
+ boolean addedPosition = false;
+
+ for (AirMapFeature feature : features) {
+ if (feature instanceof AirMapMarker) {
+ Marker marker = (Marker) feature.getFeature();
+ builder.include(marker.getPosition());
+ addedPosition = true;
+ }
+ // TODO(lmr): may want to include shapes / etc.
+ }
+ if (addedPosition) {
+ LatLngBounds bounds = builder.build();
+ CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
+ if (animated) {
+ map.animateCamera(cu);
+ } else {
+ map.moveCamera(cu);
+ }
+ }
+ }
+
+ public void fitToSuppliedMarkers(ReadableArray markerIDsArray, boolean animated) {
+ if (map == null) return;
+
+ LatLngBounds.Builder builder = new LatLngBounds.Builder();
+
+ String[] markerIDs = new String[markerIDsArray.size()];
+ for (int i = 0; i < markerIDsArray.size(); i++) {
+ markerIDs[i] = markerIDsArray.getString(i);
+ }
+
+ boolean addedPosition = false;
+
+ List markerIDList = Arrays.asList(markerIDs);
+
+ for (AirMapFeature feature : features) {
+ if (feature instanceof AirMapMarker) {
+ String identifier = ((AirMapMarker) feature).getIdentifier();
+ Marker marker = (Marker) feature.getFeature();
+ if (markerIDList.contains(identifier)) {
+ builder.include(marker.getPosition());
+ addedPosition = true;
+ }
+ }
+ }
+ }
+
+
+ public void fitToCoordinates(ReadableArray coordinatesArray, ReadableMap edgePadding,
+ boolean animated) {
+ if (map == null) return;
+
+ LatLngBounds.Builder builder = new LatLngBounds.Builder();
+
+ for (int i = 0; i < coordinatesArray.size(); i++) {
+ ReadableMap latLng = coordinatesArray.getMap(i);
+ Double lat = latLng.getDouble("latitude");
+ Double lng = latLng.getDouble("longitude");
+ builder.include(new LatLng(lat, lng));
+ }
+
+ LatLngBounds bounds = builder.build();
+ CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
+
+ if (edgePadding != null) {
+ map.setPadding(edgePadding.getInt("left"), edgePadding.getInt("top"),
+ edgePadding.getInt("right"), edgePadding.getInt("bottom"));
+ }
+
+ if (animated) {
+ map.animateCamera(cu);
+ } else {
+ map.moveCamera(cu);
+ }
+ map.setPadding(0, 0, 0,
+ 0); // Without this, the Google logo is moved up by the value of edgePadding.bottom
+ }
+
+ public void setMapBoundaries(ReadableMap northEast, ReadableMap southWest) {
+ if (map == null) return;
+
+ LatLngBounds.Builder builder = new LatLngBounds.Builder();
+
+ Double latNE = northEast.getDouble("latitude");
+ Double lngNE = northEast.getDouble("longitude");
+ builder.include(new LatLng(latNE, lngNE));
+
+ Double latSW = southWest.getDouble("latitude");
+ Double lngSW = southWest.getDouble("longitude");
+ builder.include(new LatLng(latSW, lngSW));
+
+ LatLngBounds bounds = builder.build();
+
+ map.setLatLngBoundsForCameraTarget(bounds);
+ }
+
+ // InfoWindowAdapter interface
+
+ @Override
+ public View getInfoWindow(Marker marker) {
+ AirMapMarker markerView = markerMap.get(marker);
+ return markerView.getCallout();
+ }
+
+ @Override
+ public View getInfoContents(Marker marker) {
+ AirMapMarker markerView = markerMap.get(marker);
+ return markerView.getInfoContents();
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ gestureDetector.onTouchEvent(ev);
+
+ int action = MotionEventCompat.getActionMasked(ev);
+
+ switch (action) {
+ case (MotionEvent.ACTION_DOWN):
+ this.getParent().requestDisallowInterceptTouchEvent(
+ map != null && map.getUiSettings().isScrollGesturesEnabled());
+ break;
+ case (MotionEvent.ACTION_UP):
+ // Clear this regardless, since isScrollGesturesEnabled() may have been updated
+ this.getParent().requestDisallowInterceptTouchEvent(false);
+ break;
+ }
+ super.dispatchTouchEvent(ev);
+ return true;
+ }
+
+ @Override
+ public void onMarkerDragStart(Marker marker) {
+ WritableMap event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, this, "onMarkerDragStart", event);
+
+ AirMapMarker markerView = markerMap.get(marker);
+ event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, markerView, "onDragStart", event);
+ }
+
+ @Override
+ public void onMarkerDrag(Marker marker) {
+ WritableMap event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, this, "onMarkerDrag", event);
+
+ AirMapMarker markerView = markerMap.get(marker);
+ event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, markerView, "onDrag", event);
+ }
+
+ @Override
+ public void onMarkerDragEnd(Marker marker) {
+ WritableMap event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, this, "onMarkerDragEnd", event);
+
+ AirMapMarker markerView = markerMap.get(marker);
+ event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, markerView, "onDragEnd", event);
+ }
+
+ private ProgressBar getMapLoadingProgressBar() {
+ if (this.mapLoadingProgressBar == null) {
+ this.mapLoadingProgressBar = new ProgressBar(getContext());
+ this.mapLoadingProgressBar.setIndeterminate(true);
+ }
+ if (this.loadingIndicatorColor != null) {
+ this.setLoadingIndicatorColor(this.loadingIndicatorColor);
+ }
+ return this.mapLoadingProgressBar;
+ }
+
+ private RelativeLayout getMapLoadingLayoutView() {
+ if (this.mapLoadingLayout == null) {
+ this.mapLoadingLayout = new RelativeLayout(getContext());
+ this.mapLoadingLayout.setBackgroundColor(Color.LTGRAY);
+ this.addView(this.mapLoadingLayout,
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
+ params.addRule(RelativeLayout.CENTER_IN_PARENT);
+ this.mapLoadingLayout.addView(this.getMapLoadingProgressBar(), params);
+
+ this.mapLoadingLayout.setVisibility(View.INVISIBLE);
+ }
+ this.setLoadingBackgroundColor(this.loadingBackgroundColor);
+ return this.mapLoadingLayout;
+ }
+
+ private ImageView getCacheImageView() {
+ if (this.cacheImageView == null) {
+ this.cacheImageView = new ImageView(getContext());
+ this.addView(this.cacheImageView,
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ this.cacheImageView.setVisibility(View.INVISIBLE);
+ }
+ return this.cacheImageView;
+ }
+
+ private void removeCacheImageView() {
+ if (this.cacheImageView != null) {
+ ((ViewGroup) this.cacheImageView.getParent()).removeView(this.cacheImageView);
+ this.cacheImageView = null;
+ }
+ }
+
+ private void removeMapLoadingProgressBar() {
+ if (this.mapLoadingProgressBar != null) {
+ ((ViewGroup) this.mapLoadingProgressBar.getParent()).removeView(this.mapLoadingProgressBar);
+ this.mapLoadingProgressBar = null;
+ }
+ }
+
+ private void removeMapLoadingLayoutView() {
+ this.removeMapLoadingProgressBar();
+ if (this.mapLoadingLayout != null) {
+ ((ViewGroup) this.mapLoadingLayout.getParent()).removeView(this.mapLoadingLayout);
+ this.mapLoadingLayout = null;
+ }
+ }
+
+ private void cacheView() {
+ if (this.cacheEnabled) {
+ final ImageView cacheImageView = this.getCacheImageView();
+ final RelativeLayout mapLoadingLayout = this.getMapLoadingLayoutView();
+ cacheImageView.setVisibility(View.INVISIBLE);
+ mapLoadingLayout.setVisibility(View.VISIBLE);
+ if (this.isMapLoaded) {
+ this.map.snapshot(new GoogleMap.SnapshotReadyCallback() {
+ @Override public void onSnapshotReady(Bitmap bitmap) {
+ cacheImageView.setImageBitmap(bitmap);
+ cacheImageView.setVisibility(View.VISIBLE);
+ mapLoadingLayout.setVisibility(View.INVISIBLE);
+ }
+ });
+ }
+ } else {
+ this.removeCacheImageView();
+ if (this.isMapLoaded) {
+ this.removeMapLoadingLayoutView();
+ }
+ }
+ }
+
+ public void onPanDrag(MotionEvent ev) {
+ Point point = new Point((int) ev.getX(), (int) ev.getY());
+ LatLng coords = this.map.getProjection().fromScreenLocation(point);
+ WritableMap event = makeClickEventData(coords);
+ manager.pushEvent(context, this, "onPanDrag", event);
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/LatLngBoundsUtils.java b/lib/android/src/main/java/com/airbnb/android/react/maps/LatLngBoundsUtils.java
new file mode 100644
index 000000000..d32e0dc72
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/LatLngBoundsUtils.java
@@ -0,0 +1,47 @@
+package com.airbnb.android.react.maps;
+
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
+
+public class LatLngBoundsUtils {
+ public static boolean BoundsAreDifferent(LatLngBounds a, LatLngBounds b) {
+ LatLng centerA = a.getCenter();
+ double latA = centerA.latitude;
+ double lngA = centerA.longitude;
+ double latDeltaA = a.northeast.latitude - a.southwest.latitude;
+ double lngDeltaA = a.northeast.longitude - a.southwest.longitude;
+
+ LatLng centerB = b.getCenter();
+ double latB = centerB.latitude;
+ double lngB = centerB.longitude;
+ double latDeltaB = b.northeast.latitude - b.southwest.latitude;
+ double lngDeltaB = b.northeast.longitude - b.southwest.longitude;
+
+ double latEps = LatitudeEpsilon(a, b);
+ double lngEps = LongitudeEpsilon(a, b);
+
+ return
+ different(latA, latB, latEps) ||
+ different(lngA, lngB, lngEps) ||
+ different(latDeltaA, latDeltaB, latEps) ||
+ different(lngDeltaA, lngDeltaB, lngEps);
+ }
+
+ private static boolean different(double a, double b, double epsilon) {
+ return Math.abs(a - b) > epsilon;
+ }
+
+ private static double LatitudeEpsilon(LatLngBounds a, LatLngBounds b) {
+ double sizeA = a.northeast.latitude - a.southwest.latitude; // something mod 180?
+ double sizeB = b.northeast.latitude - b.southwest.latitude; // something mod 180?
+ double size = Math.min(Math.abs(sizeA), Math.abs(sizeB));
+ return size / 2560;
+ }
+
+ private static double LongitudeEpsilon(LatLngBounds a, LatLngBounds b) {
+ double sizeA = a.northeast.longitude - a.southwest.longitude;
+ double sizeB = b.northeast.longitude - b.southwest.longitude;
+ double size = Math.min(Math.abs(sizeA), Math.abs(sizeB));
+ return size / 2560;
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java b/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java
new file mode 100644
index 000000000..ce8aa4d11
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java
@@ -0,0 +1,55 @@
+package com.airbnb.android.react.maps;
+
+import android.app.Activity;
+
+import com.facebook.react.ReactPackage;
+import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.bridge.NativeModule;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.uimanager.ViewManager;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class MapsPackage implements ReactPackage {
+ public MapsPackage(Activity activity) {
+ } // backwards compatibility
+
+ public MapsPackage() {
+ }
+
+ @Override
+ public List createNativeModules(ReactApplicationContext reactContext) {
+ return Arrays.asList(new AirMapModule(reactContext));
+ }
+
+ // Deprecated RN 0.47
+ public List> createJSModules() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactContext) {
+ AirMapCalloutManager calloutManager = new AirMapCalloutManager();
+ AirMapMarkerManager annotationManager = new AirMapMarkerManager();
+ AirMapPolylineManager polylineManager = new AirMapPolylineManager(reactContext);
+ AirMapPolygonManager polygonManager = new AirMapPolygonManager(reactContext);
+ AirMapCircleManager circleManager = new AirMapCircleManager(reactContext);
+ AirMapGeoJSONManager geoJsonManager = new AirMapGeoJSONManager(reactContext);
+ AirMapManager mapManager = new AirMapManager(reactContext);
+ AirMapLiteManager mapLiteManager = new AirMapLiteManager(reactContext);
+ AirMapUrlTileManager tileManager = new AirMapUrlTileManager(reactContext);
+
+ return Arrays.asList(
+ calloutManager,
+ annotationManager,
+ polylineManager,
+ polygonManager,
+ circleManager,
+ geoJsonManager,
+ mapManager,
+ mapLiteManager,
+ tileManager);
+ }
+}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/RegionChangeEvent.java b/lib/android/src/main/java/com/airbnb/android/react/maps/RegionChangeEvent.java
new file mode 100644
index 000000000..675eb4106
--- /dev/null
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/RegionChangeEvent.java
@@ -0,0 +1,46 @@
+package com.airbnb.android.react.maps;
+
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableNativeMap;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+import com.google.android.gms.maps.model.LatLng;
+import com.google.android.gms.maps.model.LatLngBounds;
+
+public class RegionChangeEvent extends Event {
+ private final LatLngBounds bounds;
+ private final boolean continuous;
+
+ public RegionChangeEvent(int id, LatLngBounds bounds, boolean continuous) {
+ super(id);
+ this.bounds = bounds;
+ this.continuous = continuous;
+ }
+
+ @Override
+ public String getEventName() {
+ return "topChange";
+ }
+
+ @Override
+ public boolean canCoalesce() {
+ return false;
+ }
+
+ @Override
+ public void dispatch(RCTEventEmitter rctEventEmitter) {
+
+ WritableMap event = new WritableNativeMap();
+ event.putBoolean("continuous", continuous);
+
+ WritableMap region = new WritableNativeMap();
+ LatLng center = bounds.getCenter();
+ region.putDouble("latitude", center.latitude);
+ region.putDouble("longitude", center.longitude);
+ region.putDouble("latitudeDelta", bounds.northeast.latitude - bounds.southwest.latitude);
+ region.putDouble("longitudeDelta", bounds.northeast.longitude - bounds.southwest.longitude);
+ event.putMap("region", region);
+
+ rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event);
+ }
+}
diff --git a/android/src/main/java/com/airbnb/android/react/maps/SizeReportingShadowNode.java b/lib/android/src/main/java/com/airbnb/android/react/maps/SizeReportingShadowNode.java
similarity index 65%
rename from android/src/main/java/com/airbnb/android/react/maps/SizeReportingShadowNode.java
rename to lib/android/src/main/java/com/airbnb/android/react/maps/SizeReportingShadowNode.java
index 40ace480f..bf6c29d65 100644
--- a/android/src/main/java/com/airbnb/android/react/maps/SizeReportingShadowNode.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/SizeReportingShadowNode.java
@@ -18,14 +18,14 @@
// which sends the width/height of the view after layout occurs.
public class SizeReportingShadowNode extends LayoutShadowNode {
- @Override
- public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
- super.onCollectExtraUpdates(uiViewOperationQueue);
+ @Override
+ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
+ super.onCollectExtraUpdates(uiViewOperationQueue);
- Map data = new HashMap<>();
- data.put("width", getLayoutWidth());
- data.put("height", getLayoutHeight());
+ Map data = new HashMap<>();
+ data.put("width", getLayoutWidth());
+ data.put("height", getLayoutHeight());
- uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), data);
- }
+ uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), data);
+ }
}
diff --git a/components/AnimatedRegion.js b/lib/components/AnimatedRegion.js
similarity index 95%
rename from components/AnimatedRegion.js
rename to lib/components/AnimatedRegion.js
index 29356ca9e..ad18c5e07 100644
--- a/components/AnimatedRegion.js
+++ b/lib/components/AnimatedRegion.js
@@ -111,25 +111,25 @@ export default class AnimatedMapRegion extends AnimatedWithChildren {
spring(config) {
var animations = [];
config.hasOwnProperty('latitude') &&
- animations.push(Animated.timing(this.latitude, {
+ animations.push(Animated.spring(this.latitude, {
...config,
toValue: config.latitude
}));
config.hasOwnProperty('longitude') &&
- animations.push(Animated.timing(this.longitude, {
+ animations.push(Animated.spring(this.longitude, {
...config,
toValue: config.longitude
}));
config.hasOwnProperty('latitudeDelta') &&
- animations.push(Animated.timing(this.latitudeDelta, {
+ animations.push(Animated.spring(this.latitudeDelta, {
...config,
toValue: config.latitudeDelta
}));
config.hasOwnProperty('longitudeDelta') &&
- animations.push(Animated.timing(this.longitudeDelta, {
+ animations.push(Animated.spring(this.longitudeDelta, {
...config,
toValue: config.longitudeDelta
}));
diff --git a/components/MapCallout.js b/lib/components/MapCallout.js
similarity index 77%
rename from components/MapCallout.js
rename to lib/components/MapCallout.js
index cf4bb9cef..2ef73a096 100644
--- a/components/MapCallout.js
+++ b/lib/components/MapCallout.js
@@ -1,15 +1,20 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
- View,
StyleSheet,
+ ViewPropTypes,
+ View,
} from 'react-native';
import decorateMapComponent, {
SUPPORTED,
USES_DEFAULT_IMPLEMENTATION,
} from './decorateMapComponent';
+// if ViewPropTypes is not defined fall back to View.propType (to support RN < 0.44)
+const viewPropTypes = ViewPropTypes || View.propTypes;
+
const propTypes = {
- ...View.propTypes,
+ ...viewPropTypes,
tooltip: PropTypes.bool,
onPress: PropTypes.func,
};
diff --git a/components/MapCircle.js b/lib/components/MapCircle.js
similarity index 90%
rename from components/MapCircle.js
rename to lib/components/MapCircle.js
index 054cd2b6b..ae5d1bdbe 100644
--- a/components/MapCircle.js
+++ b/lib/components/MapCircle.js
@@ -1,5 +1,7 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
+ ViewPropTypes,
View,
} from 'react-native';
import decorateMapComponent, {
@@ -7,8 +9,11 @@ import decorateMapComponent, {
NOT_SUPPORTED,
} from './decorateMapComponent';
+// if ViewPropTypes is not defined fall back to View.propType (to support RN < 0.44)
+const viewPropTypes = ViewPropTypes || View.propTypes;
+
const propTypes = {
- ...View.propTypes,
+ ...viewPropTypes,
/**
* The coordinate of the center of the circle
@@ -125,10 +130,14 @@ const defaultProps = {
};
class MapCircle extends React.Component {
+ setNativeProps(props) {
+ this.circle.setNativeProps(props);
+ }
+
render() {
const AIRMapCircle = this.getAirComponent();
return (
-
+ { this.circle = ref; }} />
);
}
}
diff --git a/components/MapGeoJson.js b/lib/components/MapGeoJson.js
similarity index 100%
rename from components/MapGeoJson.js
rename to lib/components/MapGeoJson.js
diff --git a/components/MapMarker.js b/lib/components/MapMarker.js
similarity index 91%
rename from components/MapMarker.js
rename to lib/components/MapMarker.js
index 45ed6c300..a2f809f58 100644
--- a/components/MapMarker.js
+++ b/lib/components/MapMarker.js
@@ -1,11 +1,13 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
- View,
StyleSheet,
Platform,
NativeModules,
Animated,
findNodeHandle,
+ ViewPropTypes,
+ View,
} from 'react-native';
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
@@ -21,8 +23,11 @@ const viewConfig = {
},
};
+// if ViewPropTypes is not defined fall back to View.propType (to support RN < 0.44)
+const viewPropTypes = ViewPropTypes || View.propTypes;
+
const propTypes = {
- ...View.propTypes,
+ ...viewPropTypes,
// TODO(lmr): get rid of these?
identifier: PropTypes.string,
@@ -48,6 +53,11 @@ const propTypes = {
*/
image: PropTypes.any,
+ /**
+ * Opacity level of view/image based markers
+ */
+ opacity: PropTypes.number,
+
/**
* If no custom marker view or custom image is provided, the platform default pin will be used,
* which can be customized by this color. Ignored if a custom marker is being used.
@@ -159,6 +169,14 @@ const propTypes = {
draggable: PropTypes.bool,
+ /**
+ * Sets whether this marker should track view changes true.
+ *
+ * @platform ios
+ */
+
+ tracksViewChanges: PropTypes.bool,
+
/**
* Callback that is called when the user presses on the marker
*/
@@ -212,6 +230,10 @@ class MapMarker extends React.Component {
this.hideCallout = this.hideCallout.bind(this);
}
+ setNativeProps(props) {
+ this.marker.setNativeProps(props);
+ }
+
showCallout() {
this._runCommand('showCallout', []);
}
@@ -247,14 +269,16 @@ class MapMarker extends React.Component {
let image;
if (this.props.image) {
image = resolveAssetSource(this.props.image) || {};
- image = image.uri;
+ image = image.uri || this.props.image;
}
const AIRMapMarker = this.getAirComponent();
return (
{ this.marker = ref; }}
+ ref={ref => {
+ this.marker = ref;
+ }}
{...this.props}
image={image}
style={[styles.marker, this.props.style]}
diff --git a/components/MapPolygon.js b/lib/components/MapPolygon.js
similarity index 83%
rename from components/MapPolygon.js
rename to lib/components/MapPolygon.js
index 979cd54f7..fc57beb29 100644
--- a/components/MapPolygon.js
+++ b/lib/components/MapPolygon.js
@@ -1,5 +1,7 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
+ ViewPropTypes,
View,
} from 'react-native';
import decorateMapComponent, {
@@ -7,8 +9,11 @@ import decorateMapComponent, {
NOT_SUPPORTED,
} from './decorateMapComponent';
+// if ViewPropTypes is not defined fall back to View.propType (to support RN < 0.44)
+const viewPropTypes = ViewPropTypes || View.propTypes;
+
const propTypes = {
- ...View.propTypes,
+ ...viewPropTypes,
/**
* An array of coordinates to describe the polygon
@@ -21,11 +26,28 @@ const propTypes = {
longitude: PropTypes.number.isRequired,
})),
+ /**
+ * An array of array of coordinates to describe the polygon holes
+ */
+ holes: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.shape({
+ /**
+ * Latitude/Longitude coordinates
+ */
+ latitude: PropTypes.number.isRequired,
+ longitude: PropTypes.number.isRequired,
+ }))),
+
/**
* Callback that is called when the user presses on the polygon
*/
onPress: PropTypes.func,
+ /**
+ * Boolean to allow a polygon to be tappable and use the
+ * onPress function
+ */
+ tappable: PropTypes.bool,
+
/**
* The stroke width to use for the path.
*/
@@ -130,10 +152,14 @@ const defaultProps = {
};
class MapPolygon extends React.Component {
+ setNativeProps(props) {
+ this.polygon.setNativeProps(props);
+ }
+
render() {
const AIRMapPolygon = this.getAirComponent();
return (
-
+ { this.polygon = ref; }} />
);
}
}
diff --git a/components/MapPolyline.js b/lib/components/MapPolyline.js
similarity index 88%
rename from components/MapPolyline.js
rename to lib/components/MapPolyline.js
index 067e706de..4b576717e 100644
--- a/components/MapPolyline.js
+++ b/lib/components/MapPolyline.js
@@ -1,5 +1,7 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
+ ViewPropTypes,
View,
} from 'react-native';
import decorateMapComponent, {
@@ -7,8 +9,11 @@ import decorateMapComponent, {
NOT_SUPPORTED,
} from './decorateMapComponent';
+// if ViewPropTypes is not defined fall back to View.propType (to support RN < 0.44)
+const viewPropTypes = ViewPropTypes || View.propTypes;
+
const propTypes = {
- ...View.propTypes,
+ ...viewPropTypes,
/**
* An array of coordinates to describe the polygon
@@ -26,6 +31,11 @@ const propTypes = {
*/
onPress: PropTypes.func,
+ /* Boolean to allow a polyline to be tappable and use the
+ * onPress function
+ */
+ tappable: PropTypes.bool,
+
/**
* The stroke width to use for the path.
*/
@@ -125,10 +135,14 @@ const defaultProps = {
};
class MapPolyline extends React.Component {
+ setNativeProps(props) {
+ this.polyline.setNativeProps(props);
+ }
+
render() {
const AIRMapPolyline = this.getAirComponent();
return (
-
+ { this.polyline = ref; }} />
);
}
}
diff --git a/components/MapUrlTile.js b/lib/components/MapUrlTile.js
similarity index 82%
rename from components/MapUrlTile.js
rename to lib/components/MapUrlTile.js
index cf2770334..a2b49e960 100644
--- a/components/MapUrlTile.js
+++ b/lib/components/MapUrlTile.js
@@ -1,6 +1,8 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
+ ViewPropTypes,
View,
} from 'react-native';
@@ -9,8 +11,11 @@ import decorateMapComponent, {
SUPPORTED,
} from './decorateMapComponent';
+// if ViewPropTypes is not defined fall back to View.propType (to support RN < 0.44)
+const viewPropTypes = ViewPropTypes || View.propTypes;
+
const propTypes = {
- ...View.propTypes,
+ ...viewPropTypes,
/**
* The url template of the tile server. The patterns {x} {y} {z} will be replaced at runtime
diff --git a/components/MapView.js b/lib/components/MapView.js
similarity index 73%
rename from components/MapView.js
rename to lib/components/MapView.js
index 7e93ccbdf..66af88e0a 100644
--- a/components/MapView.js
+++ b/lib/components/MapView.js
@@ -1,13 +1,15 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
EdgeInsetsPropType,
Platform,
- View,
Animated,
requireNativeComponent,
NativeModules,
ColorPropType,
findNodeHandle,
+ ViewPropTypes,
+ View,
} from 'react-native';
import MapMarker from './MapMarker';
import MapPolyline from './MapPolyline';
@@ -31,6 +33,7 @@ const MAP_TYPES = {
HYBRID: 'hybrid',
TERRAIN: 'terrain',
NONE: 'none',
+ MUTEDSTANDARD: 'mutedStandard',
};
const ANDROID_ONLY_MAP_TYPES = [
@@ -45,8 +48,11 @@ const viewConfig = {
},
};
+// if ViewPropTypes is not defined fall back to View.propType (to support RN < 0.44)
+const viewPropTypes = ViewPropTypes || View.propTypes;
+
const propTypes = {
- ...View.propTypes,
+ ...viewPropTypes,
/**
* When provider is "google", we will use GoogleMaps.
* Any value other than "google" will default to using
@@ -60,7 +66,7 @@ const propTypes = {
* Used to style and layout the `MapView`. See `StyleSheet.js` and
* `ViewStylePropTypes.js` for more info.
*/
- style: View.propTypes.style,
+ style: viewPropTypes.style,
/**
* A json object that describes the style of the map. This is transformed to a string
@@ -87,6 +93,15 @@ const propTypes = {
*/
showsUserLocation: PropTypes.bool,
+ /**
+ * The title of the annotation for current user location. This only works if
+ * `showsUserLocation` is true.
+ * There is a default value `My Location` set by MapView.
+ *
+ * @platform ios
+ */
+ userLocationAnnotationTitle: PropTypes.string,
+
/**
* If `false` hide the button to move map to the current user's location.
* Default value is `true`.
@@ -218,6 +233,14 @@ const propTypes = {
*/
showsIndoors: PropTypes.bool,
+ /**
+ * A Boolean indicating whether indoor level picker should be enabled.
+ * Default value is `false`
+ *
+ * @platform android
+ */
+ showsIndoorLevelPicker: PropTypes.bool,
+
/**
* The map type to be displayed.
*
@@ -280,6 +303,15 @@ const propTypes = {
*/
liteMode: PropTypes.bool,
+ /**
+ * (Google Maps only)
+ *
+ * Padding that is used by the Google Map View to position
+ * the camera, legal labels and buttons
+ *
+ */
+ mapPadding: EdgeInsetsPropType,
+
/**
* Maximum size of area that can be displayed.
*
@@ -300,6 +332,11 @@ const propTypes = {
*/
legalLabelInsets: EdgeInsetsPropType,
+ /**
+ * Callback that is called once the map is fully loaded.
+ */
+ onMapReady: PropTypes.func,
+
/**
* Callback that is called continuously when the user is dragging the map.
*/
@@ -367,6 +404,16 @@ const propTypes = {
*/
onMarkerDragEnd: PropTypes.func,
+ /**
+ * Minimum zoom value for the map, must be between 0 and 20
+ */
+ minZoomLevel: PropTypes.number,
+
+ /**
+ * Maximum zoom value for the map, must be between 0 and 20
+ */
+ maxZoomLevel: PropTypes.number,
+
};
class MapView extends React.Component {
@@ -378,6 +425,7 @@ class MapView extends React.Component {
};
this._onMapReady = this._onMapReady.bind(this);
+ this._onMarkerPress = this._onMarkerPress.bind(this);
this._onChange = this._onChange.bind(this);
this._onLayout = this._onLayout.bind(this);
}
@@ -413,30 +461,39 @@ class MapView extends React.Component {
}
_onMapReady() {
- const { region, initialRegion } = this.props;
+ const { region, initialRegion, onMapReady } = this.props;
if (region) {
this.map.setNativeProps({ region });
} else if (initialRegion) {
- this.map.setNativeProps({ region: initialRegion });
+ this.map.setNativeProps({ initialRegion });
}
this._updateStyle();
- this.setState({ isReady: true });
+ this.setState({ isReady: true }, () => {
+ if (onMapReady) onMapReady();
+ });
}
_onLayout(e) {
- const { region, initialRegion, onLayout } = this.props;
- const { isReady } = this.state;
const { layout } = e.nativeEvent;
if (!layout.width || !layout.height) return;
- if (region && isReady && !this.__layoutCalled) {
- this.__layoutCalled = true;
- this.map.setNativeProps({ region });
- } else if (initialRegion && isReady && !this.__layoutCalled) {
- this.__layoutCalled = true;
- this.map.setNativeProps({ region: initialRegion });
+ if (this.state.isReady && !this.__layoutCalled) {
+ const { region, initialRegion } = this.props;
+ if (region) {
+ this.__layoutCalled = true;
+ this.map.setNativeProps({ region });
+ } else if (initialRegion) {
+ this.__layoutCalled = true;
+ this.map.setNativeProps({ initialRegion });
+ }
+ }
+ if (this.props.onLayout) {
+ this.props.onLayout(e);
}
- if (onLayout) {
- onLayout(e);
+ }
+
+ _onMarkerPress(event) {
+ if (this.props.onMarkerPress) {
+ this.props.onMarkerPress(event.nativeEvent);
}
}
@@ -459,6 +516,14 @@ class MapView extends React.Component {
this._runCommand('animateToCoordinate', [latLng, duration || 500]);
}
+ animateToBearing(bearing, duration) {
+ this._runCommand('animateToBearing', [bearing, duration || 500]);
+ }
+
+ animateToViewingAngle(angle, duration) {
+ this._runCommand('animateToViewingAngle', [angle, duration || 500]);
+ }
+
fitToElements(animated) {
this._runCommand('fitToElements', [animated]);
}
@@ -467,7 +532,7 @@ class MapView extends React.Component {
this._runCommand('fitToSuppliedMarkers', [markers, animated]);
}
- fitToCoordinates(coordinates = [], options) {
+ fitToCoordinates(coordinates = [], options = {}) {
const {
edgePadding = { top: 0, right: 0, bottom: 0, left: 0 },
animated = true,
@@ -476,9 +541,83 @@ class MapView extends React.Component {
this._runCommand('fitToCoordinates', [coordinates, edgePadding, animated]);
}
- takeSnapshot(width, height, region, callback) {
- const finalRegion = region || this.props.region || this.props.initialRegion;
- this._runCommand('takeSnapshot', [width, height, finalRegion, callback]);
+ setMapBoundaries(northEast, southWest) {
+ this._runCommand('setMapBoundaries', [northEast, southWest]);
+ }
+
+ /**
+ * Takes a snapshot of the map and saves it to a picture
+ * file or returns the image as a base64 encoded string.
+ *
+ * @param config Configuration options
+ * @param [config.width] Width of the rendered map-view (when omitted actual view width is used).
+ * @param [config.height] Height of the rendered map-view (when omitted actual height is used).
+ * @param [config.region] Region to render (Only supported on iOS).
+ * @param [config.format] Encoding format ('png', 'jpg') (default: 'png').
+ * @param [config.quality] Compression quality (only used for jpg) (default: 1.0).
+ * @param [config.result] Result format ('file', 'base64') (default: 'file').
+ *
+ * @return Promise Promise with either the file-uri or base64 encoded string
+ */
+ takeSnapshot(args) {
+ // For the time being we support the legacy API on iOS.
+ // This will be removed in a future release and only the
+ // new Promise style API shall be supported.
+ if (Platform.OS === 'ios' && (arguments.length === 4)) {
+ console.warn('Old takeSnapshot API has been deprecated; will be removed in the near future'); //eslint-disable-line
+ const width = arguments[0]; // eslint-disable-line
+ const height = arguments[1]; // eslint-disable-line
+ const region = arguments[2]; // eslint-disable-line
+ const callback = arguments[3]; // eslint-disable-line
+ this._runCommand('takeSnapshot', [
+ width || 0,
+ height || 0,
+ region || {},
+ 'png',
+ 1,
+ 'legacy',
+ callback,
+ ]);
+ return undefined;
+ }
+
+ // Sanitize inputs
+ const config = {
+ width: args.width || 0,
+ height: args.height || 0,
+ region: args.region || {},
+ format: args.format || 'png',
+ quality: args.quality || 1.0,
+ result: args.result || 'file',
+ };
+ if ((config.format !== 'png') &&
+ (config.format !== 'jpg')) throw new Error('Invalid format specified');
+ if ((config.result !== 'file') &&
+ (config.result !== 'base64')) throw new Error('Invalid result specified');
+
+ // Call native function
+ if (Platform.OS === 'android') {
+ return NativeModules.AirMapModule.takeSnapshot(this._getHandle(), config);
+ } else if (Platform.OS === 'ios') {
+ return new Promise((resolve, reject) => {
+ this._runCommand('takeSnapshot', [
+ config.width,
+ config.height,
+ config.region,
+ config.format,
+ config.quality,
+ config.result,
+ (err, snapshot) => {
+ if (err) {
+ reject(err);
+ } else {
+ resolve(snapshot);
+ }
+ },
+ ]);
+ });
+ }
+ return Promise.reject('takeSnapshot not supported on this platform');
}
_uiManagerCommand(name) {
@@ -520,6 +659,7 @@ class MapView extends React.Component {
...this.props,
region: null,
initialRegion: null,
+ onMarkerPress: this._onMarkerPress,
onChange: this._onChange,
onMapReady: this._onMapReady,
onLayout: this._onLayout,
@@ -533,6 +673,7 @@ class MapView extends React.Component {
style: this.props.style,
region: null,
initialRegion: null,
+ onMarkerPress: this._onMarkerPress,
onChange: this._onChange,
onMapReady: this._onMapReady,
onLayout: this._onLayout,
diff --git a/components/ProviderConstants.js b/lib/components/ProviderConstants.js
similarity index 100%
rename from components/ProviderConstants.js
rename to lib/components/ProviderConstants.js
diff --git a/components/decorateMapComponent.js b/lib/components/decorateMapComponent.js
similarity index 90%
rename from components/decorateMapComponent.js
rename to lib/components/decorateMapComponent.js
index 2f5e98de5..168d4f122 100644
--- a/components/decorateMapComponent.js
+++ b/lib/components/decorateMapComponent.js
@@ -1,4 +1,4 @@
-import { PropTypes } from 'react';
+import PropTypes from 'prop-types';
import {
requireNativeComponent,
NativeModules,
@@ -48,8 +48,8 @@ export default function decorateMapComponent(Component, { componentType, provide
if (components[provider]) return components[provider];
if (provider === PROVIDER_DEFAULT) {
- components.default = getDefaultComponent();
- return components.default;
+ components[PROVIDER_DEFAULT] = getDefaultComponent();
+ return components[PROVIDER_DEFAULT];
}
const providerInfo = providers[provider];
@@ -62,8 +62,8 @@ export default function decorateMapComponent(Component, { componentType, provide
components[provider] = requireNativeComponent(componentName, Component);
}
} else { // (platformSupport === USES_DEFAULT_IMPLEMENTATION)
- if (!components.default) components.default = getDefaultComponent();
- components[provider] = components.default;
+ if (!components[PROVIDER_DEFAULT]) components[PROVIDER_DEFAULT] = getDefaultComponent();
+ components[provider] = components[PROVIDER_DEFAULT];
}
return components[provider];
diff --git a/ios/AirGoogleMaps/AIRGMSMarker.h b/lib/ios/AirGoogleMaps/AIRGMSMarker.h
similarity index 93%
rename from ios/AirGoogleMaps/AIRGMSMarker.h
rename to lib/ios/AirGoogleMaps/AIRGMSMarker.h
index baf89341d..89723ca2a 100644
--- a/ios/AirGoogleMaps/AIRGMSMarker.h
+++ b/lib/ios/AirGoogleMaps/AIRGMSMarker.h
@@ -6,7 +6,7 @@
//
#import
-#import "UIView+React.h"
+#import
@class AIRGoogleMapMarker;
diff --git a/ios/AirGoogleMaps/AIRGMSMarker.m b/lib/ios/AirGoogleMaps/AIRGMSMarker.m
similarity index 100%
rename from ios/AirGoogleMaps/AIRGMSMarker.m
rename to lib/ios/AirGoogleMaps/AIRGMSMarker.m
diff --git a/lib/ios/AirGoogleMaps/AIRGMSPolygon.h b/lib/ios/AirGoogleMaps/AIRGMSPolygon.h
new file mode 100644
index 000000000..d41c87d5e
--- /dev/null
+++ b/lib/ios/AirGoogleMaps/AIRGMSPolygon.h
@@ -0,0 +1,16 @@
+//
+// AIRGMSPolygon.h
+// AirMaps
+//
+// Created by Gerardo Pacheco 02/05/2017.
+//
+
+#import
+#import
+
+@class AIRGoogleMapPolygon;
+
+@interface AIRGMSPolygon : GMSPolygon
+@property (nonatomic, strong) NSString *identifier;
+@property (nonatomic, copy) RCTBubblingEventBlock onPress;
+@end
diff --git a/lib/ios/AirGoogleMaps/AIRGMSPolygon.m b/lib/ios/AirGoogleMaps/AIRGMSPolygon.m
new file mode 100644
index 000000000..05de0b029
--- /dev/null
+++ b/lib/ios/AirGoogleMaps/AIRGMSPolygon.m
@@ -0,0 +1,12 @@
+//
+// AIRGMSPolygon.m
+// AirMaps
+//
+// Created by Gerardo Pacheco 02/05/2017.
+//
+
+#import "AIRGMSPolygon.h"
+
+@implementation AIRGMSPolygon
+
+@end
diff --git a/lib/ios/AirGoogleMaps/AIRGMSPolyline.h b/lib/ios/AirGoogleMaps/AIRGMSPolyline.h
new file mode 100644
index 000000000..d7ee19783
--- /dev/null
+++ b/lib/ios/AirGoogleMaps/AIRGMSPolyline.h
@@ -0,0 +1,16 @@
+//
+// AIRGMSPolyline.h
+// AirMaps
+//
+// Created by Guilherme Pontes 04/05/2017.
+//
+
+#import
+#import
+
+@class AIRGoogleMapPolyline;
+
+@interface AIRGMSPolyline : GMSPolyline
+@property (nonatomic, strong) NSString *identifier;
+@property (nonatomic, copy) RCTBubblingEventBlock onPress;
+@end
diff --git a/lib/ios/AirGoogleMaps/AIRGMSPolyline.m b/lib/ios/AirGoogleMaps/AIRGMSPolyline.m
new file mode 100644
index 000000000..86e7ac055
--- /dev/null
+++ b/lib/ios/AirGoogleMaps/AIRGMSPolyline.m
@@ -0,0 +1,11 @@
+//
+// AIRGMSPolyline.m
+// AirMaps
+//
+// Created by Guilherme Pontes 04/05/2017.
+//
+
+#import "AIRGMSPolyline.h"
+
+@implementation AIRGMSPolyline
+@end
diff --git a/ios/AirGoogleMaps/AIRGoogleMap.h b/lib/ios/AirGoogleMaps/AIRGoogleMap.h
similarity index 83%
rename from ios/AirGoogleMaps/AIRGoogleMap.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMap.h
index bf16a2ef4..29f71a3a4 100644
--- a/ios/AirGoogleMaps/AIRGoogleMap.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMap.h
@@ -6,11 +6,11 @@
//
#import
-#import "RCTComponent.h"
+#import
#import
#import
-#import "RCTConvert+MapKit.h"
#import "AIRGMSMarker.h"
+#import "RCTConvert+AirMap.h"
@interface AIRGoogleMap : GMSMapView
@@ -18,6 +18,8 @@
@property (nonatomic, assign) MKCoordinateRegion initialRegion;
@property (nonatomic, assign) MKCoordinateRegion region;
@property (nonatomic, assign) NSString *customMapStyleString;
+@property (nonatomic, assign) UIEdgeInsets mapPadding;
+@property (nonatomic, copy) RCTBubblingEventBlock onMapReady;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, copy) RCTBubblingEventBlock onLongPress;
@property (nonatomic, copy) RCTBubblingEventBlock onMarkerPress;
@@ -38,8 +40,13 @@
@property (nonatomic, assign) BOOL rotateEnabled;
@property (nonatomic, assign) BOOL pitchEnabled;
@property (nonatomic, assign) BOOL showsUserLocation;
+@property (nonatomic, assign) BOOL showsMyLocationButton;
+@property (nonatomic, assign) BOOL showsIndoorLevelPicker;
+- (void)didPrepareMap;
- (BOOL)didTapMarker:(GMSMarker *)marker;
+- (void)didTapPolyline:(GMSPolyline *)polyline;
+- (void)didTapPolygon:(GMSPolygon *)polygon;
- (void)didTapAtCoordinate:(CLLocationCoordinate2D)coordinate;
- (void)didLongPressAtCoordinate:(CLLocationCoordinate2D)coordinate;
- (void)didChangeCameraPosition:(GMSCameraPosition *)position;
diff --git a/ios/AirGoogleMaps/AIRGoogleMap.m b/lib/ios/AirGoogleMaps/AIRGoogleMap.m
similarity index 84%
rename from ios/AirGoogleMaps/AIRGoogleMap.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMap.m
index 50f148eb1..c7c57663e 100644
--- a/ios/AirGoogleMaps/AIRGoogleMap.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMap.m
@@ -13,8 +13,8 @@
#import "AIRGoogleMapUrlTile.h"
#import
#import
-#import "RCTConvert+MapKit.h"
-#import "UIView+React.h"
+#import
+#import "RCTConvert+AirMap.h"
id regionAsJSON(MKCoordinateRegion region) {
return @{
@@ -91,6 +91,11 @@ - (void)insertReactSubview:(id)subview atIndex:(NSInteger)atIndex
AIRGoogleMapUrlTile *tile = (AIRGoogleMapUrlTile*)subview;
tile.tileLayer.map = self;
[self.tiles addObject:tile];
+ } else {
+ NSArray> *childSubviews = [subview reactSubviews];
+ for (int i = 0; i < childSubviews.count; i++) {
+ [self insertReactSubview:(UIView *)childSubviews[i] atIndex:atIndex];
+ }
}
[_reactSubviews insertObject:(UIView *)subview atIndex:(NSUInteger) atIndex];
}
@@ -122,6 +127,11 @@ - (void)removeReactSubview:(id)subview {
AIRGoogleMapUrlTile *tile = (AIRGoogleMapUrlTile*)subview;
tile.tileLayer.map = nil;
[self.tiles removeObject:tile];
+ } else {
+ NSArray> *childSubviews = [subview reactSubviews];
+ for (int i = 0; i < childSubviews.count; i++) {
+ [self removeReactSubview:(UIView *)childSubviews[i]];
+ }
}
[_reactSubviews removeObject:(UIView *)subview];
}
@@ -145,6 +155,10 @@ - (void)setRegion:(MKCoordinateRegion)region {
self.camera = [AIRGoogleMap makeGMSCameraPositionFromMap:self andMKCoordinateRegion:region];
}
+- (void)didPrepareMap {
+ if (self.onMapReady) self.onMapReady(@{});
+}
+
- (BOOL)didTapMarker:(GMSMarker *)marker {
AIRGMSMarker *airMarker = (AIRGMSMarker *)marker;
@@ -160,6 +174,26 @@ - (BOOL)didTapMarker:(GMSMarker *)marker {
return NO;
}
+- (void)didTapPolyline:(GMSOverlay *)polyline {
+ AIRGMSPolyline *airPolyline = (AIRGMSPolyline *)polyline;
+
+ id event = @{@"action": @"polyline-press",
+ @"id": airPolyline.identifier ?: @"unknown",
+ };
+
+ if (airPolyline.onPress) airPolyline.onPress(event);
+}
+
+- (void)didTapPolygon:(GMSOverlay *)polygon {
+ AIRGMSPolygon *airPolygon = (AIRGMSPolygon *)polygon;
+
+ id event = @{@"action": @"polygon-press",
+ @"id": airPolygon.identifier ?: @"unknown",
+ };
+
+ if (airPolygon.onPress) airPolygon.onPress(event);
+}
+
- (void)didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
if (!self.onPress) return;
self.onPress([self eventFromCoordinate:coordinate]);
@@ -185,6 +219,13 @@ - (void)idleAtCameraPosition:(GMSCameraPosition *)position {
if (self.onChange) self.onChange(event); // complete
}
+- (void)setMapPadding:(UIEdgeInsets)mapPadding {
+ self.padding = mapPadding;
+}
+
+- (UIEdgeInsets)mapPadding {
+ return self.padding;
+}
- (void)setScrollEnabled:(BOOL)scrollEnabled {
self.settings.scrollGestures = scrollEnabled;
@@ -262,6 +303,30 @@ - (BOOL)showsUserLocation {
return self.myLocationEnabled;
}
+- (void)setShowsMyLocationButton:(BOOL)showsMyLocationButton {
+ self.settings.myLocationButton = showsMyLocationButton;
+}
+
+- (BOOL)showsMyLocationButton {
+ return self.settings.myLocationButton;
+}
+
+- (void)setMinZoomLevel:(CGFloat)minZoomLevel {
+ [self setMinZoom:minZoomLevel maxZoom:self.maxZoom ];
+}
+
+- (void)setMaxZoomLevel:(CGFloat)maxZoomLevel {
+ [self setMinZoom:self.minZoom maxZoom:maxZoomLevel ];
+}
+
+- (void)setShowsIndoorLevelPicker:(BOOL)showsIndoorLevelPicker {
+ self.settings.indoorPicker = showsIndoorLevelPicker;
+}
+
+- (BOOL)showsIndoorLevelPicker {
+ return self.settings.indoorPicker;
+}
+
+ (MKCoordinateRegion) makeGMSCameraPositionFromMap:(GMSMapView *)map andGMSCameraPosition:(GMSCameraPosition *)position {
// solution from here: http://stackoverflow.com/a/16587735/1102215
GMSVisibleRegion visibleRegion = map.projection.visibleRegion;
diff --git a/ios/AirGoogleMaps/AIRGoogleMapCallout.h b/lib/ios/AirGoogleMaps/AIRGoogleMapCallout.h
similarity index 90%
rename from ios/AirGoogleMaps/AIRGoogleMapCallout.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapCallout.h
index 61558e6bc..784bcf613 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapCallout.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapCallout.h
@@ -7,7 +7,7 @@
//
#import
-#import "RCTView.h"
+#import
@interface AIRGoogleMapCallout : UIView
@property (nonatomic, assign) BOOL tooltip;
diff --git a/ios/AirGoogleMaps/AIRGoogleMapCallout.m b/lib/ios/AirGoogleMaps/AIRGoogleMapCallout.m
similarity index 66%
rename from ios/AirGoogleMaps/AIRGoogleMapCallout.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapCallout.m
index c64a6e03b..acc6b86b7 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapCallout.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapCallout.m
@@ -7,9 +7,9 @@
//
#import "AIRGoogleMapCallout.h"
-#import "RCTUtils.h"
-#import "RCTView.h"
-#import "RCTBridge.h"
+#import
+#import
+#import
@implementation AIRGoogleMapCallout
@end
diff --git a/ios/AirGoogleMaps/AIRGoogleMapCalloutManager.h b/lib/ios/AirGoogleMaps/AIRGoogleMapCalloutManager.h
similarity index 82%
rename from ios/AirGoogleMaps/AIRGoogleMapCalloutManager.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapCalloutManager.h
index be0e1a72f..e5514087e 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapCalloutManager.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapCalloutManager.h
@@ -5,7 +5,7 @@
// Created by Gil Birman on 9/6/16.
//
//
-#import "RCTViewManager.h"
+#import
@interface AIRGoogleMapCalloutManager : RCTViewManager
diff --git a/ios/AirGoogleMaps/AIRGoogleMapCalloutManager.m b/lib/ios/AirGoogleMaps/AIRGoogleMapCalloutManager.m
similarity index 94%
rename from ios/AirGoogleMaps/AIRGoogleMapCalloutManager.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapCalloutManager.m
index 9a2a20998..1828beb8a 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapCalloutManager.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapCalloutManager.m
@@ -8,7 +8,7 @@
#import "AIRGoogleMapCalloutManager.h"
#import "AIRGoogleMapCallout.h"
-#import "RCTView.h"
+#import
@implementation AIRGoogleMapCalloutManager
RCT_EXPORT_MODULE()
diff --git a/ios/AirGoogleMaps/AIRGoogleMapCircle.h b/lib/ios/AirGoogleMaps/AIRGoogleMapCircle.h
similarity index 100%
rename from ios/AirGoogleMaps/AIRGoogleMapCircle.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapCircle.h
diff --git a/ios/AirGoogleMaps/AIRGoogleMapCircle.m b/lib/ios/AirGoogleMaps/AIRGoogleMapCircle.m
similarity index 97%
rename from ios/AirGoogleMaps/AIRGoogleMapCircle.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapCircle.m
index 1698bee8c..28741b9f3 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapCircle.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapCircle.m
@@ -6,7 +6,7 @@
#import
#import "AIRGoogleMapCircle.h"
#import
-#import "RCTUtils.h"
+#import
@implementation AIRGoogleMapCircle
diff --git a/ios/AirGoogleMaps/AIRGoogleMapCircleManager.h b/lib/ios/AirGoogleMaps/AIRGoogleMapCircleManager.h
similarity index 81%
rename from ios/AirGoogleMaps/AIRGoogleMapCircleManager.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapCircleManager.h
index 481b6d6c5..c1de72318 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapCircleManager.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapCircleManager.h
@@ -4,7 +4,7 @@
// Created by Nick Italiano on 10/24/16.
//
-#import "RCTViewManager.h"
+#import
@interface AIRGoogleMapCircleManager : RCTViewManager
diff --git a/ios/AirGoogleMaps/AIRGoogleMapCircleManager.m b/lib/ios/AirGoogleMaps/AIRGoogleMapCircleManager.m
similarity index 91%
rename from ios/AirGoogleMaps/AIRGoogleMapCircleManager.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapCircleManager.m
index 62a164d22..93afa145f 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapCircleManager.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapCircleManager.m
@@ -6,8 +6,8 @@
#import "AIRGoogleMapCircleManager.h"
#import "AIRGoogleMapCircle.h"
-#import "RCTBridge.h"
-#import "UIView+React.h"
+#import
+#import
@interface AIRGoogleMapCircleManager()
diff --git a/ios/AirGoogleMaps/AIRGoogleMapManager.h b/lib/ios/AirGoogleMaps/AIRGoogleMapManager.h
similarity index 80%
rename from ios/AirGoogleMaps/AIRGoogleMapManager.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapManager.h
index b726eae65..ac841c7bf 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapManager.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapManager.h
@@ -5,7 +5,7 @@
// Created by Gil Birman on 9/1/16.
//
-#import "RCTViewManager.h"
+#import
@interface AIRGoogleMapManager : RCTViewManager
diff --git a/ios/AirGoogleMaps/AIRGoogleMapManager.m b/lib/ios/AirGoogleMaps/AIRGoogleMapManager.m
similarity index 57%
rename from ios/AirGoogleMaps/AIRGoogleMapManager.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapManager.m
index a04186e7e..5e6ef9c34 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapManager.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapManager.m
@@ -7,31 +7,35 @@
#import "AIRGoogleMapManager.h"
-#import "RCTViewManager.h"
-#import "RCTBridge.h"
-#import "RCTUIManager.h"
-#import "RCTConvert+CoreLocation.h"
-#import "RCTConvert+MapKit.h"
+#import
+#import
+#import
+#import
+#import
+#import
+#import
+#import
#import "RCTConvert+GMSMapViewType.h"
-#import "RCTEventDispatcher.h"
#import "AIRGoogleMap.h"
-#import "UIView+React.h"
#import "AIRMapMarker.h"
-#import "RCTViewManager.h"
-#import "RCTConvert.h"
#import "AIRMapPolyline.h"
#import "AIRMapPolygon.h"
#import "AIRMapCircle.h"
#import "SMCalloutView.h"
#import "AIRGoogleMapMarker.h"
+#import "RCTConvert+AirMap.h"
#import
+#import
static NSString *const RCTMapViewKey = @"MapView";
@interface AIRGoogleMapManager()
-
+{
+ BOOL didCallOnMapReady;
+}
+
@end
@implementation AIRGoogleMapManager
@@ -56,7 +60,11 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(scrollEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(showsUserLocation, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(showsMyLocationButton, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(showsIndoorLevelPicker, BOOL)
RCT_EXPORT_VIEW_PROPERTY(customMapStyleString, NSString)
+RCT_EXPORT_VIEW_PROPERTY(mapPadding, UIEdgeInsets)
+RCT_EXPORT_VIEW_PROPERTY(onMapReady, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLongPress, RCTBubblingEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock)
@@ -64,6 +72,8 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(onRegionChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onRegionChangeComplete, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(mapType, GMSMapViewType)
+RCT_EXPORT_VIEW_PROPERTY(minZoomLevel, CGFloat)
+RCT_EXPORT_VIEW_PROPERTY(maxZoomLevel, CGFloat)
RCT_EXPORT_METHOD(animateToRegion:(nonnull NSNumber *)reactTag
withRegion:(MKCoordinateRegion)region
@@ -74,10 +84,67 @@ - (UIView *)view
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
- [AIRGoogleMap animateWithDuration:duration/1000 animations:^{
- GMSCameraPosition* camera = [AIRGoogleMap makeGMSCameraPositionFromMap:(AIRGoogleMap *)view andMKCoordinateRegion:region];
- [(AIRGoogleMap *)view animateToCameraPosition:camera];
- }];
+ // Core Animation must be used to control the animation's duration
+ // See http://stackoverflow.com/a/15663039/171744
+ [CATransaction begin];
+ [CATransaction setAnimationDuration:duration/1000];
+ AIRGoogleMap *mapView = (AIRGoogleMap *)view;
+ GMSCameraPosition *camera = [AIRGoogleMap makeGMSCameraPositionFromMap:mapView andMKCoordinateRegion:region];
+ [mapView animateToCameraPosition:camera];
+ [CATransaction commit];
+ }
+ }];
+}
+
+RCT_EXPORT_METHOD(animateToCoordinate:(nonnull NSNumber *)reactTag
+ withRegion:(CLLocationCoordinate2D)latlng
+ withDuration:(CGFloat)duration)
+{
+ [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
+ id view = viewRegistry[reactTag];
+ if (![view isKindOfClass:[AIRGoogleMap class]]) {
+ RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
+ } else {
+ [CATransaction begin];
+ [CATransaction setAnimationDuration:duration/1000];
+ [(AIRGoogleMap *)view animateToLocation:latlng];
+ [CATransaction commit];
+ }
+ }];
+}
+
+RCT_EXPORT_METHOD(animateToViewingAngle:(nonnull NSNumber *)reactTag
+ withAngle:(double)angle
+ withDuration:(CGFloat)duration)
+{
+ [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
+ id view = viewRegistry[reactTag];
+ if (![view isKindOfClass:[AIRGoogleMap class]]) {
+ RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
+ } else {
+ [CATransaction begin];
+ [CATransaction setAnimationDuration:duration/1000];
+ AIRGoogleMap *mapView = (AIRGoogleMap *)view;
+ [mapView animateToViewingAngle:angle];
+ [CATransaction commit];
+ }
+ }];
+}
+
+RCT_EXPORT_METHOD(animateToBearing:(nonnull NSNumber *)reactTag
+ withBearing:(CGFloat)bearing
+ withDuration:(CGFloat)duration)
+{
+ [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
+ id view = viewRegistry[reactTag];
+ if (![view isKindOfClass:[AIRGoogleMap class]]) {
+ RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
+ } else {
+ [CATransaction begin];
+ [CATransaction setAnimationDuration:duration/1000];
+ AIRGoogleMap *mapView = (AIRGoogleMap *)view;
+ [mapView animateToBearing:bearing];
+ [CATransaction commit];
}
}];
}
@@ -165,43 +232,108 @@ - (UIView *)view
withWidth:(nonnull NSNumber *)width
withHeight:(nonnull NSNumber *)height
withRegion:(MKCoordinateRegion)region
+ format:(nonnull NSString *)format
+ quality:(nonnull NSNumber *)quality
+ result:(nonnull NSString *)result
withCallback:(RCTResponseSenderBlock)callback)
{
+ NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
+ NSString *pathComponent = [NSString stringWithFormat:@"Documents/snapshot-%.20lf.%@", timeStamp, format];
+ NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent: pathComponent];
+
[self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
id view = viewRegistry[reactTag];
if (![view isKindOfClass:[AIRGoogleMap class]]) {
- RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
+ RCTLogError(@"Invalid view returned from registry, expecting AIRMap, got: %@", view);
} else {
AIRGoogleMap *mapView = (AIRGoogleMap *)view;
-
+
// TODO: currently we are ignoring width, height, region
-
+
UIGraphicsBeginImageContextWithOptions(mapView.frame.size, YES, 0.0f);
[mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
-
- NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
- NSString *pathComponent = [NSString stringWithFormat:@"Documents/snapshot-%.20lf.png", timeStamp];
- NSString *filePath = [NSHomeDirectory() stringByAppendingPathComponent: pathComponent];
-
- NSData *data = UIImagePNGRepresentation(image);
- [data writeToFile:filePath atomically:YES];
- NSDictionary *snapshotData = @{
- @"uri": filePath,
- @"data": [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]
- };
- callback(@[[NSNull null], snapshotData]);
+
+ NSData *data;
+ if ([format isEqualToString:@"png"]) {
+ data = UIImagePNGRepresentation(image);
+
+ }
+ else if([format isEqualToString:@"jpg"]) {
+ data = UIImageJPEGRepresentation(image, quality.floatValue);
+ }
+
+ if ([result isEqualToString:@"file"]) {
+ [data writeToFile:filePath atomically:YES];
+ callback(@[[NSNull null], filePath]);
+ }
+ else if ([result isEqualToString:@"base64"]) {
+ callback(@[[NSNull null], [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]]);
+ }
+ else if ([result isEqualToString:@"legacy"]) {
+
+ // In the initial (iOS only) implementation of takeSnapshot,
+ // both the uri and the base64 encoded string were returned.
+ // Returning both is rarely useful and in fact causes a
+ // performance penalty when only the file URI is desired.
+ // In that case the base64 encoded string was always marshalled
+ // over the JS-bridge (which is quite slow).
+ // A new more flexible API was created to cover this.
+ // This code should be removed in a future release when the
+ // old API is fully deprecated.
+ [data writeToFile:filePath atomically:YES];
+ NSDictionary *snapshotData = @{
+ @"uri": filePath,
+ @"data": [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]
+ };
+ callback(@[[NSNull null], snapshotData]);
+ }
+
}
+ UIGraphicsEndImageContext();
}];
}
+RCT_EXPORT_METHOD(setMapBoundaries:(nonnull NSNumber *)reactTag
+ northEast:(CLLocationCoordinate2D)northEast
+ southWest:(CLLocationCoordinate2D)southWest)
+{
+ [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
+ id view = viewRegistry[reactTag];
+ if (![view isKindOfClass:[AIRGoogleMap class]]) {
+ RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
+ } else {
+ AIRGoogleMap *mapView = (AIRGoogleMap *)view;
+
+ GMSCoordinateBounds *bounds = [[GMSCoordinateBounds alloc] initWithCoordinate:northEast coordinate:southWest];
+
+ mapView.cameraTargetBounds = bounds;
+ }
+ }];
+}
+
+- (NSDictionary *)constantsToExport {
+ return @{ @"legalNotice": [GMSServices openSourceLicenseInfo] };
+}
+
+- (void)mapViewDidStartTileRendering:(GMSMapView *)mapView {
+ if (didCallOnMapReady) return;
+ didCallOnMapReady = YES;
+
+ AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
+ [googleMapView didPrepareMap];
+}
- (BOOL)mapView:(GMSMapView *)mapView didTapMarker:(GMSMarker *)marker {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
return [googleMapView didTapMarker:marker];
}
+- (void)mapView:(GMSMapView *)mapView didTapOverlay:(GMSPolygon *)polygon {
+ AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
+ [googleMapView didTapPolygon:polygon];
+}
+
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
AIRGoogleMap *googleMapView = (AIRGoogleMap *)mapView;
[googleMapView didTapAtCoordinate:coordinate];
diff --git a/ios/AirGoogleMaps/AIRGoogleMapMarker.h b/lib/ios/AirGoogleMaps/AIRGoogleMapMarker.h
similarity index 88%
rename from ios/AirGoogleMaps/AIRGoogleMapMarker.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapMarker.h
index 8f1018b05..1cb4d2659 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapMarker.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapMarker.h
@@ -6,8 +6,8 @@
//
#import
+#import
#import "AIRGMSMarker.h"
-#import "RCTBridge.h"
#import "AIRGoogleMap.h"
#import "AIRGoogleMapCallout.h"
@@ -17,6 +17,7 @@
@property (nonatomic, strong) AIRGoogleMapCallout *calloutView;
@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, assign) CLLocationCoordinate2D coordinate;
+@property (nonatomic, assign) CLLocationDegrees rotation;
@property (nonatomic, strong) AIRGMSMarker* realMarker;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, copy) RCTDirectEventBlock onDragStart;
@@ -28,7 +29,9 @@
@property (nonatomic, strong) UIColor *pinColor;
@property (nonatomic, assign) CGPoint anchor;
@property (nonatomic, assign) NSInteger zIndex;
+@property (nonatomic, assign) double opacity;
@property (nonatomic, assign) BOOL draggable;
+@property (nonatomic, assign) BOOL tracksViewChanges;
- (void)showCalloutView;
- (void)hideCalloutView;
diff --git a/ios/AirGoogleMaps/AIRGoogleMapMarker.m b/lib/ios/AirGoogleMaps/AIRGoogleMapMarker.m
similarity index 94%
rename from ios/AirGoogleMaps/AIRGoogleMapMarker.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapMarker.m
index a3bbbffc0..42cf016a9 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapMarker.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapMarker.m
@@ -7,10 +7,10 @@
#import "AIRGoogleMapMarker.h"
#import
+#import
+#import
#import "AIRGMSMarker.h"
#import "AIRGoogleMapCallout.h"
-#import "RCTImageLoader.h"
-#import "RCTUtils.h"
#import "DummyView.h"
CGRect unionRect(CGRect a, CGRect b) {
@@ -36,6 +36,7 @@ - (instancetype)init
if ((self = [super init])) {
_realMarker = [[AIRGMSMarker alloc] init];
_realMarker.fakeMarker = self;
+ _realMarker.tracksViewChanges = true;
}
return self;
}
@@ -157,6 +158,14 @@ - (CLLocationCoordinate2D)coordinate {
return _realMarker.position;
}
+- (void)setRotation:(CLLocationDegrees)rotation {
+ _realMarker.rotation = rotation;
+}
+
+- (CLLocationDegrees)rotation {
+ return _realMarker.rotation;
+}
+
- (void)setIdentifier:(NSString *)identifier {
_realMarker.identifier = identifier;
}
@@ -173,6 +182,11 @@ - (RCTBubblingEventBlock)onPress {
return _realMarker.onPress;
}
+- (void)setOpacity:(double)opacity
+{
+ _realMarker.opacity = opacity;
+}
+
- (void)setImageSrc:(NSString *)imageSrc
{
_imageSrc = imageSrc;
@@ -186,14 +200,14 @@ - (void)setImageSrc:(NSString *)imageSrc
if (_iconImageView) [_iconImageView removeFromSuperview];
return;
}
-
+
if (!_iconImageView) {
// prevent glitch with marker (cf. https://github.com/airbnb/react-native-maps/issues/738)
UIImageView *empyImageView = [[UIImageView alloc] init];
_iconImageView = empyImageView;
[self iconViewInsertSubview:_iconImageView atIndex:0];
}
-
+
_reloadImageCancellationBlock = [_bridge.imageLoader loadImageWithURLRequest:[RCTConvert NSURLRequest:_imageSrc]
size:self.bounds.size
scale:RCTScreenScale()
@@ -282,4 +296,12 @@ - (BOOL)draggable {
return _realMarker.draggable;
}
+- (void)setTracksViewChanges:(BOOL)tracksViewChanges {
+ _realMarker.tracksViewChanges = tracksViewChanges;
+}
+
+- (BOOL)tracksViewChanges {
+ return _realMarker.tracksViewChanges;
+}
+
@end
diff --git a/ios/AirGoogleMaps/AIRGoogleMapMarkerManager.h b/lib/ios/AirGoogleMaps/AIRGoogleMapMarkerManager.h
similarity index 82%
rename from ios/AirGoogleMaps/AIRGoogleMapMarkerManager.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapMarkerManager.h
index 657f6b044..f2698dcd0 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapMarkerManager.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapMarkerManager.h
@@ -5,7 +5,7 @@
// Created by Gil Birman on 9/2/16.
//
-#import "RCTViewManager.h"
+#import
@interface AIRGoogleMapMarkerManager : RCTViewManager
diff --git a/ios/AirGoogleMaps/AIRGoogleMapMarkerManager.m b/lib/ios/AirGoogleMaps/AIRGoogleMapMarkerManager.m
similarity index 91%
rename from ios/AirGoogleMaps/AIRGoogleMapMarkerManager.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapMarkerManager.m
index ee138c25f..6b9c8f64b 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapMarkerManager.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapMarkerManager.m
@@ -8,8 +8,8 @@
#import "AIRGoogleMapMarkerManager.h"
#import "AIRGoogleMapMarker.h"
#import
-#import "RCTConvert+MapKit.h"
-#import "RCTUIManager.h"
+#import
+#import "RCTConvert+AirMap.h"
@implementation AIRGoogleMapMarkerManager
@@ -28,6 +28,7 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(identifier, NSString)
RCT_EXPORT_VIEW_PROPERTY(coordinate, CLLocationCoordinate2D)
+RCT_EXPORT_VIEW_PROPERTY(rotation, CLLocationDegrees)
RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
RCT_REMAP_VIEW_PROPERTY(image, imageSrc, NSString)
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
@@ -36,6 +37,8 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(anchor, CGPoint)
RCT_EXPORT_VIEW_PROPERTY(zIndex, NSInteger)
RCT_EXPORT_VIEW_PROPERTY(draggable, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(tracksViewChanges, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(opacity, double)
RCT_EXPORT_VIEW_PROPERTY(onDragStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDrag, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onDragEnd, RCTDirectEventBlock)
diff --git a/ios/AirGoogleMaps/AIRGoogleMapPolygon.h b/lib/ios/AirGoogleMaps/AIRGoogleMapPolygon.h
similarity index 56%
rename from ios/AirGoogleMaps/AIRGoogleMapPolygon.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapPolygon.h
index 26f0236d8..e7719ebee 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapPolygon.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapPolygon.h
@@ -5,17 +5,24 @@
//
#import
+#import
+#import "AIRGMSPolygon.h"
#import "AIRMapCoordinate.h"
@interface AIRGoogleMapPolygon : UIView
-@property (nonatomic, strong) GMSPolygon *polygon;
+@property (nonatomic, weak) RCTBridge *bridge;
+@property (nonatomic, strong) NSString *identifier;
+@property (nonatomic, strong) AIRGMSPolygon *polygon;
@property (nonatomic, strong) NSArray *coordinates;
+@property (nonatomic, strong) NSArray *> *holes;
+@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, assign) UIColor *fillColor;
@property (nonatomic, assign) double strokeWidth;
@property (nonatomic, assign) UIColor *strokeColor;
@property (nonatomic, assign) BOOL geodesic;
@property (nonatomic, assign) int zIndex;
+@property (nonatomic, assign) BOOL tappable;
@end
diff --git a/ios/AirGoogleMaps/AIRGoogleMapPolygon.m b/lib/ios/AirGoogleMaps/AIRGoogleMapPolygon.m
similarity index 58%
rename from ios/AirGoogleMaps/AIRGoogleMapPolygon.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapPolygon.m
index 8727cad37..bbd5d99c9 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapPolygon.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapPolygon.m
@@ -5,6 +5,7 @@
//
#import "AIRGoogleMapPolygon.h"
+#import "AIRGMSPolygon.h"
#import
@implementation AIRGoogleMapPolygon
@@ -12,7 +13,7 @@ @implementation AIRGoogleMapPolygon
- (instancetype)init
{
if (self = [super init]) {
- _polygon = [[GMSPolygon alloc] init];
+ _polygon = [[AIRGMSPolygon alloc] init];
}
return self;
@@ -31,6 +32,27 @@ - (void)setCoordinates:(NSArray *)coordinates
_polygon.path = path;
}
+- (void)setHoles:(NSArray *> *)holes
+{
+ _holes = holes;
+
+ if (holes.count)
+ {
+ NSMutableArray *interiorPolygons = [NSMutableArray array];
+ for(int h = 0; h < holes.count; h++)
+ {
+ GMSMutablePath *path = [GMSMutablePath path];
+ for(int i = 0; i < holes[h].count; i++)
+ {
+ [path addCoordinate:holes[h][i].coordinate];
+ }
+ [interiorPolygons addObject:path];
+ }
+
+ _polygon.holes = interiorPolygons;
+ }
+}
+
-(void)setFillColor:(UIColor *)fillColor
{
_fillColor = fillColor;
@@ -61,4 +83,14 @@ -(void)setZIndex:(int)zIndex
_polygon.zIndex = zIndex;
}
+-(void)setTappable:(BOOL)tappable
+{
+ _tappable = tappable;
+ _polygon.tappable = tappable;
+}
+
+- (void)setOnPress:(RCTBubblingEventBlock)onPress {
+ _polygon.onPress = onPress;
+}
+
@end
diff --git a/ios/AirGoogleMaps/AIRGoogleMapPolygonManager.h b/lib/ios/AirGoogleMaps/AIRGoogleMapPolygonManager.h
similarity index 81%
rename from ios/AirGoogleMaps/AIRGoogleMapPolygonManager.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapPolygonManager.h
index fd6040ca0..3380c61e3 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapPolygonManager.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapPolygonManager.h
@@ -4,7 +4,7 @@
// Created by Nick Italiano on 10/22/16.
//
-#import "RCTViewManager.h"
+#import
@interface AIRGoogleMapPolygonManager : RCTViewManager
diff --git a/ios/AirGoogleMaps/AIRGoogleMapPolygonManager.m b/lib/ios/AirGoogleMaps/AIRGoogleMapPolygonManager.m
similarity index 60%
rename from ios/AirGoogleMaps/AIRGoogleMapPolygonManager.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapPolygonManager.m
index 5e6c8d319..59e239627 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapPolygonManager.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapPolygonManager.m
@@ -5,13 +5,13 @@
//
#import "AIRGoogleMapPolygonManager.h"
-#import "RCTBridge.h"
-#import "RCTConvert.h"
-#import "RCTConvert+CoreLocation.h"
-#import "RCTConvert+MoreMapKit.h"
-#import "RCTEventDispatcher.h"
-#import "UIView+React.h"
-#import "RCTViewManager.h"
+#import
+#import
+#import
+#import
+#import
+#import
+#import "RCTConvert+AirMap.h"
#import "AIRGoogleMapPolygon.h"
@interface AIRGoogleMapPolygonManager()
@@ -25,14 +25,18 @@ @implementation AIRGoogleMapPolygonManager
- (UIView *)view
{
AIRGoogleMapPolygon *polygon = [AIRGoogleMapPolygon new];
+ polygon.bridge = self.bridge;
return polygon;
}
RCT_EXPORT_VIEW_PROPERTY(coordinates, AIRMapCoordinateArray)
+RCT_EXPORT_VIEW_PROPERTY(holes, AIRMapCoordinateArrayArray)
RCT_EXPORT_VIEW_PROPERTY(fillColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, double)
RCT_EXPORT_VIEW_PROPERTY(strokeColor, UIColor)
RCT_EXPORT_VIEW_PROPERTY(geodesic, BOOL)
RCT_EXPORT_VIEW_PROPERTY(zIndex, int)
+RCT_EXPORT_VIEW_PROPERTY(tappable, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
@end
diff --git a/ios/AirGoogleMaps/AIRGoogleMapPolyline.h b/lib/ios/AirGoogleMaps/AIRGoogleMapPolyline.h
similarity index 65%
rename from ios/AirGoogleMaps/AIRGoogleMapPolyline.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapPolyline.h
index b127567a5..adebc40d6 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapPolyline.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapPolyline.h
@@ -5,18 +5,25 @@
//
#import
#import
+#import
+#import "AIRGMSPolyline.h"
#import "AIRMapCoordinate.h"
#import "AIRGoogleMapMarker.h"
@interface AIRGoogleMapPolyline : UIView
-@property (nonatomic, strong) GMSPolyline* polyline;
+@property (nonatomic, weak) RCTBridge *bridge;
+@property (nonatomic, strong) NSString *identifier;
+@property (nonatomic, strong) AIRGMSPolyline *polyline;
@property (nonatomic, strong) NSArray *coordinates;
+@property (nonatomic, copy) RCTBubblingEventBlock onPress;
+
@property (nonatomic, strong) UIColor *strokeColor;
@property (nonatomic, assign) double strokeWidth;
@property (nonatomic, assign) UIColor *fillColor;
@property (nonatomic, assign) BOOL geodesic;
@property (nonatomic, assign) NSString *title;
@property (nonatomic, assign) int zIndex;
+@property (nonatomic, assign) BOOL tappable;
@end
diff --git a/ios/AirGoogleMaps/AIRGoogleMapPolyline.m b/lib/ios/AirGoogleMaps/AIRGoogleMapPolyline.m
similarity index 82%
rename from ios/AirGoogleMaps/AIRGoogleMapPolyline.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapPolyline.m
index c55621e97..881f17be6 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapPolyline.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapPolyline.m
@@ -5,18 +5,19 @@
//
#import
#import "AIRGoogleMapPolyline.h"
+#import "AIRGMSPolyline.h"
#import "AIRMapCoordinate.h"
#import "AIRGoogleMapMarker.h"
#import "AIRGoogleMapMarkerManager.h"
#import
-#import "RCTUtils.h"
+#import
@implementation AIRGoogleMapPolyline
- (instancetype)init
{
if (self = [super init]) {
- _polyline = [[GMSPolyline alloc] init];
+ _polyline = [[AIRGMSPolyline alloc] init];
}
return self;
}
@@ -24,13 +25,13 @@ - (instancetype)init
-(void)setCoordinates:(NSArray *)coordinates
{
_coordinates = coordinates;
-
+
GMSMutablePath *path = [GMSMutablePath path];
for(int i = 0; i < coordinates.count; i++)
{
[path addCoordinate:coordinates[i].coordinate];
}
-
+
_polyline.path = path;
}
@@ -70,4 +71,14 @@ -(void) setZIndex:(int)zIndex
_polyline.zIndex = zIndex;
}
+-(void)setTappable:(BOOL)tappable
+{
+ _tappable = tappable;
+ _polyline.tappable = tappable;
+}
+
+- (void)setOnPress:(RCTBubblingEventBlock)onPress {
+ _polyline.onPress = onPress;
+}
+
@end
diff --git a/ios/AirGoogleMaps/AIRGoogleMapPolylineManager.h b/lib/ios/AirGoogleMaps/AIRGoogleMapPolylineManager.h
similarity index 81%
rename from ios/AirGoogleMaps/AIRGoogleMapPolylineManager.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapPolylineManager.h
index 48aaf8527..82e7b8e20 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapPolylineManager.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapPolylineManager.h
@@ -4,7 +4,7 @@
// Created by Nick Italiano on 10/22/16.
//
-#import "RCTViewManager.h"
+#import
@interface AIRGoogleMapPolylineManager : RCTViewManager
diff --git a/ios/AirGoogleMaps/AIRGoogleMapPolylineManager.m b/lib/ios/AirGoogleMaps/AIRGoogleMapPolylineManager.m
similarity index 64%
rename from ios/AirGoogleMaps/AIRGoogleMapPolylineManager.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapPolylineManager.m
index 68817b138..a7515c207 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapPolylineManager.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapPolylineManager.m
@@ -6,13 +6,13 @@
#import "AIRGoogleMapPolylineManager.h"
-#import "RCTBridge.h"
-#import "RCTConvert.h"
-#import "RCTConvert+CoreLocation.h"
-#import "RCTConvert+MoreMapKit.h"
-#import "RCTEventDispatcher.h"
-#import "UIView+React.h"
-#import "RCTViewManager.h"
+#import
+#import
+#import
+#import
+#import
+#import
+#import "RCTConvert+AirMap.h"
#import "AIRGoogleMapPolyline.h"
@interface AIRGoogleMapPolylineManager()
@@ -26,6 +26,7 @@ @implementation AIRGoogleMapPolylineManager
- (UIView *)view
{
AIRGoogleMapPolyline *polyline = [AIRGoogleMapPolyline new];
+ polyline.bridge = self.bridge;
return polyline;
}
@@ -35,5 +36,7 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(strokeWidth, double)
RCT_EXPORT_VIEW_PROPERTY(geodesic, BOOL)
RCT_EXPORT_VIEW_PROPERTY(zIndex, int)
+RCT_EXPORT_VIEW_PROPERTY(tappable, BOOL)
+RCT_EXPORT_VIEW_PROPERTY(onPress, RCTBubblingEventBlock)
@end
diff --git a/ios/AirGoogleMaps/AIRGoogleMapURLTileManager.m b/lib/ios/AirGoogleMaps/AIRGoogleMapURLTileManager.m
similarity index 100%
rename from ios/AirGoogleMaps/AIRGoogleMapURLTileManager.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapURLTileManager.m
diff --git a/ios/AirGoogleMaps/AIRGoogleMapUrlTile.h b/lib/ios/AirGoogleMaps/AIRGoogleMapUrlTile.h
similarity index 100%
rename from ios/AirGoogleMaps/AIRGoogleMapUrlTile.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapUrlTile.h
diff --git a/ios/AirGoogleMaps/AIRGoogleMapUrlTile.m b/lib/ios/AirGoogleMaps/AIRGoogleMapUrlTile.m
similarity index 100%
rename from ios/AirGoogleMaps/AIRGoogleMapUrlTile.m
rename to lib/ios/AirGoogleMaps/AIRGoogleMapUrlTile.m
diff --git a/ios/AirGoogleMaps/AIRGoogleMapUrlTileManager.h b/lib/ios/AirGoogleMaps/AIRGoogleMapUrlTileManager.h
similarity index 84%
rename from ios/AirGoogleMaps/AIRGoogleMapUrlTileManager.h
rename to lib/ios/AirGoogleMaps/AIRGoogleMapUrlTileManager.h
index 3554837d4..affd718b4 100644
--- a/ios/AirGoogleMaps/AIRGoogleMapUrlTileManager.h
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapUrlTileManager.h
@@ -4,7 +4,7 @@
//
#import
-#import "RCTViewManager.h"
+#import
@interface AIRGoogleMapUrlTileManager : RCTViewManager
@end
diff --git a/ios/AirGoogleMaps/DummyView.h b/lib/ios/AirGoogleMaps/DummyView.h
similarity index 100%
rename from ios/AirGoogleMaps/DummyView.h
rename to lib/ios/AirGoogleMaps/DummyView.h
diff --git a/ios/AirGoogleMaps/DummyView.m b/lib/ios/AirGoogleMaps/DummyView.m
similarity index 100%
rename from ios/AirGoogleMaps/DummyView.m
rename to lib/ios/AirGoogleMaps/DummyView.m
diff --git a/ios/AirGoogleMaps/RCTConvert+GMSMapViewType.h b/lib/ios/AirGoogleMaps/RCTConvert+GMSMapViewType.h
similarity index 87%
rename from ios/AirGoogleMaps/RCTConvert+GMSMapViewType.h
rename to lib/ios/AirGoogleMaps/RCTConvert+GMSMapViewType.h
index a753f4331..7e02d66a0 100644
--- a/ios/AirGoogleMaps/RCTConvert+GMSMapViewType.h
+++ b/lib/ios/AirGoogleMaps/RCTConvert+GMSMapViewType.h
@@ -6,7 +6,7 @@
#import
#import
-#import "RCTConvert.h"
+#import
@interface RCTConvert (GMSMapViewType)
diff --git a/ios/AirGoogleMaps/RCTConvert+GMSMapViewType.m b/lib/ios/AirGoogleMaps/RCTConvert+GMSMapViewType.m
similarity index 85%
rename from ios/AirGoogleMaps/RCTConvert+GMSMapViewType.m
rename to lib/ios/AirGoogleMaps/RCTConvert+GMSMapViewType.m
index 42053fb1d..cfceba559 100644
--- a/ios/AirGoogleMaps/RCTConvert+GMSMapViewType.m
+++ b/lib/ios/AirGoogleMaps/RCTConvert+GMSMapViewType.m
@@ -6,13 +6,14 @@
#import "RCTConvert+GMSMapViewType.h"
#import
-#import "RCTConvert.h"
+#import
@implementation RCTConvert (GMSMapViewType)
RCT_ENUM_CONVERTER(GMSMapViewType,
(
@{
@"standard": @(kGMSTypeNormal),
+ @"satellite": @(kGMSTypeSatellite),
@"hybrid": @(kGMSTypeHybrid),
@"terrain": @(kGMSTypeTerrain),
@"none": @(kGMSTypeNone)
diff --git a/ios/AirMaps.xcodeproj/project.pbxproj b/lib/ios/AirMaps.xcodeproj/project.pbxproj
similarity index 95%
rename from ios/AirMaps.xcodeproj/project.pbxproj
rename to lib/ios/AirMaps.xcodeproj/project.pbxproj
index 4be12b6bc..ac641aff7 100644
--- a/ios/AirMaps.xcodeproj/project.pbxproj
+++ b/lib/ios/AirMaps.xcodeproj/project.pbxproj
@@ -20,8 +20,8 @@
1125B2E41C4AD3DA007D0023 /* AIRMapPolygonManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2D21C4AD3DA007D0023 /* AIRMapPolygonManager.m */; };
1125B2E51C4AD3DA007D0023 /* AIRMapPolyline.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2D41C4AD3DA007D0023 /* AIRMapPolyline.m */; };
1125B2E61C4AD3DA007D0023 /* AIRMapPolylineManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2D61C4AD3DA007D0023 /* AIRMapPolylineManager.m */; };
- 1125B2E71C4AD3DA007D0023 /* RCTConvert+MoreMapKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2D91C4AD3DA007D0023 /* RCTConvert+MoreMapKit.m */; };
1125B2F21C4AD445007D0023 /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1125B2F11C4AD445007D0023 /* SMCalloutView.m */; };
+ 19DABC7F1E7C9D3C00F41150 /* RCTConvert+AirMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 19DABC7E1E7C9D3C00F41150 /* RCTConvert+AirMap.m */; };
DA6C26381C9E2AFE0035349F /* AIRMapUrlTile.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6C26371C9E2AFE0035349F /* AIRMapUrlTile.m */; };
DA6C263E1C9E324A0035349F /* AIRMapUrlTileManager.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6C263D1C9E324A0035349F /* AIRMapUrlTileManager.m */; };
/* End PBXBuildFile section */
@@ -65,11 +65,11 @@
1125B2D41C4AD3DA007D0023 /* AIRMapPolyline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapPolyline.m; path = AirMaps/AIRMapPolyline.m; sourceTree = SOURCE_ROOT; };
1125B2D51C4AD3DA007D0023 /* AIRMapPolylineManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AIRMapPolylineManager.h; path = AirMaps/AIRMapPolylineManager.h; sourceTree = SOURCE_ROOT; };
1125B2D61C4AD3DA007D0023 /* AIRMapPolylineManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AIRMapPolylineManager.m; path = AirMaps/AIRMapPolylineManager.m; sourceTree = SOURCE_ROOT; };
- 1125B2D81C4AD3DA007D0023 /* RCTConvert+MoreMapKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "RCTConvert+MoreMapKit.h"; path = "AirMaps/RCTConvert+MoreMapKit.h"; sourceTree = SOURCE_ROOT; };
- 1125B2D91C4AD3DA007D0023 /* RCTConvert+MoreMapKit.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "RCTConvert+MoreMapKit.m"; path = "AirMaps/RCTConvert+MoreMapKit.m"; sourceTree = SOURCE_ROOT; };
1125B2F01C4AD445007D0023 /* SMCalloutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SMCalloutView.h; path = AirMaps/Callout/SMCalloutView.h; sourceTree = SOURCE_ROOT; };
1125B2F11C4AD445007D0023 /* SMCalloutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SMCalloutView.m; path = AirMaps/Callout/SMCalloutView.m; sourceTree = SOURCE_ROOT; };
11FA5C511C4A1296003AC2EE /* libAirMaps.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libAirMaps.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ 19DABC7D1E7C9D3C00F41150 /* RCTConvert+AirMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "RCTConvert+AirMap.h"; sourceTree = ""; };
+ 19DABC7E1E7C9D3C00F41150 /* RCTConvert+AirMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "RCTConvert+AirMap.m"; sourceTree = ""; };
DA6C26361C9E2AFE0035349F /* AIRMapUrlTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapUrlTile.h; sourceTree = ""; };
DA6C26371C9E2AFE0035349F /* AIRMapUrlTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AIRMapUrlTile.m; sourceTree = ""; };
DA6C263C1C9E324A0035349F /* AIRMapUrlTileManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AIRMapUrlTileManager.h; sourceTree = ""; };
@@ -132,11 +132,10 @@
1125B2D31C4AD3DA007D0023 /* AIRMapPolyline.h */,
1125B2D51C4AD3DA007D0023 /* AIRMapPolylineManager.h */,
1125B2D61C4AD3DA007D0023 /* AIRMapPolylineManager.m */,
- 21B6E2D21D99B886007E664F /* AIRMapSnapshot.h */,
1125B2F01C4AD445007D0023 /* SMCalloutView.h */,
1125B2F11C4AD445007D0023 /* SMCalloutView.m */,
- 1125B2D81C4AD3DA007D0023 /* RCTConvert+MoreMapKit.h */,
- 1125B2D91C4AD3DA007D0023 /* RCTConvert+MoreMapKit.m */,
+ 19DABC7D1E7C9D3C00F41150 /* RCTConvert+AirMap.h */,
+ 19DABC7E1E7C9D3C00F41150 /* RCTConvert+AirMap.m */,
DA6C26361C9E2AFE0035349F /* AIRMapUrlTile.h */,
DA6C26371C9E2AFE0035349F /* AIRMapUrlTile.m */,
DA6C263C1C9E324A0035349F /* AIRMapUrlTileManager.h */,
@@ -207,10 +206,10 @@
1125B2E01C4AD3DA007D0023 /* AIRMapManager.m in Sources */,
1125B2E61C4AD3DA007D0023 /* AIRMapPolylineManager.m in Sources */,
1125B2DD1C4AD3DA007D0023 /* AIRMapCircle.m in Sources */,
+ 19DABC7F1E7C9D3C00F41150 /* RCTConvert+AirMap.m in Sources */,
1125B2E51C4AD3DA007D0023 /* AIRMapPolyline.m in Sources */,
DA6C263E1C9E324A0035349F /* AIRMapUrlTileManager.m in Sources */,
1125B2DA1C4AD3DA007D0023 /* AIRMap.m in Sources */,
- 1125B2E71C4AD3DA007D0023 /* RCTConvert+MoreMapKit.m in Sources */,
1125B2DF1C4AD3DA007D0023 /* AIRMapCoordinate.m in Sources */,
1125B2F21C4AD445007D0023 /* SMCalloutView.m in Sources */,
1125B2E11C4AD3DA007D0023 /* AIRMapMarker.m in Sources */,
diff --git a/ios/AirMaps/AIRMap.h b/lib/ios/AirMaps/AIRMap.h
similarity index 88%
rename from ios/AirMaps/AIRMap.h
rename to lib/ios/AirMaps/AIRMap.h
index 6b061fe42..1d5f92cdc 100644
--- a/ios/AirMaps/AIRMap.h
+++ b/lib/ios/AirMaps/AIRMap.h
@@ -10,13 +10,14 @@
#import
#import
-#import "RCTConvert+MapKit.h"
-#import "RCTComponent.h"
+#import
#import "SMCalloutView.h"
+#import "RCTConvert+AirMap.h"
extern const CLLocationDegrees AIRMapDefaultSpan;
extern const NSTimeInterval AIRMapRegionChangeObserveInterval;
extern const CGFloat AIRMapZoomBoundBuffer;
+extern const NSInteger AIRMapMaxZoomLevel;
@interface AIRMap: MKMapView
@@ -24,6 +25,7 @@ extern const CGFloat AIRMapZoomBoundBuffer;
@property (nonatomic, strong) UIImageView *cacheImageView;
@property (nonatomic, strong) UIView *loadingView;
+@property (nonatomic, copy) NSString *userLocationAnnotationTitle;
@property (nonatomic, assign) BOOL followUserLocation;
@property (nonatomic, assign) BOOL hasStartedRendering;
@property (nonatomic, assign) BOOL cacheEnabled;
@@ -36,6 +38,8 @@ extern const CGFloat AIRMapZoomBoundBuffer;
@property (nonatomic, assign) UIEdgeInsets legalLabelInsets;
@property (nonatomic, strong) NSTimer *regionChangeObserveTimer;
@property (nonatomic, assign) MKCoordinateRegion initialRegion;
+@property (nonatomic, assign) CGFloat minZoomLevel;
+@property (nonatomic, assign) CGFloat maxZoomLevel;
@property (nonatomic, assign) CLLocationCoordinate2D pendingCenter;
@property (nonatomic, assign) MKCoordinateSpan pendingSpan;
@@ -43,6 +47,7 @@ extern const CGFloat AIRMapZoomBoundBuffer;
@property (nonatomic, assign) BOOL ignoreRegionChanges;
+@property (nonatomic, copy) RCTBubblingEventBlock onMapReady;
@property (nonatomic, copy) RCTBubblingEventBlock onChange;
@property (nonatomic, copy) RCTBubblingEventBlock onPress;
@property (nonatomic, copy) RCTBubblingEventBlock onPanDrag;
diff --git a/ios/AirMaps/AIRMap.m b/lib/ios/AirMaps/AIRMap.m
similarity index 90%
rename from ios/AirMaps/AIRMap.m
rename to lib/ios/AirMaps/AIRMap.m
index 9efe1b4aa..647be4b8a 100644
--- a/ios/AirMaps/AIRMap.m
+++ b/lib/ios/AirMaps/AIRMap.m
@@ -9,9 +9,9 @@
#import "AIRMap.h"
-#import "RCTEventDispatcher.h"
+#import
+#import
#import "AIRMapMarker.h"
-#import "UIView+React.h"
#import "AIRMapPolyline.h"
#import "AIRMapPolygon.h"
#import "AIRMapCircle.h"
@@ -21,6 +21,7 @@
const CLLocationDegrees AIRMapDefaultSpan = 0.005;
const NSTimeInterval AIRMapRegionChangeObserveInterval = 0.1;
const CGFloat AIRMapZoomBoundBuffer = 0.01;
+const NSInteger AIRMapMaxZoomLevel = 20;
@interface MKMapView (UIGestureRecognizer)
@@ -79,6 +80,9 @@ - (instancetype)init
// be identical to the built-in callout view (which has a private API)
self.calloutView = [SMCalloutView platformCalloutView];
self.calloutView.delegate = self;
+
+ self.minZoomLevel = 0;
+ self.maxZoomLevel = AIRMapMaxZoomLevel;
}
return self;
}
@@ -104,7 +108,13 @@ - (void)insertReactSubview:(id)subview atIndex:(NSInteger)atIndex
} else if ([subview isKindOfClass:[AIRMapCircle class]]) {
[self addOverlay:(id)subview];
} else if ([subview isKindOfClass:[AIRMapUrlTile class]]) {
+ ((AIRMapUrlTile *)subview).map = self;
[self addOverlay:(id)subview];
+ } else {
+ NSArray> *childSubviews = [subview reactSubviews];
+ for (int i = 0; i < childSubviews.count; i++) {
+ [self insertReactSubview:(UIView *)childSubviews[i] atIndex:atIndex];
+ }
}
[_reactSubviews insertObject:(UIView *)subview atIndex:(NSUInteger) atIndex];
}
@@ -125,6 +135,11 @@ - (void)removeReactSubview:(id)subview {
[self removeOverlay:(id