diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 34541f1a9..000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,2 +0,0 @@
-index.d.ts
-scripts/
diff --git a/.eslintrc.js b/.eslintrc.js
index c86edfece..02fc5cede 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,7 +1,7 @@
module.exports = {
root: true,
- parser: 'babel-eslint',
- plugins: ['react', 'react-native', 'prettier', 'fp', 'import'],
+ parser: '@babel/eslint-parser',
+ plugins: ['react', 'react-native', 'import'],
env: {
jest: true,
},
@@ -38,8 +38,9 @@ module.exports = {
extends: [
'eslint:recommended',
'plugin:react/recommended',
- 'prettier',
+ 'plugin:jest/recommended',
'@react-native-community',
+ 'prettier',
],
rules: {
'react/no-deprecated': 'warn',
@@ -59,7 +60,7 @@ module.exports = {
'no-console': [0],
'import/prefer-default-export': 'off',
'jsx-a11y/href-no-hash': 'off',
- 'react/prop-types': [2],
+ 'react/prop-types': [0],
quotes: [2, 'single'],
'eol-last': [0],
'no-continue': [1],
@@ -73,17 +74,38 @@ module.exports = {
'no-underscore-dangle': [0],
'no-await-in-loop': 0,
'no-restricted-syntax': 0,
- 'no-use-before-define': ['error', {functions: false}],
- 'no-unused-expressions': ['error', {allowTaggedTemplates: true}],
- 'no-plusplus': ['error', {allowForLoopAfterthoughts: true}],
- 'prettier/prettier': [
- 'error',
- {
- singleQuote: true,
- trailingComma: 'all',
- bracketSpacing: false,
- },
- ],
- 'fp/no-mutating-methods': 'warn',
+ 'no-use-before-define': ['error', { functions: false }],
+ 'no-unused-expressions': ['error', { allowTaggedTemplates: true }],
+ 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }],
+ 'react-native/no-inline-styles': 0,
+ '@typescript-eslint/no-explicit-any': ['error', { ignoreRestArgs: true }],
},
+ ignorePatterns: ['**/rnmapbox.web.symlink', 'plugin/build/'],
+ overrides: [
+ {
+ // Match TypeScript Files
+ files: ['**/*.{ts,tsx}'],
+
+ parserOptions: {
+ project: [
+ './tsconfig.json',
+ './example/tsconfig.json',
+ './plugin/src/__tests__/tsconfig.eslint.json',
+ ],
+ },
+ plugins: ['@typescript-eslint'],
+ extends: [
+ 'eslint:recommended',
+ 'plugin:react/recommended',
+ '@react-native-community',
+ 'plugin:@typescript-eslint/recommended',
+ 'prettier',
+ ],
+ rules: {
+ 'no-shadow': 'off',
+ 'import/named': 'off',
+ 'react-native/no-inline-styles': 0,
+ },
+ },
+ ],
};
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 519f9eec5..000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,94 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: ''
-labels: ''
-assignees: ''
-
----
-
-🚨🚨🚨
-* Please respect and fill out the issue template
-* Before you report, please make sure you tested on a physical device
-* For build issues: Can you reproduce it on a clean install of the example app? Please include full steps to reproduce from `react-native init`
-* Please include standalone code sample - a single component with one MapView in it. Use [one of our example](https://github.com/react-native-mapbox-gl/maps/blob/master/example/src/examples/PointInMapView.js) screens as a starging point.
-* Use gitter and/or stack overflow for questions.
-
-If you want others to spend time on your issue, please make sure to first spend some time on the ticket.
-
-Not following the above will lead to the ticket being closed.
-Thanks for understanding. Please understand that the project is run by volunteers on their own free time.
-
-🚨🚨🚨
-
-
-
-**Describe the bug**
-A clear and concise description of what the bug is.
-
-**To Reproduce**
-Steps to reproduce the behavior.
-
-Please include a single standalone React Native component. Use [one of our example](https://github.com/react-native-mapbox-gl/maps/blob/master/example/src/examples/BugReportTemplate.js) screens as a starting point.
-Please simplify the example as much as possible.
-
-Example:
-```js
-import React from 'react';
-import {
- MapView,
- ShapeSource,
- LineLayer,
- Camera,
-} from '@react-native-mapbox-gl/maps';
-
-const aLine = {
- type: 'LineString',
- coordinates: [
- [-74.00597, 40.71427],
- [-74.00697, 40.71527],
- ],
-};
-
-class BugReportExample extends React.Component {
- render() {
- return (
-
-
-
-
-
-
- );
- }
-}
-```
-
-If it's a build/startup issue please include full steps to reproduce from `react-native init ...`
-
-Example:
-
-```sh
-react-native init sample --version react-native@0.60.5
-cd sample
-npm install react-native-mapbox-gl/maps#master --save
-# or released version `npm install @react-native-mapbox-gl/maps@8.0.0-rc1 --save`
-react-native run-android
-```
-
-**Expected behavior**
-A clear and concise description of what you expected to happen.
-
-**Screenshots**
-If applicable, add screenshots to help explain your problem.
-
-**Versions (please complete the following information):**
- - Platform: [e.g. Android, iOS]
- - Device: [e.g. iPhone6]
- - Emulator/ Simulator: [yes/ no]
- - OS: [e.g. iOS8.1]
- - react-native-mapbox-gl Version [e.g. 7.0.9]
- - React Native Version [e.g. 0.59]
-
-**Additional context**
-Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 000000000..dc38b4da7
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,112 @@
+name: Bug Report
+description: This template should be used for reporting bugs and defects.
+title: "[Bug]: "
+labels: 'bug :beetle:'
+body:
+- type: markdown
+ attributes:
+ value: |
+ Thanks for taking the time to fill out this bug report!
+- type: dropdown
+ id: mapbox-implementation
+ attributes:
+ label: Mapbox Implementation
+ description: |-
+ Check `RNMapboxMapsImpl` in your Podfile/gradle files. Defaults to `Maplibre`.
+ options:
+ - Mapbox
+ - Mapbox GL
+ - Maplibre
+ validations:
+ required: true
+- type: input
+ id: mapbox-version
+ attributes:
+ label: Mapbox Version
+ description: |-
+ Check `RNMapboxMapsVersion` in your Podfile/gradle files, set to `default` if you don't cusomize the version
+ placeholder: 10.7.0
+ validations:
+ required: true
+- type: dropdown
+ id: platform
+ attributes:
+ label: Platform
+ multiple: true
+ description: |-
+ The platform where you experience the issue
+ options:
+ - iOS
+ - Android
+ validations:
+ required: true
+- type: input
+ id: rnmapbox-version
+ attributes:
+ label: "`@rnmapbox/maps` version"
+ description: |-
+ The version of `@rnmapbox/maps`, such as `#main`, `10.0.0-beta.32`
+ value: 10.0.0-beta.11
+ validations:
+ required: true
+- type: textarea
+ attributes:
+ label: Standalone component to reproduce
+ description: |-
+ - Use [our BugReportTemplate](https://github.com/rnmapbox/maps/blob/main/example/src/examples/BugReportExample.js) screens as a starting point.
+ - Component should be self contained - no extra libraries, external data, no parameters
+ - Do not include setAccessToken or access token istelf.
+ value: |-
+ ```javascript
+ import React from 'react';
+ import {
+ MapView,
+ ShapeSource,
+ LineLayer,
+ Camera,
+ } from '@rnmapbox/maps';
+
+ const aLine = {
+ type: 'LineString',
+ coordinates: [
+ [-74.00597, 40.71427],
+ [-74.00697, 40.71527],
+ ],
+ };
+
+ class BugReportExample extends React.Component {
+ render() {
+ return (
+
+
+
+
+
+
+ );
+ }
+ }
+ ```
+ validations:
+ required: true
+- type: textarea
+ attributes:
+ label: Observed behavior and steps to reproduce
+ description: |-
+ - Please include as much evidence as possible (traces, videos, screenshots etc.)
+- type: textarea
+ attributes:
+ label: Expected behavior
+ description: |-
+ - Please include the expected behavior and any resources supporting this expected behavior.
+- type: textarea
+ attributes:
+ label: Notes / preliminary analysis
+ description: |-
+ - include your initial analysis, if available
+- type: textarea
+ attributes:
+ label: Additional links and references
+ description: |-
+ - Links to traces, videos et
+
diff --git a/.github/ISSUE_TEMPLATE/bug_setup.md b/.github/ISSUE_TEMPLATE/bug_setup.md
new file mode 100644
index 000000000..5e4f52857
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_setup.md
@@ -0,0 +1,23 @@
+---
+name: Setup/installation error
+about: This template should be used for reporting bugs and defects with project setup
+labels: 'bug-setup :beetle:'
+assignees: ''
+---
+
+
+## Environment
+- Dev OS: [e.g. OSX 11.0.1, Win10]
+
+## Steps to reproduce
+
+
+
+```sh
+react-native init sample --version react-native@0.60.5
+cd sample
+npm install rnmapbox/maps#main --save
+# or released version `npm install @rnmapbox/maps@8.0.0-rc1 --save`
+react-native run-android
+```
+
diff --git a/.github/ISSUE_TEMPLATE/feature.md b/.github/ISSUE_TEMPLATE/feature.md
new file mode 100644
index 000000000..7cd3c47c0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature.md
@@ -0,0 +1,15 @@
+---
+name: Feature Request
+about: To request a new feature, please provide detail on the outcome desired, solutions attempted and any suggested approaches.
+title: ''
+labels: 'feature :green apple:'
+assignees: ''
+
+---
+
+## New Feature
+<- Description of the feature being requested and any outcomes desired, an example use case, and any suggestions for solution ->
+
+## Why
+<- 1-2 sentence description of why you're requesting this feature. What problem does it solve? Why is it valuable? ->
+
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..87169ee47
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,42 @@
+version: 2
+updates:
+ # root
+ - package-ecosystem: "npm"
+ directory: "/"
+ schedule:
+ interval: "monthly"
+ labels:
+ - "🤖 dependabot 🤖"
+ open-pull-requests-limit: 1
+ pull-request-branch-name:
+ separator: "-"
+ ignore: # ignore updates for react-native deps, think about updating, once react-native is updated
+ - dependency-name: "@babel/core"
+ - dependency-name: "@babel/runtime"
+ - dependency-name: "@react-native-community/eslint-config"
+ - dependency-name: "eslint"
+ - dependency-name: "jest"
+ - dependency-name: "metro-react-native-babel-preset"
+ - dependency-name: "react-test-renderer"
+ - dependency-name: "react"
+ - dependency-name: "react-native"
+ - dependency-name: "jest-cli"
+ # example
+ - package-ecosystem: "npm"
+ directory: "/example"
+ schedule:
+ interval: "monthly"
+ labels:
+ - "🤖 dependabot 🤖"
+ open-pull-requests-limit: 1
+ pull-request-branch-name:
+ separator: "-"
+ # gh-actions workflow files
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "monthly"
+ pull-request-branch-name:
+ separator: "-"
+ labels:
+ - "🤖 dependabot 🤖"
diff --git a/.github/label-actions.yml b/.github/label-actions.yml
index 6d30136cf..67e655920 100644
--- a/.github/label-actions.yml
+++ b/.github/label-actions.yml
@@ -1,15 +1,26 @@
# Configuration for Label Actions - https://github.com/dessant/label-actions
+"Needs: Issue Template":
+ comment: >
+ :wave: @{issue-author}, please respect our issue template
required fields are missing.
+ # Close the issue
+ close: true
+"Needs: Standalone component":
+ comment: >
+ :wave: @{issue-author}, please include a [complete, isolated example](https://github.com/rnmapbox/maps/wiki/Issue-missing-standalone-component)
+ # Close the issue
+ close: true
+"question":
+ comment: >
+ :thinking: @{issue-author}, this is rather a question than an issue
please use our [discussions](https://github.com/rnmapbox/maps/discussions) or [gitter](https://gitter.im/rnmapbox/Lobby) or stackoverflow for this.
+ # Close the issue
+ close: true
+"stale":
+ comment: >
+ :thinking: @{issue-author}, closing the issue for lack of activity, if the issue still persist, pls open a new one with steps to reproduce on recent versions
+ # Close the issue
+ close: true
+"Needs: Project setup instructions":
+ comment: >
+ @{issue-author}, sorry for us to look into project setup issues, we require steps to reproduce from `react-native init ...`. If you cannot reproduce starting with a blank project, then compare your setup with a blank working one.
+ close: true
-issues:
- actions:
- # our issue template is not respected - required fields are missing
- "Needs: Issue Template":
- comment: >
- :wave: @{issue-author}, please respect our issue template
required fields are missing.
- # Close the issue
- close: true
- "question":
- comment: >
- :thinking: @{issue-author}, this is rather a question than an issue
please use our [gitter](https://gitter.im/react-native-mapbox-gl/Lobby) or stackoverflow for this.
- # Close the issue
- close: true
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 000000000..d4aa7a51b
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,26 @@
+
+
+## Description
+
+Fixes #
+
+
+
+Added `your feature` that allows ...
+
+## Checklist
+
+
+
+- [ ] I have tested this on a device/simulator for each compatible OS
+- [ ] I updated the documentation with running `yarn generate` in the root folder
+- [ ] I added/updated a sample - if a new feature was implemented (`/example`)
+
+## Screenshot OR Video
+
+
diff --git a/.github/workflows/android-actions.yml b/.github/workflows/android-actions.yml
new file mode 100644
index 000000000..4df74549f
--- /dev/null
+++ b/.github/workflows/android-actions.yml
@@ -0,0 +1,56 @@
+name: Android Build
+
+on:
+ workflow_call:
+ inputs:
+ NVMRC:
+ required: true
+ type: string
+ MAP_IMPL:
+ description: "The map implementation to use (mapbox,maplibre or mapbox-gl)"
+ default: mapbox
+ required: false
+ type: string
+ secrets:
+ MAPBOX_ACCESS_TOKEN:
+ required: true
+ MAPBOX_DOWNLOAD_TOKEN:
+ required: true
+
+jobs:
+ build_example:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Setup node ${{ inputs.NVMRC }}
+ uses: actions/setup-node@v3.6.0
+ with:
+ node-version: ${{ inputs.NVMRC }}
+
+ - name: Setup JDK zulu 11
+ uses: actions/setup-java@v3.6.0
+ with:
+ distribution: 'zulu'
+ java-version: '11'
+
+ - run: |
+ mkdir -p ~/.gradle/
+ echo MAPBOX_DOWNLOADS_TOKEN=$MAPBOX_DOWNLOAD_TOKEN > ~/.gradle/gradle.properties
+ working-directory: example
+ env:
+ MAPBOX_DOWNLOAD_TOKEN: ${{ secrets.MAPBOX_DOWNLOAD_TOKEN }}
+
+ - run: echo $MAPBOX_ACCESS_TOKEN > ./accesstoken
+ working-directory: example
+ env:
+ MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
+
+ - run: yarn install --network-timeout 1000000
+ working-directory: example
+
+ - run: ./gradlew assemble
+ working-directory: example/android
+ env:
+ CI_MAP_IMPL: ${{ inputs.MAP_IMPL }}
diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml
new file mode 100644
index 000000000..e3cea57fb
--- /dev/null
+++ b/.github/workflows/bump-version.yml
@@ -0,0 +1,55 @@
+# This is a basic workflow that is manually triggered
+
+name: Bump version
+
+# Controls when the action will run. Workflow runs when manually triggered using the UI
+# or API.
+on:
+ workflow_dispatch:
+ # Inputs the workflow accepts.
+ inputs:
+ version:
+ # Friendly description to be shown in the UI instead of 'name'
+ description: 'Semver type of new version (major / minor / patch)'
+ # Input has to be provided for the workflow to run
+ required: true
+ type: choice
+ options:
+ - patch
+ - minor
+ - major
+ - prerelease --preid=beta
+ - prerelease --preid=rc
+
+# A workflow run is made up of one or more jobs that can run sequentially or in parallel
+jobs:
+ # This workflow contains a single job called "bump-version"
+ bump-version:
+ # The type of runner that the job will run on
+ runs-on: ubuntu-latest
+
+ # Steps represent a sequence of tasks that will be executed as part of the job
+ steps:
+ # Check out the content (source branch). Use a deploy key so that
+ # when we push changes, it will trigger the release workflow
+ # run that runs on: tag. (Using the GitHub token would
+ # not run the workflow to prevent infinite recursion.)
+ - name: Check out source
+ uses: actions/checkout@v3
+ with:
+ ssh-key: ${{ secrets.DEPLOY_KEY }}
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v3.6.0
+ with:
+ node-version: '16'
+
+ - name: Setup Git
+ run: |
+ git config user.name 'RNMapbox robot'
+ git config user.email 'rnmapbox@gmail.com'
+ - name: bump version
+ run: npm version ${{ github.event.inputs.version }}
+
+ - name: Push latest version
+ run: git push origin main --follow-tags
diff --git a/.github/workflows/ios-actions.yml b/.github/workflows/ios-actions.yml
new file mode 100644
index 000000000..36a661cb8
--- /dev/null
+++ b/.github/workflows/ios-actions.yml
@@ -0,0 +1,98 @@
+name: iOS Build & Detox
+
+on:
+ workflow_call:
+ inputs:
+ NVMRC:
+ required: true
+ type: string
+ MAP_IMPL:
+ description: "The map implementation to use (mapbox,maplibre or mapbox-gl)"
+ default: mapbox
+ required: false
+ type: string
+ secrets:
+ MAPBOX_ACCESS_TOKEN:
+ required: true
+ MAPBOX_DOWNLOAD_TOKEN:
+ required: true
+
+jobs:
+ build:
+ runs-on: macos-12
+ timeout-minutes: 55
+
+ defaults:
+ run:
+ working-directory: ./example
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Access Token
+ run: echo $MAPBOX_ACCESS_TOKEN > ./accesstoken
+ env:
+ MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
+
+ - name: Setup .netrc with MAPBOX_DOWNLOAD_TOKEN
+ run: |
+ echo 'machine api.mapbox.com' >> ~/.netrc
+ echo 'login mapbox' >> ~/.netrc
+ echo "password $MAPBOX_DOWNLOAD_TOKEN" >> ~/.netrc
+ chmod 0600 ~/.netrc
+ if: "${{ env.MAPBOX_DOWNLOAD_TOKEN != '' }}"
+ env:
+ MAPBOX_DOWNLOAD_TOKEN: ${{ secrets.MAPBOX_DOWNLOAD_TOKEN }}
+
+ - name: Setup node ${{ inputs.NVMRC }}
+ uses: actions/setup-node@v3.6.0
+ with:
+ node-version: ${{ inputs.NVMRC }}
+
+ - name: Cache node_modules
+ uses: actions/cache@v3
+ id: yarn-cache
+ with:
+ path: node_modules
+ key: node-modules-${{ hashFiles('**/yarn.lock') }}
+
+ - name: Install Yarn Dependencies
+ if: steps.yarn-cache.outputs.cache-hit != 'true'
+ run: yarn install --network-timeout 1000000
+
+ - name: Cache Pods
+ uses: actions/cache@v3
+ id: pods-cache
+ with:
+ path: ios/Pods
+ key: pods-${{ hashFiles('**/Podfile.lock') }}
+
+ - name: Install Pod Dependencies
+ if: steps.pods-cache.outputs.cache-hit != 'true'
+ run: cd ios && pod --version && pod install
+ env:
+ CI_MAP_IMPL: ${{ inputs.MAP_IMPL }}
+
+ - name: Install Detox Dependencies
+ run: |
+ brew tap wix/brew
+ brew install applesimutils
+ brew install xcbeautify
+
+ - name: Build for detox
+ run: set -o pipefail && NSUnbufferedIO=YES yarn detox build --configuration ios.debug 2>&1 | xcbeautify -qq
+
+ - name: Test with detox
+ run: |
+ npx detox --version
+ yarn detox test --configuration ios.debug --debug-synchronization 500 --loglevel trace --record-logs all --take-screenshots all
+ env:
+ SKIP_TESTS_NO_METAL: ${{ inputs.MAP_IMPL == 'mapbox' }}
+
+ - name: Store Detox artifacts on test failure
+ uses: actions/upload-artifact@v3
+ if: failure()
+ with:
+ name: detox-artifacts
+ path: example/artifacts
diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml
new file mode 100644
index 000000000..c58942c20
--- /dev/null
+++ b/.github/workflows/label-actions.yml
@@ -0,0 +1,17 @@
+# Configuration for Label Actions - https://github.com/dessant/label-actions
+
+name: "Label Actions"
+
+on:
+ issues:
+ types: labeled
+
+permissions:
+ contents: read
+ issues: write
+
+jobs:
+ action:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: dessant/label-actions@v2
diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml
new file mode 100644
index 000000000..78654575b
--- /dev/null
+++ b/.github/workflows/on-push.yml
@@ -0,0 +1,131 @@
+name: CI
+on:
+ push:
+ branches:
+ - 'main'
+ - 'v8'
+ pull_request:
+
+concurrency:
+ group: ${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
+
+jobs:
+ lint_test_generate:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Read .nvmrc
+ run: echo ::set-output name=NVMRC::$(cat .nvmrc)
+ id: nvm
+
+ - name: Setup node ${{ steps.nvm.outputs.NVMRC }}
+ uses: actions/setup-node@v3.6.0
+ with:
+ node-version: ${{ steps.nvm.outputs.NVMRC }}
+
+ - name: Install
+ run: yarn install --network-timeout 1000000
+
+ - name: Lint
+ run: yarn lint
+
+ - name: Type check
+ run: yarn type:check
+
+ - name: Example/install
+ run: yarn install --ignore-scripts --network-timeout 1000000
+ working-directory: example
+
+ - name: Example type check
+ run: yarn type:check
+ working-directory: example
+
+ - name: Test
+ run: yarn unittest
+
+ - name: Generate
+ run: yarn generate
+
+ outputs:
+ NVMRC: ${{ steps.nvm.outputs.NVMRC }}
+
+ has_mapbox_token:
+ runs-on: ubuntu-latest
+ outputs:
+ has-mapbox-token: ${{ steps.has-mapbox-token.outputs.defined }}
+ steps:
+ - id: has-mapbox-token
+ env:
+ MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
+ if: "${{ env.MAPBOX_ACCESS_TOKEN != '' }}"
+ run: echo "::set-output name=defined::true"
+
+ call_android_workflow:
+ name: "Android/Mapbox"
+ needs: [lint_test_generate,has_mapbox_token]
+ uses: ./.github/workflows/android-actions.yml
+ with:
+ NVMRC: ${{ needs.lint_test_generate.outputs.NVMRC }}
+ MAP_IMPL: mapbox
+ if: needs.has_mapbox_token.outputs.has-mapbox-token == 'true'
+ secrets:
+ MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
+ MAPBOX_DOWNLOAD_TOKEN: ${{ secrets.MAPBOX_DOWNLOAD_TOKEN }}
+
+ call_maplibre_android_workflow:
+ name: "Android/MapLibre"
+ needs: lint_test_generate
+ uses: ./.github/workflows/android-actions.yml
+ with:
+ NVMRC: ${{ needs.lint_test_generate.outputs.NVMRC }}
+ MAP_IMPL: maplibre
+ secrets:
+ MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
+ MAPBOX_DOWNLOAD_TOKEN: ${{ secrets.MAPBOX_DOWNLOAD_TOKEN }}
+
+ call_ios_workflow:
+ name: "iOS/Mapbox"
+ needs: [lint_test_generate,has_mapbox_token]
+ uses: ./.github/workflows/ios-actions.yml
+ if: needs.has_mapbox_token.outputs.has-mapbox-token == 'true'
+ with:
+ NVMRC: ${{ needs.lint_test_generate.outputs.NVMRC }}
+ MAP_IMPL: mapbox
+ secrets:
+ MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
+ MAPBOX_DOWNLOAD_TOKEN: ${{ secrets.MAPBOX_DOWNLOAD_TOKEN }}
+
+ call_maplibre_ios_workflow:
+ name: "iOS/MapLibre"
+ needs: lint_test_generate
+ uses: ./.github/workflows/ios-actions.yml
+ with:
+ NVMRC: ${{ needs.lint_test_generate.outputs.NVMRC }}
+ MAP_IMPL: maplibre
+ secrets:
+ MAPBOX_ACCESS_TOKEN: ${{ secrets.MAPBOX_ACCESS_TOKEN }}
+ MAPBOX_DOWNLOAD_TOKEN: ${{ secrets.MAPBOX_DOWNLOAD_TOKEN }}
+
+ publish:
+ if: startsWith(github.ref, 'refs/tags/') && (github.event_name == 'push')
+ needs: [lint_test_generate, call_maplibre_android_workflow, call_maplibre_ios_workflow]
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Setup node ${{ steps.nvm.outputs.NVMRC }}
+ uses: actions/setup-node@v3.6.0
+ with:
+ node-version: ${{ needs.lint_test_generate.outputs.NVMRC }}
+ registry-url: https://registry.npmjs.org/
+
+ - name: Install and Publish
+ run: npm install --force && npm publish
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
new file mode 100644
index 000000000..ed604ee23
--- /dev/null
+++ b/.github/workflows/publish.yml
@@ -0,0 +1,29 @@
+name: Publish to NPM
+on:
+ release:
+ types: [created]
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+ - name: Read .nvmrc
+ run: echo ::set-output name=NVMRC::$(cat .nvmrc)
+ id: nvm
+ - name: Setup node ${{ steps.nvm.outputs.NVMRC }}
+ uses: actions/setup-node@v3.6.0
+ with:
+ node-version: ${{ steps.nvm.outputs.NVMRC }}
+ registry-url: https://registry.npmjs.org/
+ - name: Setup Node
+ uses: actions/setup-node@v3.6.0
+ with:
+ node-version: '14.x'
+ registry-url: 'https://registry.npmjs.org'
+ - name: Install dependencies and build 🔧
+ run: npm install --force
+ - name: Publish package on NPM 📦
+ run: npm publish
+ env:
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN_RNMAPBOX }}
diff --git a/.gitignore b/.gitignore
index 20dc4030c..6bc2b9432 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
+# System
+.DS_Store
+
# Xcode
!**/*.xcodeproj
!**/*.pbxproj
@@ -58,9 +61,6 @@ yarn.lock
# Expo
.expo
-# OS X
-.DS_Store
-
# Test generated files
/ReactAndroid/src/androidTest/assets/AndroidTestBundle.js
*.js.meta
@@ -82,10 +82,14 @@ RNTester/build
/React/CoreModules/**/*.xcodeproj
/packages/react-native-codegen/**/*.xcodeproj
+# Ruby gems/bundle
+Gemfile
+Gemfile.lock
+vendor/
+
# CocoaPods
/template/ios/Pods/
/template/ios/Podfile.lock
-/RNTester/Gemfile.lock
# Ignore RNTester specific Pods, but keep the __offline_mirrors__ here.
RNTester/Pods/*
@@ -99,7 +103,7 @@ RNTester/Pods/*
.vscode
.vs
-# project specific
+# Project specific
ios/Mapbox.framework
ios/temp.zip
ios/.framework_version
@@ -120,4 +124,7 @@ coverage
*.core.prefs
*.iml
-react-native-mapbox-gl-maps.tgz
+rnmapbox-maps.tgz
+
+# generated by bob
+lib/
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100755
index 000000000..5a1cb4e67
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1,5 @@
+#!/usr/bin/env sh
+. "$(dirname -- "$0")/_/husky.sh"
+
+npm run generate
+npx lint-staged
diff --git a/.npmignore b/.npmignore
index eb03bb362..690f63a22 100644
--- a/.npmignore
+++ b/.npmignore
@@ -38,7 +38,11 @@ android/gradlew
android/gradlew.bat
android/local.properties
-# react-native-mapbox-gl
+# rnmapbox/maps
example
__tests__
coverage
+
+plugin/src
+plugin/jest.config.js
+plugin/tsconfig.json
diff --git a/.nvmrc b/.nvmrc
index ebf08b064..5d42dd403 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1,2 +1,2 @@
-v10.18.1
+v16.18.0
diff --git a/example/.prettierrc.js b/.prettierrc.js
similarity index 55%
rename from example/.prettierrc.js
rename to .prettierrc.js
index 5c4de1a4f..de2f53cdf 100644
--- a/example/.prettierrc.js
+++ b/.prettierrc.js
@@ -1,6 +1,4 @@
module.exports = {
- bracketSpacing: false,
- jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
};
diff --git a/.sonarcloud.properties b/.sonarcloud.properties
index cd93bc753..4a0afcc43 100644
--- a/.sonarcloud.properties
+++ b/.sonarcloud.properties
@@ -1,5 +1,5 @@
# Path to sources
-sonar.sources=javascript,android/src,ios/RCTMGL
+sonar.sources=src,android/src,ios/RCTMGL
#sonar.exclusions=
#sonar.inclusions=
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index c47ef4b03..000000000
--- a/.travis.yml
+++ /dev/null
@@ -1,88 +0,0 @@
-matrix:
- include:
- - language: android
- jdk: oraclejdk8
- before_install:
- - nvm install 10.22.1
- - echo yes | sdkmanager "platforms;android-28"
- - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.21.1
- - export PATH=$HOME/.yarn/bin:$PATH
- android:
- components:
- - tools
- - platform-tools
- - build-tools-28.0.3
- - tools
- cache:
- bundler: true
- yarn: true
- directories:
- - example/node_modules
- - "$HOME/.gradle/caches/"
- - "$HOME/.gradle/wrapper/"
- before_cache:
- - rm -f example/node_modules/\@react-native-mapbox-gl/
- - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- - rm -fr $HOME/.gradle/caches/*/plugin-resolution/
- - os: osx
- osx_image: xcode12.2
- node_js: 10.22.1
- cache:
- bundler: true
- yarn: true
- cocoapods: true
- directories:
- - example/node_modules
- - "$HOME/Library/Caches/Homebrew"
- before_cache:
- - rm -f example/node_modules/\@react-native-mapbox-gl/
- - brew cleanup
- podfile: example/ios/Podfile
-before_install:
-- nvm use 10.22.1
-- curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.21.1
-- export PATH=$HOME/.yarn/bin:$PATH
-install:
-- cd $TRAVIS_BUILD_DIR/example
-- echo $MAPBOX_ACCESS_TOKEN > ./accesstoken
-- find node_modules -name ".git" -exec rm -r "{}" \; || true
-- rm -rf example/node_modules/\@react-native-mapbox-gl/
-- yarn install --ignore-engines
-- echo $TRAVIS_OS_NAME
-- |
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
- cd $TRAVIS_BUILD_DIR/example/ios
- pod install
- pod update
- gem install xcpretty
- fi
-script:
-- |
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
- cd $TRAVIS_BUILD_DIR/example/ios
- set -o pipefail
- rm -f build
- xcodebuild -arch x86_64 -sdk iphonesimulator14.2 -workspace ./RNMapboxGLExample.xcworkspace -scheme RNMapboxGLExample | xcpretty -c
- fi
-- |
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then
- cd $TRAVIS_BUILD_DIR/example/android
- TERM=dumb ./gradlew assemble
- fi
-- cd $TRAVIS_BUILD_DIR
-- yarn global add -g 'jest@24.8.0'
-- yarn install --ignore-engines
-- yarn run unittest
-- yarn run generate
-deploy:
- provider: npm
- edge: true
- email: kristfallro@gmail.com
- api_key:
- secure: XP74gf8AAWkjMRBYzOQcSbU5uLSQA5Y7UYHjTPd+At/nBuf/38hkiZ/oOkJUNSVtc76zfCdnLRjXRFgGNYYH4XPe9vviaENWs0ykrT8H0OBhkKARF7w/R55uZF9IByOyOqnl2VviGgXHIJNCjZCr+r1Nm3nenfNdyEFfR6RT/5ZilsoZbvfZ/fs74HH3NE27q4T+mdgF9hgDOVO+p1tfGn0P7yGUbRhytQhMWkyeFnaYnu4kNv/aWWIkbzwEdOg1fYcjYv7LZVxaQFmrKpMDlyoBn9K3RwWgKX0mVR/IHfM0U3Vz0C/s9Zym8i9nBiJuBR0dH6tBwCgu/ORL+bX5PmuHYIk/vTcvU3dh0sFmdE8z6dFAThlHvNQMy9jW7QaYeBrnzDITyQMghI9+cBgnOtL0tlMU2TeAsbyfxjfr6HvOrKJiCQCv3kL7FoXCCtdlWjHnYHBzazj35bZYzyOEFFcyNe9Qe6pVwdz4AbAF1Tw0KmpZtfJTqNl512hmEFV9J2/0qIYvX7K+dlacRLKMImAwaU3pnkS40qXCAVnmSBHd3lq3QmIXp0t+QSuqRr88FOMAV/ShJDwbT2juCs13iLHHX4Jr1KCTowGatjoKbV/3OyuB9qpdsz62a7HAw3YulU1cnHRt8cTADb/7S0UZCy0TBzPKitg8MHSyQqEyvEs=
- on:
- tags: true
- repo: react-native-mapbox-gl/maps
- branch: master
- condition: $TRAVIS_OS_NAME = linux
-
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f36b61d59..10926ada0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,18 +1,253 @@
+## UNRELEASED
+
+```
+Please add unreleased changes in the following style:
+PR Title ([#123](link to my pr))
+```
+
+### UNRELEASED/10.0.0-beta.10
+
+#### Breaking changes:
+
+The setup was changed - see install instructions for more details. In a nuthsell:
+* On both android/ios to select mapbox implementation use `RNMapboxMapsImpl`/`$RNMapboxMapsImpl` variable which can be one of (`maplibre`,`mapbox`(aka v10),`mapbox-gl`)
+* Default implementation is `maplibre` as it requires not further setup. *WARNING* using mapbox styles from `maplibre` has different pricing than mapbox native sdk-s.
+* On Podfile `$RNMBGL.(pre|post)_install` was changed `$RNMapboxMaps.(pre|post)_install`
+* Package name was changed from `@react-native-mapbox-gl/maps` to `@rnmapbox/maps`. If you just testing with the v10 version you can use something like [babel-plugin-transform-rename-import](https://www.npmjs.com/package/babel-plugin-transform-rename-import) to keep using the old imports for a while.
+* `MapboxGL.setAccessToken` now requires `MapboxGL.setWellKnownTileServer` on maplibre.
+
+
+#### Changes:
+
+- Convert Camera component to TypeScript and update related documentation generation and tests ([#2057](https://github.com/rnmapbox/maps/pull/2057))
+- Implement clustering properties to ShapeSource ([#1745](https://github.com/react-native-mapbox-gl/maps/pull/1745))
+- Initial Mapbox V10 support ([#1750](https://github.com/rnmapbox/maps/pull/1750))
+- Updated MapLibre on Android to 9.5.2 ([#1780](https://github.com/rnmapbox/maps/pull/1780))
+
+## 8.6.0-beta.0
+
+fix: add TypeScript type for MapViews's preferredFramesPerSecond prop ([#1717](https://github.com/rnmapbox/maps/pull/1717))
+fix(example): update `/example` project (iOS only) to work with ARM-based Macs ([#1703](https://github.com/rnmapbox/maps/pull/1703))
+fix(iOS): correct import of UIView+React.h header ([#1672](https://github.com/rnmapbox/maps/pull/1672))
+
+---
+
+## 8.5.0
+
+build: update install guide and `/example` project for android dependencies ([#1640](https://github.com/rnmapbox/maps/pull/1640))
+build(turf): update to version 6.5.0 ([#1638](https://github.com/rnmapbox/maps/pull/1638))
+fix(Camera) fix `zoomTo` method and expand Fit example ([#1631](https://github.com/rnmapbox/maps/pull/1631))
+ci: two scripts for linting with and without fix ([#1630](https://github.com/rnmapbox/maps/pull/1630))
+feat(Camera) add an optional `allowUpdates` boolean prop ([#1619](https://github.com/rnmapbox/maps/pull/1619))
+refactor(example): remove unused modules and scripts ([#1618](https://github.com/rnmapbox/maps/pull/1618))
+fix(react-native): update api to get rid of EventEmitter warnings ([#1615](https://github.com/rnmapbox/maps/pull/1615))
+fix(Camera) persist zoom when changing from `bounds` to `centerCoordinate`, fix zero padding not causing map to update, create unified example showcasing bounds/centerCoordinate/zoom/padding ([#1614](https://github.com/rnmapbox/maps/pull/1614))
+Update MapLibre to 5.12.1 on iOS ([#1596](https://github.com/rnmapbox/maps/pull/1596))
+Update ShapeSource methods to make it usable with any cluster ( Use cluster itself instead of cluster_id as first argument for getClusterExpansionZoom/getClusterLeaves/getClusterChildren methods. Version < 9 methods still supports passing cluster_id as a first argument but a deprecation warning will be shown. ) ([#1499](https://github.com/rnmapbox/maps/pull/1499))
+
+---
+
+## 8.4.0
+
+fix(iOS): pin mapLibre back to `5.12.0` ([#1589](https://github.com/rnmapbox/maps/pull/1589))
+chore: improve GH workflows ([#1588](https://github.com/rnmapbox/maps/pull/1588))
+build(deps): bump @expo/config-plugins from 3.1.0 to 4.0.3 ([#1585](https://github.com/rnmapbox/maps/pull/1585))
+chore(pre-commit): run lint on TS files, change PR template ([#1584](https://github.com/rnmapbox/maps/pull/1584))
+feat(example): update vertical alignment example ([#1579](https://github.com/rnmapbox/maps/pull/1579))
+fix incorrect anchor calculation for PointAnnotation on iOS ([#1576](https://github.com/rnmapbox/maps/pull/1576))
+style(eslint): align root and example with the same configuration ([#1575](https://github.com/rnmapbox/maps/pull/1575))
+fix(mapLibre): support version `5.12.0` upwards ([#1571](https://github.com/rnmapbox/maps/pull/1571))
+build: upgrade to RN `0.66` ([#1570](https://github.com/rnmapbox/maps/pull/1570))
+build(android): add telemetry dependency to default build setup ([#1550](https://github.com/rnmapbox/maps/pull/1550))
+feat(camera): Enable `padding` as a root-level prop on the camera, with `bounds.padding*` as fallbacks ([#1538](https://github.com/rnmapbox/maps/pull/1538/files))
+fix: revert pinned mapLibre version to `5.11.0` ([8a2b00e67ba6398f3f6e6f52e98b0f0cea437e4d](https://github.com/rnmapbox/maps/commit/8a2b00e67ba6398f3f6e6f52e98b0f0cea437e4d))
+
+---
+
+## 8.3.0
+
+Fix TypeScript type for Callout's textStyle prop ([#1450](https://github.com/rnmapbox/maps/pull/1450))
+Build(ios): pin maplibre version to 5.12.0 ([#1454](https://github.com/rnmapbox/maps/pull/1454))
+Update geoUtils helpers types to correspond with `turf/helpers` ([#1455](https://github.com/rnmapbox/maps/pull/1455))
+Fix crash with missing okhttp dependency ([#1452](https://github.com/rnmapbox/maps/pull/1452))
+Move from react-native-testing-library => @testing-library/react-native ([#1453](https://github.com/rnmapbox/maps/pull/1453))
+Feat(camera): maxBounds/(min|max)ZoomLevel can be updated dynamically ([#1462](https://github.com/rnmapbox/maps/pull/1462))
+Refactor(example): clean up folder structure ([#1464](https://github.com/rnmapbox/maps/pull/1464))
+Fix lineGradient showing wrong colors ([#1471](https://github.com/rnmapbox/maps/pull/1471))
+Support tintColor on Android ([#1465](https://github.com/rnmapbox/maps/pull/1465))
+Feat(android): dynamically update tintColor & add example ([#1469](https://github.com/rnmapbox/maps/pull/1469)
+Examples: align install steps with yarn, ignore created env files ([#1484](https://github.com/rnmapbox/maps/pull/1484)
+Fix(plugin): Exclude arm64 architectures for simulator builds ([#1490](https://github.com/rnmapbox/maps/pull/1490)
+Feat(android): dynamically update tintColor & add example ([#1469](https://github.com/rnmapbox/maps/pull/1469))
+Docs: make background in example pngs transparent ([#1483](https://github.com/rnmapbox/maps/pull/1483))
+Style: run yarn lint ([#1486](https://github.com/rnmapbox/maps/pull/1486))
+Test: add unit tests for component light ([#1489](https://github.com/rnmapbox/maps/pull/1489))
+Feat: add Adds getClusterChildren method to ShapeSource ([#1495](https://github.com/rnmapbox/maps/pull/1495))
+
+## 8.2.1
+
+fix issue when publishing to npm with `prepare` script
+
+## 8.2.0
+
+getClusterLeaves method for ShapeSource ([#1411](https://github.com/rnmapbox/maps/pull/1411))
+Add logoPosition props to `MapView` to position the mapbox logo ([#1396](https://github.com/rnmapbox/maps/pull/1396))
+Add compatibility with React 17/ npm7 ([#1387](https://github.com/rnmapbox/maps/pull/1387))
+Add Expo config plugin ([#1388](https://github.com/rnmapbox/maps/pull/1388))
+Android: Bump `okhttp` to `4.9.0` ([#1390](https://github.com/rnmapbox/maps/pull/1390))
+Support dynamically changing local JSON in styleURL ([#1399](https://github.com/rnmapbox/maps/pull/1399))
+Add missing types to `SymbolLayerStyle` & `ImagesProps` ([#1360](https://github.com/rnmapbox/maps/pull/1360))
+Fix error while updating coordinates of RCTMGLImageSource ([#1310](https://github.com/rnmapbox/maps/pull/1310))
+
+## 8.2.0-beta2
+
+Add types for `Logger` class ([#1316](https://github.com/rnmapbox/maps/pull/1316))
+Enable linear easing on map camera ([#1281](https://github.com/rnmapbox/maps/pull/1281))
+Allow MapLibre as an option ([#1311](https://github.com/rnmapbox/maps/pull/1311))
+Fix native UserLocation on Android ([#1284](https://github.com/rnmapbox/maps/pull/1284))
+Add getClusterExpansionZoom to ShapeSource ([#1279](https://github.com/rnmapbox/maps/pull/1279))
+Add type definition for AnimatedPoint ([#1280](https://github.com/rnmapbox/maps/pull/1280))
+
+## 8.2.0-beta1
+
+### Breaking changes:
+
+Use `pre_install` hook to support non `use_frameworks!` usage #1262. Please add the following to your `Podfile`:
+
+```ruby
+pre_install do |installer|
+ $RNMBGL.pre_install(installer)
+ ...
+end
+```
+
+and
+
+```ruby
+post_install do |installer|
+ $RNMBGL.post_install(installer)
+ ...
+end
+```
+
+### Other changes:
+
+- Add course to the location events #1209
+- Fix heading indicator alignment #1215
+- App crash when ProGuard is set to true #1184
+- [iOS] Implemented ShapeSource.features(...) method #1140
+- style json support on styleURL #1102
+- Fix: onUpdate not called when renderMode is native #1135
+
+## 8.1.0
+
+- By default [use 5.9.0 Mapbox on iOS as 8.1.0rc8 and before](https://github.com/rnmapbox/maps/pull/1120)
+- Fix [crash during styleURL change on adroid](https://github.com/rnmapbox/maps/pull/1119)
+- Fix [warning Sending LogEvent with no listeners registered.](https://github.com/rnmapbox/maps/pull/1108)
+- Fix [race in close map and icon image download](https://github.com/rnmapbox/maps/pull/1089)
+- Fix [android padding](https://github.com/rnmapbox/maps/pull/1087)
+- Android [custom mapboxgl version](https://github.com/rnmapbox/maps/pull/1088)
+- Fix [support 6.\* of MapboxGL IOS by setting `$ReactNativeMapboxGLIOSVersion = "6.2.1"` in Podfile](https://github.com/rnmapbox/maps/pull/1044)
+- Fix [map rendered at (0,0,0,0) on iOS](https://github.com/rnmapbox/maps/pull/1084)
+- Fix [edge Padding + auto limit padding on iOS](https://github.com/rnmapbox/maps/pull/1057)
+- Fix [coordinate 0,0 was considered invalid on IOS](https://github.com/rnmapbox/maps/pull/1076)
+- Fix [refresh on PointAnnotation on Android](https://github.com/rnmapbox/maps/pull/1062)
+- Fix [Image source coordinates update on the fly](https://github.com/rnmapbox/maps/pull/1036/files)
+- Upgrade to [ios 5.9.0](https://github.com/mapbox/mapbox-gl-native-ios/releases/tag/ios-v5.9.0)
+- Upgrade to [android 9.1.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.1.0)
+- Set default Mapbox logging verbosity to warning. (Change it using Logger.setLogLevel('verbose'))
+- Error/Warn mapbox log messages are treated as redbox/yellowbox errors/warnings. (Override it using Logger.setLoggerCallback(log => { return true })
+- Native user location [#825](https://github.com/rnmapbox/maps/pull/825)
+
+## 8.1.0-rc11
+
+- By default [use 5.9.0 Mapbox on iOS as 8.1.0rc8 and before](https://github.com/rnmapbox/maps/pull/1120)
+- Fix [crash during styleURL change on adroid](https://github.com/rnmapbox/maps/pull/1119)
+- Fix [warning Sending LogEvent with no listeners registered.](https://github.com/rnmapbox/maps/pull/1108)
+- Fix [race in close map and icon image download](https://github.com/rnmapbox/maps/pull/1089)
+- Fix [android padding](https://github.com/rnmapbox/maps/pull/1087)
+- Android [custom mapboxgl version](https://github.com/rnmapbox/maps/pull/1088)
+- Fix [support 6.\* of MapboxGL IOS by setting `$ReactNativeMapboxGLIOSVersion = "6.2.1"` in Podfile](https://github.com/rnmapbox/maps/pull/1044)
+- Fix [map rendered at (0,0,0,0) on iOS](https://github.com/rnmapbox/maps/pull/1084)
+- Fix [edge Padding + auto limit padding on iOS](https://github.com/rnmapbox/maps/pull/1057)
+- Fix [coordinate 0,0 was considered invalid on IOS](https://github.com/rnmapbox/maps/pull/1076)
+- Fix [refresh on PointAnnotation on Android](https://github.com/rnmapbox/maps/pull/1062)
+- Fix [Image source coordinates update on the fly](https://github.com/rnmapbox/maps/pull/1036/files)
+- Upgrade to [ios 5.9.0](https://github.com/mapbox/mapbox-gl-native-ios/releases/tag/ios-v5.9.0)
+- Upgrade to [android 9.1.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.1.0)
+- Set default Mapbox logging verbosity to warning. (Change it using Logger.setLogLevel('verbose'))
+- Error/Warn mapbox log messages are treated as redbox/yellowbox errors/warnings. (Override it using Logger.setLoggerCallback(log => { return true })
+- Native user location [#825](https://github.com/rnmapbox/maps/pull/825)
+
+## 8.1.0-rc10
+
+- By default [use 5.9.0 Mapbox on iOS as 8.1.0rc8 and before](https://github.com/rnmapbox/maps/pull/1120)
+- Fix [crash during styleURL change on adroid](https://github.com/rnmapbox/maps/pull/1119)
+- Fix [warning Sending LogEvent with no listeners registered.](https://github.com/rnmapbox/maps/pull/1108)
+- Fix [race in close map and icon image download](https://github.com/rnmapbox/maps/pull/1089)
+- Fix [android padding](https://github.com/rnmapbox/maps/pull/1087)
+- Android [custom mapboxgl version](https://github.com/rnmapbox/maps/pull/1088)
+- Fix [support 6.\* of MapboxGL IOS by setting `$ReactNativeMapboxGLIOSVersion = "6.2.1"` in Podfile](https://github.com/rnmapbox/maps/pull/1044)
+- Fix [map rendered at (0,0,0,0) on iOS](https://github.com/rnmapbox/maps/pull/1084)
+- Fix [edge Padding + auto limit padding on iOS](https://github.com/rnmapbox/maps/pull/1057)
+- Fix [coordinate 0,0 was considered invalid on IOS](https://github.com/rnmapbox/maps/pull/1076)
+- Fix [refresh on PointAnnotation on Android](https://github.com/rnmapbox/maps/pull/1062)
+- Fix [Image source coordinates update on the fly](https://github.com/rnmapbox/maps/pull/1036/files)
+- Upgrade to [ios 5.9.0](https://github.com/mapbox/mapbox-gl-native-ios/releases/tag/ios-v5.9.0)
+- Upgrade to [android 9.1.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.1.0)
+- Set default Mapbox logging verbosity to warning. (Change it using Logger.setLogLevel('verbose'))
+- Error/Warn mapbox log messages are treated as redbox/yellowbox errors/warnings. (Override it using Logger.setLoggerCallback(log => { return true })
+- Native user location [#825](https://github.com/rnmapbox/maps/pull/825)
+
+## 8.1.0.rc10
+
+- By default [use 5.9.0 Mapbox on iOS as 8.1.0rc8 and before](https://github.com/rnmapbox/maps/pull/1120)
+- Fix [crash during styleURL change on adroid](https://github.com/rnmapbox/maps/pull/1119)
+- Fix [warning Sending LogEvent with no listeners registered.](https://github.com/rnmapbox/maps/pull/1108)
+
+## 8.1.0.rc9
+
+- Fix [race in close map and icon image download](https://github.com/rnmapbox/maps/pull/1089)
+
+## 8.1.0.rc8
+
+- Fix [android padding](https://github.com/rnmapbox/maps/pull/1087)
+- Android [custome mapboxgl version](https://github.com/rnmapbox/maps/pull/1088)
+
+## 8.1.0.rc7
+
+- Fix [map rendered at (0,0,0,0) on iOS](https://github.com/rnmapbox/maps/pull/1084)
+
+## 8.1.0.rc6
+
+- Fix [edge Padding + auto limit padding on iOS](https://github.com/rnmapbox/maps/pull/1057)
+- Fix [coordinate 0,0 was considered invalid on IOS](https://github.com/rnmapbox/maps/pull/1076)
+- Fix [refresh on PointAnnotation on Android](https://github.com/rnmapbox/maps/pull/1062)
+
+## 8.1.0.rc5
+
+- Fix [support 6.\* of MapboxGL IOS by setting `$ReactNativeMapboxGLIOSVersion = "6.2.1"` in Podfile](https://github.com/rnmapbox/maps/pull/1044)
+- Fix [Image source coordinates update on the fly](https://github.com/rnmapbox/maps/pull/1036/files)
+
+## 8.1.0.rc4
+
## 8.1.0.rc3
-- Fix [iOS interface for getAccessToken() on Android](https://github.com/react-native-mapbox-gl/maps/pull/954)
+- Fix [android crashes](https://github.com/rnmapbox/maps/pull/963)
+- Fix [android padding addition](https://github.com/rnmapbox/maps/pull/973)
+- Fix [iOS interface for getAccessToken() on Android](https://github.com/rnmapbox/maps/pull/954)
## 8.1.0.rc2
-- Fix [camera padding on android](https://github.com/react-native-mapbox-gl/maps/pull/941)
-- Allow [zPosition on iOS](https://github.com/react-native-mapbox-gl/maps/pull/942) in PointAnnotation child views.
-- Added [InvalidatePack](https://github.com/react-native-mapbox-gl/maps/pull/929)
-- Allow to [customize iOS framework version used](https://github.com/react-native-mapbox-gl/maps/pull/940)
+- Fix [camera padding on android](https://github.com/rnmapbox/maps/pull/941)
+- Allow [zPosition on iOS](https://github.com/rnmapbox/maps/pull/942) in PointAnnotation child views.
+- Added [InvalidatePack](https://github.com/rnmapbox/maps/pull/929)
+- Allow to [customize iOS framework version used](https://github.com/rnmapbox/maps/pull/940)
## 8.1.0.rc1
-- Added [invalidateAmbientCache](https://github.com/react-native-mapbox-gl/maps/pull/899)
-- Implemented [ShapeSource#features](https://github.com/react-native-mapbox-gl/maps/pull/911)
+- Added [invalidateAmbientCache](https://github.com/rnmapbox/maps/pull/899)
+- Implemented [ShapeSource#features](https://github.com/rnmapbox/maps/pull/911)
## 8.1.0.beta
@@ -20,24 +255,24 @@
- Upgrade to [android 9.1.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.1.0)
- Set default Mapbox logging verbosity to warning. (Change it using Logger.setLogLevel('verbose'))
- Error/Warn mapbox log messages are treated as redbox/yellowbox errors/warnings. (Override it using Logger.setLoggerCallback(log => { return true })
-- Native user location [#825](https://github.com/react-native-mapbox-gl/maps/pull/825)
+- Native user location [#825](https://github.com/rnmapbox/maps/pull/825)
## 8.0.0
-### Breaking changes - [#610](https://github.com/react-native-mapbox-gl/maps/issues/610)
+### Breaking changes - [#610](https://github.com/rnmapbox/maps/issues/610)
- iOS mapbox libraries updated to [5.7.0](https://github.com/mapbox/mapbox-gl-native-ios/releases/tag/ios-v5.7.0) android libraries updated to [9.0.0](https://github.com/mapbox/mapbox-gl-native-android/releases/tag/android-v9.0.0)
-- ShapeSource#images is now removed (deprecated in 7.*), use Images#images instead. Also special `assets` inside `images` is now deprecated, use `nativeAssetImages` istead.
+- ShapeSource#images is now removed (deprecated in 7.\*), use Images#images instead. Also special `assets` inside `images` is now deprecated, use `nativeAssetImages` istead.
- iOS now defaults to non `use_frameworks!`, if you want to continue to use `use_frameworks!` please see our iOS installation guidelines
- [Images#onImagesMissing](docs/Images.md)
- Android code migrated to AndroidX, RN 60.0+ is recommended.
- geoUtils is now private, please use [turf-js](https://turfjs.org/) instead
-- VectorSource/SymbolSource#onPress sends ({features, point, coordinates}) instead of single feature in `event.nativeEvent.payload`. [PR#700](https://github.com/react-native-mapbox-gl/maps/pull/700)
+- VectorSource/SymbolSource#onPress sends ({features, point, coordinates}) instead of single feature in `event.nativeEvent.payload`. [PR#700](https://github.com/rnmapbox/maps/pull/700)
### Changes:
- added [MarkerView](docs/MarkerView.md)
-- added AnimatedShape and AnimatedCoordinatesArray [PR#702](https://github.com/react-native-mapbox-gl/maps/pull/702)
+- added AnimatedShape and AnimatedCoordinatesArray [PR#702](https://github.com/rnmapbox/maps/pull/702)
## 7.2.0
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 26d623d24..b22911688 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -8,7 +8,7 @@
## Testing my changes
The metro bundler under `/example` is set up to use the libraries files under root.
-Which means, when you change something within `javascript/components/UserLocation.js`
+Which means, when you change something within `src/components/UserLocation.js`
it will be reflected in any scene in example that uses that component.
## Best practices for PR's
diff --git a/LICENSE.md b/LICENSE.md
index a0b06297d..0e77b64a4 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,23 +1,5 @@
-react-native-mapbox-gl copyright (c) 2017, Mapbox.
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-* Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-Mapbox GL uses portions of the Mapbox Maps SDK for iOS, which was derived from the Route-Me open source project, including the Alpstein fork of it.
-
-The Route-Me license appears below.
-
-Copyright (c) 2008-2013, Route-Me Contributors All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
-
-Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
-Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/README-v10.md b/README-v10.md
new file mode 100644
index 000000000..21c9167e4
--- /dev/null
+++ b/README-v10.md
@@ -0,0 +1,86 @@
+# Getting Started
+
+
+```shell
+react-native init sample --version 0.60.5
+cd sample
+yarn add https://github.com/rnmapbox/maps#main --save
+
+code android/build.gradle
+```
+
+```gradle
+# add the following:
+allprojects {
+ repositories {
+ maven {
+ url 'https://api.mapbox.com/downloads/v2/releases/maven'
+ authentication {
+ basic(BasicAuthentication)
+ }
+ credentials {
+ // Do not change the username below.
+ // This should always be `mapbox` (not your username).
+ username = 'mapbox'
+ // Use the secret token you stored in gradle.properties as the password
+ password = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: ""
+ }
+ }
+ }
+}
+```
+
+code android/app/build.gradle
+```gradle
+# add the following:
+android {
+ packagingOptions {
+ pickFirst 'lib/x86/libc++_shared.so'
+ pickFirst 'lib/x86_64/libc++_shared.so'
+ pickFirst 'lib/arm64-v8a/libc++_shared.so'
+ pickFirst 'lib/armeabi-v7a/libc++_shared.so'
+ }
+}
+```
+
+code android/build.gradle
+```
+buildscript {
+ ext {
+ ...
+ RNMapboxMapsImpl = 'mapbox'
+ }
+}
+```
+
+code ios/Podfile
+```pod
+ # change these
+ $RNMapboxMapsImpl = 'mapbox'
+
+ platform :ios, '13.0'
+
+ ...
+
+ ...
+
+ pre_install do |installer|
+ $RNMapboxMaps.pre_install(installer)
+ end
+
+ post_install do |installer|
+ react_native_post_install(installer)
+ $RNMapboxMaps.post_install(installer)
+ end
+```
+
+```pod
+# on RN 0.60 only:
+# add modular_headers to `React-Core`
+pod 'React-Core', :path => '../node_modules/react-native/React', modular_headers: true
+```
+
+iOS:
+
+ * Add `$(SDKROOT)/usr/lib/swift` to Library search paths.
+
diff --git a/README.md b/README.md
index 1edc97563..5fb7b086c 100644
--- a/README.md
+++ b/README.md
@@ -1,49 +1,184 @@
+
# Mapbox Maps SDK for React Native
-_An unofficial React Native library for building maps with the [Mapbox Maps SDK for iOS](https://www.mapbox.com/ios-sdk/) and [Mapbox Maps SDK for Android](https://www.mapbox.com/android-sdk/)_
+
+
+
+
+ |
+
+
+ |
+
+
-[![npm version](https://badge.fury.io/js/%40react-native-mapbox-gl%2Fmaps.svg)](https://badge.fury.io/js/%40react-native-mapbox-gl%2Fmaps)
-![build_status](https://travis-ci.org/react-native-mapbox-gl/maps.svg?branch=master)
-[![Depfu](https://badges.depfu.com/badges/2eac6b62372619718b7f55ebbf8e9d8f/overview.svg)](https://depfu.com/github/react-native-mapbox-gl/maps?project_id=8248)
+| [![npm version](https://badge.fury.io/js/%40rnmapbox%2Fmaps.svg)](https://badge.fury.io/js/%40rnmapbox%2Fmaps) | [![iOS & Android Build](https://github.com/rnmapbox/maps/actions/workflows/on-push.yml/badge.svg?branch=main)](https://github.com/rnmapbox/maps/actions/workflows/on-push.yml?branch=main) |
+|---|---|
-## Installation
-### Prerequisit
-On Android we support from version 6 (API 23) upwards
-### Dependencies
+_A community-supported, open-source React Native library for building maps with the [Mapbox Maps SDK for iOS](https://www.mapbox.com/ios-sdk/) and [Mapbox Maps SDK for Android](https://www.mapbox.com/android-sdk/)_
+
+---
+## News & Discussions
+#### → Future of this repo: participate in the [discussion thread](https://github.com/rnmapbox/maps/discussions/1680)
+
+#### → Call for additional maintainers [discussion thread](https://github.com/rnmapbox/maps/discussions/1551)
+
+#### → This README is for the unreleased 10* branch. Please see [v8 branch](https://github.com/rnmapbox/maps/tree/v8) for documentation on 8.* releases
+---
+
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+ |
+
+
+
+---
+
+### Supported Implementations
+At the moment, the following implementations are supported:
+
+
+|*RNMapboxMapsImpl*|*Notes*|
+|----------------|-----|
+|mapbox|New [Mapbox v10](https://www.mapbox.com/mobile-maps-sdk) implementation - recommended|
+|maplibre|[MapLibre](https://github.com/maplibre/maplibre-gl-native) opensource fork of Mapbox SDKs - will be dropped in next version|
+|mapbox-gl|Legacy mapbox implementation [iOS](https://docs.mapbox.com/android/legacy/maps/guides/) [Android](https://docs.mapbox.com/ios/legacy/maps/guides/) - legacy, will be dropped in next version|
+
+_See [iOS](ios/install.md) & [Android](android/install.md) setup guide for more details on setting `RNMapboxMapsImpl`_
+
+
+
+
+## Prerequisite
+
+1. On Android we support from version 6 (API 23) upwards
+2. Please [Sign Up to Mapbox](https://account.mapbox.com/auth/signup/) to get the Mapbox Access Token.
+
+
+## Dependencies
- [node](https://nodejs.org)
- [npm](https://www.npmjs.com/)
- [React Native](https://facebook.github.io/react-native/) (0.60+)
-### Git
-```
-git clone git@github.com:react-native-mapbox-gl/maps.git
-cd maps
-```
+## Installation
-### Yarn
+### Step 1 - Install Package:
-```
-yarn add @react-native-mapbox-gl/maps
-```
+#### Using `yarn`
+Install the latest source from git:
+```sh
+yarn add rnmapbox/maps#main
+```
-### Npm
+#### Using `npm`
+Install the latest source from git:
+```sh
+npm install --save rnmapbox/maps#main
+```
+
+#### Installing other versions
+Replace `rnmapbox/maps#main` with the following to install other versions:
+- `@rnmapbox/maps` installs the latest release
-```
-npm install @react-native-mapbox-gl/maps --save
-```
-## Installation Guides
+#### Using `expo`
+Please follow the [Expo Guide](/plugin/install.md).
+
+### Step 2 - Installation Guides:
- [Android](/android/install.md)
- [iOS](/ios/install.md)
+- [Expo](/plugin/install.md)
- [Example](/example)
-## [Getting Started](/docs/GettingStarted.md)
+### Getting Started
+For more information, check out our [Getting Started](/docs/GettingStarted.md) section
+
+## Run Project
+Before you run your project be sure you have completed the Installation Guides for Android or iOS.
+
+### Run iOS Simulator
+```sh
+# Run with yarn
+yarn run ios
+
+# or Run with NPM
+npm run ios
+```
+
+### Run Android Emulator
+```sh
+# Run with yarn
+yarn run android
+
+# or Run with NPM
+npm run android
+```
+
+## Adding a map
+```js
+import React from 'react';
+import { StyleSheet, View } from 'react-native';
+import Mapbox from '@rnmapbox/maps';
+
+Mapbox.setAccessToken('');
+
+const App = () => {
+ return (
+
+
+
+
+
+ );
+}
+
+export default App;
+
+const styles = StyleSheet.create({
+ page: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+ container: {
+ height: 300,
+ width: 300,
+ },
+ map: {
+ flex: 1
+ }
+});
+```
+---
## Documentation
### Components
@@ -57,12 +192,14 @@ npm install @react-native-mapbox-gl/maps --save
- [Camera](docs/Camera.md)
- [UserLocation](docs/UserLocation.md)
- [Images](docs/Images.md)
+- [Image](docs/Image.md)
### Sources
- [VectorSource](/docs/VectorSource.md)
- [ShapeSource](/docs/ShapeSource.md)
- [RasterSource](/docs/RasterSource.md)
+- [RasterDemSource](/docs/RasterDemSource.md)
### Layers
@@ -74,6 +211,12 @@ npm install @react-native-mapbox-gl/maps --save
- [RasterLayer](/docs/RasterLayer.md)
- [SymbolLayer](/docs/SymbolLayer.md)
- [HeatmapLayer](/docs/HeatmapLayer.md)
+- [SkyLayer](/docs/SkyLayer.md)
+
+### Terrain
+
+- [Terrain](/docs/Terrain.md)
+- [Atmosphere](/docs/Atmosphere.md)
### Offline
@@ -84,10 +227,11 @@ npm install @react-native-mapbox-gl/maps --save
- [MapboxGL](/docs/MapboxGL.md)
- [CustomHttpHeaders](/docs/CustomHttpHeaders.md)
+- [Logger](/docs/Logger.md)
## Expo Support
-We have a feature request open with Expo if you want to see it get in show your support https://expo.canny.io/feature-requests/p/add-mapbox-gl-support
+This package is not available in the [Expo Go](https://expo.io/client) app. Learn how you can use it with [custom dev clients](/plugin/install.md).
## Testing with Jest
@@ -98,10 +242,48 @@ Example:
```json
"jest": {
"preset": "react-native",
- "setupFilesAfterEnv": ["@react-native-mapbox-gl/maps/setup-jest"]
+ "setupFilesAfterEnv": ["@rnmapbox/maps/setup-jest"],
+ "transformIgnorePatterns": [
+ "node_modules/(?!(...|@rnmapbox))"
+ ]
}
```
-
+---
+## Sponsors
+
+Help drive this repo forward - be a sponsor. Add a comment [here](https://github.com/rnmapbox/maps/discussions/1551) to discuss your sponsorship.
+
+
+
+---
## Developer Group
-Have a question or need some help? Join our [Gitter developer group](https://gitter.im/react-native-mapbox-gl/Lobby)!
+Have a question or need some help? Join our [Gitter developer group](https://gitter.im/rnmapbox/Lobby)!
diff --git a/RELEASE.md b/RELEASE.md
new file mode 100644
index 000000000..e85d56bc4
--- /dev/null
+++ b/RELEASE.md
@@ -0,0 +1,28 @@
+# How to create a release for this repo
+
+## Make sure `main` builds correctly
+
+Are all our [actions](https://github.com/rnmapbox/maps/actions) passing successfully?
+If not, make sure to investigate the issue and fix it prior to a release.
+
+## Bump the version in our package.json
+
+Once you verified, that `main` isn't broken, go on and increase the `version` within our `package.json`.
+
+## Update the CHANGELOG accordingly
+
+Our [`CHANGELOG.md`](https://github.com/rnmapbox/maps/blob/main/CHANGELOG.md) should be updated whenever a PR is merged/ noteworthy changes are committed to `main`.
+Prior to a release, the changes should be documented under the `UNRELEASED` section.
+Once it's clear, that a release is about to be published, move the items under `UNRELEASED` to _this_ releases sections.
+Let your actions be guided by the previous release entries.
+
+## Draft a new release on GitHub
+
+Within the [releases](https://github.com/rnmapbox/maps/releases) section of the repo you can [`Draft a new release`](https://github.com/rnmapbox/maps/releases/new).
+
+`Tag version` & `Release title` should be the same.
+As redundant as it might sound, please add the changes from the `CHANGELOG.md` into the body of the release.
+
+## Monitor the repos issues for updates
+
+Once the release is out the door (on [npm](https://www.npmjs.com/package/@rnmapbox/maps)), make sure to monitor the [issues](https://github.com/rnmapbox/maps/issues) closely for problems the community might encounter
diff --git a/__tests__/__mocks__/react-native.mock.js b/__tests__/__mocks__/react-native.mock.js
index 8a2bd3146..30f073484 100644
--- a/__tests__/__mocks__/react-native.mock.js
+++ b/__tests__/__mocks__/react-native.mock.js
@@ -1,10 +1,27 @@
jest.mock('react-native/Libraries/Image/resolveAssetSource', () => {
- return () => ({uri: 'asset://test.png'});
+ return () => ({ uri: 'asset://test.png' });
});
-jest.mock('NativeEventEmitter', () => {
+jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter', () => {
function MockEventEmitter() {}
- MockEventEmitter.prototype.addListener = jest.fn(() => ({remove: jest.fn()}));
- MockEventEmitter.prototype.removeListener = jest.fn();
- return MockEventEmitter;
+ MockEventEmitter.prototype.addListener = jest.fn(() => ({
+ remove: jest.fn(),
+ }));
+ return {
+ __esModule: true,
+ default: MockEventEmitter,
+ };
});
+
+jest.mock('react-native/Libraries/Utilities/Platform', () => ({
+ OS: 'ios', // or 'android'
+ select: (x) => {
+ if (x.android) {
+ return x.android;
+ } else if (x.native) {
+ return x.native;
+ } else if (x.default) {
+ return x.default;
+ }
+ },
+}));
diff --git a/__tests__/components/BackgroundLayer.test.js b/__tests__/components/BackgroundLayer.test.js
index 0c9c7f41a..9d085cdb7 100644
--- a/__tests__/components/BackgroundLayer.test.js
+++ b/__tests__/components/BackgroundLayer.test.js
@@ -1,18 +1,15 @@
import React from 'react';
-import {render} from 'react-native-testing-library';
+import { render } from '@testing-library/react-native';
-import BackgroundLayer from '../../javascript/components/BackgroundLayer';
-
-export const NATIVE_MODULE_NAME = 'RCTMGLBackgroundLayer';
+import BackgroundLayer from '../../src/components/BackgroundLayer';
describe('BackgroundLayer', () => {
test('renders correctly with default props', () => {
- const {queryByTestId} = render(
+ const { container: backgroundLayer } = render(
,
);
- const backgroundLayer = queryByTestId('rctmglBackgroundLayer');
- const {props} = backgroundLayer;
+ const { props } = backgroundLayer;
expect(props.sourceID).toStrictEqual('DefaultSourceID');
});
@@ -28,12 +25,13 @@ describe('BackgroundLayer', () => {
filter: ['==', 'arbitraryFilter', true],
minZoomLevel: 3,
maxZoomLevel: 8,
- style: {visibility: 'none'},
+ style: { visibility: 'none' },
};
- const {queryByTestId} = render();
- const backgroundLayer = queryByTestId('rctmglBackgroundLayer');
- const {props} = backgroundLayer;
+ const { container: backgroundLayer } = render(
+ ,
+ );
+ const { props } = backgroundLayer;
expect(props.id).toStrictEqual(testProps.id);
expect(props.sourceID).toStrictEqual(testProps.sourceID);
@@ -44,10 +42,13 @@ describe('BackgroundLayer', () => {
expect(props.filter).toStrictEqual(testProps.filter);
expect(props.minZoomLevel).toStrictEqual(testProps.minZoomLevel);
expect(props.maxZoomLevel).toStrictEqual(testProps.maxZoomLevel);
- expect(props.reactStyle).toStrictEqual({
+ expect(props.style).toStrictEqual(testProps.style);
+
+ // abstract layer props
+ expect(backgroundLayer.children[0].props.reactStyle).toStrictEqual({
visibility: {
styletype: 'constant',
- stylevalue: {type: 'string', value: testProps.style.visibility},
+ stylevalue: { type: 'string', value: testProps.style.visibility },
},
});
});
diff --git a/__tests__/components/Callout.test.js b/__tests__/components/Callout.test.js
index 8d112bf0d..4c2e29d1a 100644
--- a/__tests__/components/Callout.test.js
+++ b/__tests__/components/Callout.test.js
@@ -1,20 +1,20 @@
import React from 'react';
-import {render} from 'react-native-testing-library';
-import {Text, View} from 'react-native';
+import { render } from '@testing-library/react-native';
+import { Text, View } from 'react-native';
-import Callout from '../../javascript/components/Callout';
+import Callout from '../../src/components/Callout';
describe('Callout', () => {
test('renders with custom title', () => {
const testTitle = 'test title';
- const {getByText} = render();
+ const { getByText } = render();
expect(getByText(testTitle)).toBeDefined();
});
describe('_renderDefaultCallout', () => {
test('renders default children', () => {
- const {UNSAFE_getByType, UNSAFE_getAllByType} = render();
+ const { UNSAFE_getByType, UNSAFE_getAllByType } = render();
const callout = UNSAFE_getByType('RCTMGLCallout');
expect(callout).toBeDefined();
@@ -24,13 +24,13 @@ describe('Callout', () => {
test('renders with custom styles', () => {
const testProps = {
- style: {height: 1},
- containerStyle: {height: 2},
- contentStyle: {height: 3},
- tipStyle: {height: 4},
- textStyle: {height: 5},
+ style: { height: 1 },
+ containerStyle: { height: 2 },
+ contentStyle: { height: 3 },
+ tipStyle: { height: 4 },
+ textStyle: { height: 5 },
};
- const {UNSAFE_getByType, UNSAFE_getAllByType} = render(
+ const { UNSAFE_getByType, UNSAFE_getAllByType } = render(
,
);
@@ -56,7 +56,7 @@ describe('Callout', () => {
describe('_renderCustomCallout', () => {
test('renders custom children', () => {
- const {getByTestId, UNSAFE_queryByType} = render(
+ const { getByTestId, UNSAFE_queryByType } = render(
{'Foo Bar'}
,
@@ -68,10 +68,10 @@ describe('Callout', () => {
test('renders with custom styles', () => {
const testProps = {
- style: {width: 1},
- containerStyle: {width: 2},
+ style: { width: 1 },
+ containerStyle: { width: 2 },
};
- const {UNSAFE_getByType, UNSAFE_getAllByType} = render(
+ const { UNSAFE_getByType, UNSAFE_getAllByType } = render(
{'Foo Bar'}
,
diff --git a/__tests__/components/Camera.test.js b/__tests__/components/Camera.test.js
index dd8c70cfe..bf2ff931e 100644
--- a/__tests__/components/Camera.test.js
+++ b/__tests__/components/Camera.test.js
@@ -1,1099 +1,71 @@
import React from 'react';
-import {render} from 'react-native-testing-library';
+import { render } from '@testing-library/react-native';
-import Camera from '../../javascript/components/Camera';
+import { Camera } from '../../src/components/Camera';
-const cameraWithoutFollowDefault = {
- animationDuration: 2000,
- animationMode: 'easeTo',
- centerCoordinate: [-111.8678, 40.2866],
- zoomLevel: 16,
- followUserLocation: false,
- followUserMode: 'normal',
- isUserInteraction: false,
-};
+const coordinate1 = [-111.8678, 40.2866];
-const cameraWithoutFollowChanged = {
- animationDuration: 1000,
- animationMode: 'easeTo',
- centerCoordinate: [-110.8678, 37.2866],
- zoomLevel: 13,
- followUserLocation: false,
- followUserMode: 'normal',
- isUserInteraction: false,
+const bounds1 = {
+ ne: [-74.12641, 40.797968],
+ sw: [-74.143727, 40.772177],
};
-const cameraWithFollowCourse = {
- animationDuration: 2000,
- animationMode: 'easeTo',
- defaultSettings: {
- centerCoordinate: [-111.8678, 40.2866],
- zoomLevel: 16,
- },
- followUserLocation: true,
- followUserMode: 'course',
- isUserInteraction: false,
+const paddingZero = {
+ paddingTop: 0,
+ paddingRight: 0,
+ paddingBottom: 0,
+ paddingLeft: 0,
};
-const cameraWithBounds = {
- animationDuration: 2000,
- animationMode: 'easeTo',
- bounds: {
- ne: [-74.12641, 40.797968],
- sw: [-74.143727, 40.772177],
- },
- isUserInteraction: false,
- maxZoomLevel: 19,
+const toFeature = (position) => {
+ return {
+ type: 'Feature',
+ geometry: {
+ type: 'Point',
+ coordinates: position,
+ },
+ properties: {},
+ };
};
+const toFeatureCollection = (bounds) => {
+ return {
+ type: 'FeatureCollection',
+ features: [toFeature(bounds.ne), toFeature(bounds.sw)],
+ };
+};
describe('Camera', () => {
- describe('render', () => {
- test('renders correctly', () => {
- const {getByTestId} = render();
-
- expect(getByTestId('Camera')).toBeDefined();
- });
-
- test('has proper default props', () => {
- const {getByTestId} = render();
-
- expect(getByTestId('Camera').props).toStrictEqual({
- children: undefined,
- testID: 'Camera',
- followUserLocation: undefined,
- followUserMode: undefined,
- followPitch: undefined,
- followHeading: undefined,
- followZoomLevel: undefined,
- stop: {
- mode: 'Ease',
- pitch: undefined,
- heading: undefined,
- duration: 2000,
- zoom: undefined,
- },
- maxZoomLevel: undefined,
- minZoomLevel: undefined,
- maxBounds: null,
- defaultStop: null,
- onUserTrackingModeChange: undefined,
- });
+ test('defaults are set', () => {
+ const result = render();
+ const { props } = result.queryByTestId('Camera');
+ expect(props.stop).toStrictEqual({
+ ...paddingZero,
});
});
-
- describe('class', () => {
- test('correct "UserTrackingModes" statics', () => {
- expect(Camera.UserTrackingModes).toStrictEqual({
- Follow: 'normal',
- FollowWithCourse: 'course',
- FollowWithHeading: 'compass',
- });
+ test('set location by center', () => {
+ const result = render(
+ ,
+ );
+ const { props } = result.queryByTestId('Camera');
+ props.stop.centerCoordinate = JSON.parse(props.stop.centerCoordinate);
+ expect(props.stop).toStrictEqual({
+ centerCoordinate: toFeature(coordinate1),
+ zoom: 14,
+ ...paddingZero,
});
});
-
- describe('methods', () => {
- describe('#_handleCameraChange', () => {
- let camera;
-
- beforeEach(() => {
- camera = new Camera();
-
- // set up fake ref
- camera.refs = {
- camera: {
- setNativeProps: jest.fn(),
- },
- };
-
- // set up fake props
- // we only do this, because we want to test the class methods!
- camera.props = {};
-
- jest.spyOn(camera, '_setCamera');
- jest.spyOn(camera, '_hasCameraChanged');
- jest.spyOn(camera, '_hasBoundsChanged');
- });
-
- test('does not call "#_setCamera" or "#setNativeProps" when "nextCamera" has no changes to "currentCamera"', () => {
- camera._handleCameraChange(
- cameraWithoutFollowDefault,
- cameraWithoutFollowDefault,
- );
-
- expect(camera._hasCameraChanged).toHaveBeenCalled();
- expect(camera._setCamera).not.toHaveBeenCalled();
- expect(camera.refs.camera.setNativeProps).not.toHaveBeenCalled();
- });
-
- test('sets "followUserLocation" to false when it was removed on "nextCamera"', () => {
- camera._handleCameraChange(
- cameraWithFollowCourse,
- cameraWithoutFollowDefault,
- );
-
- expect(camera._hasCameraChanged).toHaveBeenCalled();
- expect(camera._setCamera).not.toHaveBeenCalled();
-
- expect(camera.refs.camera.setNativeProps).toHaveBeenCalledTimes(1);
-
- expect(camera.refs.camera.setNativeProps).toHaveBeenCalledWith({
- followUserLocation: false,
- });
- });
-
- test('sets "followUserLocation" to true when it was added on "nextCamera"', () => {
- camera._handleCameraChange(
- cameraWithoutFollowDefault,
- cameraWithFollowCourse,
- );
-
- expect(camera._hasCameraChanged).toHaveBeenCalled();
- expect(camera._setCamera).not.toHaveBeenCalled();
-
- expect(camera.refs.camera.setNativeProps).toHaveBeenCalledTimes(2);
-
- expect(camera.refs.camera.setNativeProps).toHaveBeenNthCalledWith(1, {
- followUserLocation: true,
- });
- expect(camera.refs.camera.setNativeProps).toHaveBeenNthCalledWith(2, {
- followHeading: undefined,
- followPitch: undefined,
- followUserMode: 'course',
- followZoomLevel: undefined,
- });
- });
-
- test('calls "#_setCamera" when "nextCamera" "hasChanged" without bounds', () => {
- camera._handleCameraChange(
- cameraWithoutFollowDefault,
- cameraWithoutFollowChanged,
- );
-
- expect(camera._hasCameraChanged).toHaveBeenCalled();
- expect(camera._hasBoundsChanged).not.toHaveBeenCalled();
- expect(camera._setCamera).toHaveBeenCalledWith({
- animationDuration: 1000,
- animationMode: 'easeTo',
- centerCoordinate: [-110.8678, 37.2866],
- heading: undefined,
- pitch: undefined,
- zoomLevel: 13,
- });
- });
-
- test('calls "#_hasBoundsChanged" & "#_setCamera" when "nextCamera" "hasChanged" with bounds', () => {
- camera._handleCameraChange(
- cameraWithoutFollowDefault,
- cameraWithBounds,
- );
-
- expect(camera._hasCameraChanged).toHaveBeenCalled();
- expect(camera._hasBoundsChanged).toHaveBeenCalledTimes(1);
- expect(camera._setCamera).toHaveBeenCalledWith({
- animationDuration: 2000,
- animationMode: 'easeTo',
- bounds: {ne: [-74.12641, 40.797968], sw: [-74.143727, 40.772177]},
- heading: undefined,
- pitch: undefined,
- zoomLevel: undefined,
- });
- });
- });
-
- describe('#_hasCameraChanged', () => {
- let camera;
-
- beforeEach(() => {
- camera = new Camera();
-
- // set up fake ref
- camera.refs = {
- camera: {
- setNativeProps: jest.fn(),
- },
- };
-
- // set up fake props
- // we only do this, because we want to test the class methods!
- camera.props = {};
-
- jest.spyOn(camera, '_hasCenterCoordinateChanged');
- jest.spyOn(camera, '_hasBoundsChanged');
- });
-
- test('returns true if "hasDefaultPropsChanged"', () => {
- const testCases = [
- [{heading: 120}, {heading: 121}],
- [
- {
- centerCoordinate: [-111.8678, 40.2866],
- },
- {
- centerCoordinate: [-111.8678, 38.2866],
- },
- ],
- [
- {
- bounds: {
- ne: [-74.12641, 40.797968],
- sw: [-74.143727, 40.772177],
- },
- },
- {
- bounds: {
- ne: [-64.12641, 40.797968],
- sw: [-74.143727, 40.772177],
- },
- },
- ],
- [
- {
- pitch: 45,
- },
- {
- pitch: 55,
- },
- ],
- [
- {
- zoomLevel: 10,
- },
- {
- zoomLevel: 15,
- },
- ],
- [
- // using the usecase in /example
- {
- triggerKey: 1582486618640, // Date.now()
- },
- {
- triggerKey: 1582486626818, // Date.now()
- },
- ],
- ];
-
- testCases.forEach((c) => {
- expect(camera._hasCameraChanged(c[0], c[1])).toBe(true);
- });
- });
-
- test('returns true if "hasFollowPropsChanged"', () => {
- const testCases = [
- [{followUserLocation: false}, {followUserLocation: true}],
- [{followUserMode: 'normal'}, {followUserMode: 'course'}],
- [{followZoomLevel: 10}, {followZoomLevel: 13}],
- [{followHeading: 100}, {followHeading: 110}],
- [{followPitch: 40}, {followPitch: 49}],
- ];
-
- testCases.forEach((c) => {
- expect(camera._hasCameraChanged(c[0], c[1])).toBe(true);
- });
- });
-
- test('returns true if "hasAnimationPropsChanged"', () => {
- const testCases = [
- [{animationDuration: 3000}, {animationDuration: 1000}],
- [{animationMode: 'flyTo'}, {animationMode: 'easeTo'}],
- ];
-
- testCases.forEach((c) => {
- expect(camera._hasCameraChanged(c[0], c[1])).toBe(true);
- });
- });
- });
-
- describe('#_hasCenterCoordinateChanged', () => {
- const camera = new Camera();
-
- test('returns false when centerCoordinates are missing', () => {
- expect(camera._hasCenterCoordinateChanged({}, {})).toBe(false);
- });
-
- test('returns false when centerCoordinates have not changed', () => {
- expect(
- camera._hasCenterCoordinateChanged(
- {centerCoordinate: [-111.8678, 40.2866]},
- {centerCoordinate: [-111.8678, 40.2866]},
- ),
- ).toBe(false);
- });
-
- test('returns true when centerCoordinates have changed', () => {
- expect(
- camera._hasCenterCoordinateChanged(
- {centerCoordinate: [-111.8678, 40.2866]},
- {},
- ),
- ).toBe(true);
-
- expect(
- camera._hasCenterCoordinateChanged(
- {},
- {centerCoordinate: [-111.8678, 40.2866]},
- ),
- ).toBe(true);
-
- // isLngDiff
- expect(
- camera._hasCenterCoordinateChanged(
- {centerCoordinate: [-111.2678, 40.2866]},
- {centerCoordinate: [-111.8678, 40.2866]},
- ),
- ).toBe(true);
-
- // isLatDiff
- expect(
- camera._hasCenterCoordinateChanged(
- {centerCoordinate: [-111.2678, 40.2866]},
- {centerCoordinate: [-111.8678, 33.2866]},
- ),
- ).toBe(true);
- });
- });
-
- describe('#_hasBoundsChanged', () => {
- const camera = new Camera();
- const bounds = {
- bounds: {
- ne: [-74.12641, 40.797968],
- sw: [-74.143727, 40.772177],
- paddingTop: 5,
- paddingLeft: 5,
- paddingRight: 5,
- paddingBottom: 5,
- },
- };
-
- test('returns false when bounds are missing', () => {
- expect(camera._hasBoundsChanged({}, {})).toBe(false);
- });
-
- test('returns false when bounds have not changed', () => {
- expect(camera._hasBoundsChanged(bounds, bounds)).toBe(false);
- });
-
- test('returns true when bound props have changed', () => {
- // ne[0]
- expect(
- camera._hasBoundsChanged(bounds, {
- bounds: {
- ...bounds.bounds,
- ne: [-34.12641, 40.797968],
- },
- }),
- ).toBe(true);
-
- // ne[1]
- expect(
- camera._hasBoundsChanged(bounds, {
- bounds: {
- ...bounds.bounds,
- ne: [-74.12641, 30.797968],
- },
- }),
- ).toBe(true);
-
- // sw[0]
- expect(
- camera._hasBoundsChanged(bounds, {
- bounds: {
- ...bounds.bounds,
- sw: [-74.143723, 40.772177],
- },
- }),
- ).toBe(true);
-
- // sw[1]
- expect(
- camera._hasBoundsChanged(bounds, {
- bounds: {
- ...bounds.bounds,
- sw: [-74.143727, 40.772137],
- },
- }),
- ).toBe(true);
-
- // paddingTop
- expect(
- camera._hasBoundsChanged(bounds, {
- bounds: {
- ...bounds.bounds,
- paddingTop: 3,
- },
- }),
- ).toBe(true);
-
- // paddingLeft
- expect(
- camera._hasBoundsChanged(bounds, {
- bounds: {
- ...bounds.bounds,
- paddingLeft: 3,
- },
- }),
- ).toBe(true);
-
- // paddingRight
- expect(
- camera._hasBoundsChanged(bounds, {
- bounds: {
- ...bounds.bounds,
- paddingRight: 3,
- },
- }),
- ).toBe(true);
-
- // paddingBottom
- expect(
- camera._hasBoundsChanged(bounds, {
- bounds: {
- ...bounds.bounds,
- paddingBottom: 3,
- },
- }),
- ).toBe(true);
- });
- });
-
- describe('#fitBounds', () => {
- const camera = new Camera();
- const ne = [-63.12641, 39.797968];
- const sw = [-74.143727, 40.772177];
-
- beforeEach(() => {
- camera.setCamera = jest.fn();
- });
-
- test('works without provided "padding" and/ or "animationDuration"', () => {
- // FIXME: animationDuration and padding of null lead to malformed setCamera config
-
- const expectedCallResults = [
- {
- animationDuration: null,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: null,
- paddingLeft: null,
- paddingRight: null,
- paddingTop: null,
- sw: [-74.143727, 40.772177],
- },
- },
- {
- animationDuration: 0,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: null,
- paddingLeft: null,
- paddingRight: null,
- paddingTop: null,
- sw: [-74.143727, 40.772177],
- },
- },
- {
- animationDuration: 0,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 0,
- paddingLeft: 0,
- paddingRight: 0,
- paddingTop: 0,
- sw: [-74.143727, 40.772177],
- },
- },
- ];
-
- camera.fitBounds(ne, sw, null, null);
- camera.fitBounds(ne, sw, null);
- camera.fitBounds(ne, sw);
-
- camera.setCamera.mock.calls.forEach((call, i) => {
- expect(call[0]).toStrictEqual(expectedCallResults[i]);
- });
- });
-
- // TODO: Refactor #fitBounds to throw when ne or sw aren't provided
- // This is a public method and people will call it with all sorts of data
- test.skip('throws when "ne" or "sw" are missing', () => {});
-
- test('works with "padding" being a single number', () => {
- const expectedCallResult = {
- animationDuration: 500,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 3,
- paddingLeft: 3,
- paddingRight: 3,
- paddingTop: 3,
- sw: [-74.143727, 40.772177],
- },
- };
-
- camera.fitBounds(ne, sw, 3, 500);
- expect(camera.setCamera).toHaveBeenCalledWith(expectedCallResult);
- });
-
- test('works with "padding" being an array of two numbers', () => {
- const expectedCallResult = {
- animationDuration: 500,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 3,
- paddingLeft: 5,
- paddingRight: 5,
- paddingTop: 3,
- sw: [-74.143727, 40.772177],
- },
- };
-
- camera.fitBounds(ne, sw, [3, 5], 500);
- expect(camera.setCamera).toHaveBeenCalledWith(expectedCallResult);
- });
-
- test('works with "padding" being an array of four numbers', () => {
- const expectedCallResult = {
- animationDuration: 500,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 8,
- paddingLeft: 10,
- paddingRight: 5,
- paddingTop: 3,
- sw: [-74.143727, 40.772177],
- },
- };
-
- camera.fitBounds(ne, sw, [3, 5, 8, 10], 500);
- expect(camera.setCamera).toHaveBeenCalledWith(expectedCallResult);
- });
- });
-
- describe('#flyTo', () => {
- const camera = new Camera();
-
- beforeEach(() => {
- camera.setCamera = jest.fn();
- });
-
- test.skip('throws when no coordinates are provided', () => {
- // TODO: Refactor #flyTo to throw when coordinates aren't provided
- // This is a public method and people will call it with all sorts of data
- });
-
- test('sets default "animationDuration" when called without it', () => {
- camera.flyTo([-111.8678, 40.2866]);
- expect(camera.setCamera).toHaveBeenCalledWith({
- animationDuration: 2000,
- animationMode: 'flyTo',
- centerCoordinate: [-111.8678, 40.2866],
- });
- });
-
- test('calls "setCamera" with correct config', () => {
- camera.flyTo([-111.8678, 40.2866], 5000);
- expect(camera.setCamera).toHaveBeenCalledWith({
- animationDuration: 5000,
- animationMode: 'flyTo',
- centerCoordinate: [-111.8678, 40.2866],
- });
- });
- });
-
- describe('#moveTo', () => {
- const camera = new Camera();
-
- beforeEach(() => {
- // FIXME: Why is moveTo calling #_setCamera instead of #setCamera?
- // let's be consistent here - have all methods use one of both
- camera._setCamera = jest.fn();
- });
-
- test.skip('throws when no coordinates are provided', () => {
- // TODO: Refactor #moveTo to throw when coordinates aren't provided
- // This is a public method and people will call it with all sorts of data
- });
-
- test('sets default "animationDuration" when called without it', () => {
- camera.moveTo([-111.8678, 40.2866]);
- expect(camera._setCamera).toHaveBeenCalledWith({
- animationDuration: 0,
- centerCoordinate: [-111.8678, 40.2866],
- });
- });
-
- test('calls "_setCamera" with correct config', () => {
- camera.moveTo([-111.8678, 40.2866], 5000);
- expect(camera._setCamera).toHaveBeenCalledWith({
- animationDuration: 5000,
- centerCoordinate: [-111.8678, 40.2866],
- });
- });
- });
-
- describe('#zoomTo', () => {
- const camera = new Camera();
-
- beforeEach(() => {
- camera._setCamera = jest.fn();
- });
-
- test.skip('throws when no zoomLevel is provided', () => {
- // TODO: Refactor #moveTo to throw when coordinates aren't provided
- // This is a public method and people will call it with all sorts of data
- });
-
- test('sets default "animationDuration" when called without it', () => {
- camera.zoomTo(10);
- expect(camera._setCamera).toHaveBeenCalledWith({
- animationDuration: 2000,
- zoomLevel: 10,
- animationMode: 'flyTo',
- });
- });
-
- test('calls "_setCamera" with correct config', () => {
- camera.zoomTo(10, 3000);
- expect(camera._setCamera).toHaveBeenCalledWith({
- animationDuration: 3000,
- zoomLevel: 10,
- animationMode: 'flyTo',
- });
- });
- });
-
- describe('#setCamera', () => {
- const camera = new Camera();
-
- beforeEach(() => {
- camera._setCamera = jest.fn();
- });
-
- test('sets default empty "config" when called without one', () => {
- camera.setCamera();
- expect(camera._setCamera).toHaveBeenCalledWith({});
- });
-
- test('calls "_setCamera" with passed config', () => {
- const config = {
- animationDuration: 500,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 8,
- paddingLeft: 10,
- paddingRight: 5,
- paddingTop: 3,
- sw: [-74.143727, 40.772177],
- },
- };
-
- camera.setCamera(config);
- expect(camera._setCamera).toHaveBeenCalledWith(config);
- });
- });
-
- describe('#_setCamera', () => {
- const camera = new Camera();
-
- beforeEach(() => {
- jest.spyOn(Camera.prototype, '_createStopConfig');
-
- // set up fake ref
- camera.refs = {
- camera: {
- setNativeProps: jest.fn(),
- },
- };
-
- // set up fake props
- // we only do this, because we want to test the class methods!
- camera.props = {};
-
- jest.clearAllMocks();
- });
-
- test('calls "_createStopConfig" and passes stopConfig to "setNativeProps"', () => {
- const config = {
- animationDuration: 500,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 8,
- paddingLeft: 10,
- paddingRight: 5,
- paddingTop: 3,
- sw: [-74.143727, 40.772177],
- },
- heading: 100,
- pitch: 45,
- zoomLevel: 11,
- };
-
- camera._setCamera(config);
-
- expect(camera._createStopConfig).toHaveBeenCalledWith({
- animationDuration: 500,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 8,
- paddingLeft: 10,
- paddingRight: 5,
- paddingTop: 3,
- sw: [-74.143727, 40.772177],
- },
- heading: 100,
- pitch: 45,
- zoomLevel: 11,
- });
-
- expect(camera._createStopConfig).toHaveBeenCalledTimes(1);
-
- expect(camera.refs.camera.setNativeProps).toHaveBeenCalledWith({
- stop: {
- bounds:
- '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-63.12641,39.797968]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-74.143727,40.772177]}}]}',
- boundsPaddingBottom: 8,
- boundsPaddingLeft: 10,
- boundsPaddingRight: 5,
- boundsPaddingTop: 3,
- duration: 500,
- heading: 100,
- mode: 'Ease',
- pitch: 45,
- zoom: 11,
- },
- });
- });
-
- test('creates multiple stops when provided', () => {
- const config = {
- stops: [
- {
- animationDuration: 50,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 2,
- paddingLeft: 2,
- paddingRight: 2,
- paddingTop: 2,
- sw: [-74.143727, 40.772177],
- },
- heading: 20,
- pitch: 25,
- zoomLevel: 16,
- },
- {
- animationDuration: 3000,
- animationMode: 'flyTo',
- bounds: {
- ne: [-63.12641, 59.797968],
- paddingBottom: 8,
- paddingLeft: 10,
- paddingRight: 5,
- paddingTop: 3,
- sw: [-71.143727, 40.772177],
- },
- heading: 40,
- pitch: 45,
- zoomLevel: 8,
- },
- {
- animationDuration: 500,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 8,
- paddingLeft: 10,
- paddingRight: 5,
- paddingTop: 3,
- sw: [-74.143727, 40.772177],
- },
- heading: 100,
- pitch: 45,
- zoomLevel: 11,
- },
- ],
- };
-
- camera._setCamera(config);
-
- expect(camera._createStopConfig).toHaveBeenCalledTimes(3);
-
- expect(camera._createStopConfig).toHaveBeenCalledWith({
- animationDuration: 500,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 8,
- paddingLeft: 10,
- paddingRight: 5,
- paddingTop: 3,
- sw: [-74.143727, 40.772177],
- },
- heading: 100,
- pitch: 45,
- zoomLevel: 11,
- });
-
- expect(camera.refs.camera.setNativeProps).toHaveBeenCalledWith({
- stop: {
- stops: [
- {
- bounds:
- '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-63.12641,39.797968]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-74.143727,40.772177]}}]}',
- boundsPaddingBottom: 2,
- boundsPaddingLeft: 2,
- boundsPaddingRight: 2,
- boundsPaddingTop: 2,
- duration: 50,
- heading: 20,
- mode: 'Ease',
- pitch: 25,
- zoom: 16,
- },
- {
- bounds:
- '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-63.12641,59.797968]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-71.143727,40.772177]}}]}',
- boundsPaddingBottom: 8,
- boundsPaddingLeft: 10,
- boundsPaddingRight: 5,
- boundsPaddingTop: 3,
- duration: 3000,
- heading: 40,
- mode: 'Flight',
- pitch: 45,
- zoom: 8,
- },
- {
- bounds:
- '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-63.12641,39.797968]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-74.143727,40.772177]}}]}',
- boundsPaddingBottom: 8,
- boundsPaddingLeft: 10,
- boundsPaddingRight: 5,
- boundsPaddingTop: 3,
- duration: 500,
- heading: 100,
- mode: 'Ease',
- pitch: 45,
- zoom: 11,
- },
- ],
- },
- });
- });
- });
-
- describe('#_createDefaultCamera', () => {
- const camera = new Camera();
-
- beforeEach(() => {});
-
- test('returns null without "defaultSettings"', () => {
- camera.props = {};
- expect(camera._createDefaultCamera()).toBe(null);
- });
-
- test('returns "defaultCamera" with "defaultSettings" and sets property', () => {
- camera.props = {
- defaultSettings: {
- centerCoordinate: [-111.8678, 40.2866],
- zoomLevel: 16,
- },
- };
-
- const defaultCamera = {
- centerCoordinate:
- '{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-111.8678,40.2866]}}',
- duration: 0,
- heading: undefined,
- mode: 'None',
- pitch: undefined,
- zoom: 16,
- };
-
- expect(camera.defaultCamera).toStrictEqual(undefined);
- expect(camera._createDefaultCamera()).toStrictEqual(defaultCamera);
- expect(camera.defaultCamera).toStrictEqual(defaultCamera);
- });
- });
-
- describe('#_createStopConfig', () => {
- const camera = new Camera();
- const configWithoutBounds = {
- animationDuration: 2000,
- pitch: 45,
- heading: 110,
- zoomLevel: 9,
- };
-
- const configWithBounds = {
- animationDuration: 500,
- animationMode: 'easeTo',
- bounds: {
- ne: [-63.12641, 39.797968],
- paddingBottom: 8,
- paddingLeft: 10,
- paddingRight: 5,
- paddingTop: 3,
- sw: [-74.143727, 40.772177],
- },
- heading: 100,
- pitch: 45,
- zoomLevel: 11,
- };
-
- beforeEach(() => {
- jest.spyOn(Camera.prototype, '_getNativeCameraMode');
-
- jest.clearAllMocks();
- });
-
- test('returns null with "followUserLocation" prop and "!ignoreFollowUserLocation"', () => {
- camera.props = {
- followUserLocation: true,
- };
- expect(camera._createStopConfig()).toBe(null);
- });
-
- test('returns correct "stopConfig" without bounds', () => {
- camera.props = {
- followUserLocation: true,
- };
-
- expect(
- camera._createStopConfig(configWithoutBounds, true),
- ).toStrictEqual({
- duration: 2000,
- heading: 110,
- mode: 'Ease',
- pitch: 45,
- zoom: 9,
- });
-
- // with centerCoordinate
- expect(
- camera._createStopConfig(
- {...configWithoutBounds, centerCoordinate: [-111.8678, 40.2866]},
- true,
- ),
- ).toStrictEqual({
- centerCoordinate:
- '{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-111.8678,40.2866]}}',
- duration: 2000,
- heading: 110,
- mode: 'Ease',
- pitch: 45,
- zoom: 9,
- });
- });
-
- test('returns correct "stopConfig" with bounds', () => {
- camera.props = {
- followUserLocation: true,
- };
-
- expect(camera._createStopConfig(configWithBounds, true)).toStrictEqual({
- bounds:
- '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-63.12641,39.797968]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-74.143727,40.772177]}}]}',
- boundsPaddingBottom: 8,
- boundsPaddingLeft: 10,
- boundsPaddingRight: 5,
- boundsPaddingTop: 3,
- duration: 500,
- heading: 100,
- mode: 'Ease',
- pitch: 45,
- zoom: 11,
- });
-
- // with centerCoordinate
- expect(
- camera._createStopConfig(
- {...configWithBounds, centerCoordinate: [-111.8678, 40.2866]},
- true,
- ),
- ).toStrictEqual({
- bounds:
- '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-63.12641,39.797968]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-74.143727,40.772177]}}]}',
- boundsPaddingBottom: 8,
- boundsPaddingLeft: 10,
- boundsPaddingRight: 5,
- boundsPaddingTop: 3,
- centerCoordinate:
- '{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-111.8678,40.2866]}}',
- duration: 500,
- heading: 100,
- mode: 'Ease',
- pitch: 45,
- zoom: 11,
- });
- });
- });
-
- describe('#_getNativeCameraMode', () => {
- const camera = new Camera();
-
- test('returns "Flight" for "flyTo"', () => {
- expect(
- camera._getNativeCameraMode({animationMode: 'flyTo'}),
- ).toStrictEqual('Flight');
- });
-
- test('returns "None" for "moveTo"', () => {
- expect(
- camera._getNativeCameraMode({animationMode: 'moveTo'}),
- ).toStrictEqual('None');
- });
-
- test('returns "Ease" as default', () => {
- expect(camera._getNativeCameraMode({})).toStrictEqual('Ease');
- });
- });
-
- describe('#_getMaxBounds', () => {
- const camera = new Camera();
-
- test('returns null if no "maxBounds"', () => {
- camera.props = {};
- expect(camera._getMaxBounds()).toStrictEqual(null);
-
- camera.props = {
- maxBounds: {
- ne: [-74.12641, 40.797968],
- },
- };
- expect(camera._getMaxBounds()).toStrictEqual(null);
-
- camera.props = {
- maxBounds: {
- sw: [-74.143727, 40.772177],
- },
- };
- expect(camera._getMaxBounds()).toStrictEqual(null);
- });
-
- test('returns maxBounds when "maxBounds" property is set', () => {
- camera.props = {
- maxBounds: {
- ne: [-74.12641, 40.797968],
- sw: [-74.143727, 40.772177],
- },
- };
-
- expect(camera._getMaxBounds()).toStrictEqual(
- '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-74.12641,40.797968]}},{"type":"Feature","properties":{},"geometry":{"type":"Point","coordinates":[-74.143727,40.772177]}}]}',
- );
- });
+ test('set location by bounds', () => {
+ const result = render();
+ const { props } = result.queryByTestId('Camera');
+ props.stop.bounds = JSON.parse(props.stop.bounds);
+ expect(props.stop).toStrictEqual({
+ bounds: toFeatureCollection(bounds1),
+ ...paddingZero,
});
});
+ test('animation mode', () => {
+ const result = render();
+ const { props } = result.queryByTestId('Camera');
+ expect(props.stop.mode).toEqual('Move');
+ });
});
diff --git a/__tests__/components/CircleLayer.test.js b/__tests__/components/CircleLayer.test.js
index 1efda4eba..b67122942 100644
--- a/__tests__/components/CircleLayer.test.js
+++ b/__tests__/components/CircleLayer.test.js
@@ -1,13 +1,14 @@
import React from 'react';
-import {render} from 'react-native-testing-library';
+import { render } from '@testing-library/react-native';
-import CircleLayer from '../../javascript/components/CircleLayer';
+import CircleLayer from '../../src/components/CircleLayer';
describe('CircleLayer', () => {
test('renders correctly with default props', () => {
- const {queryByTestId} = render();
- const circleLayer = queryByTestId('rctmglCircleLayer');
- const {props} = circleLayer;
+ const { container: circleLayer } = render(
+ ,
+ );
+ const { props } = circleLayer;
expect(props.sourceID).toStrictEqual('DefaultSourceID');
});
@@ -23,12 +24,11 @@ describe('CircleLayer', () => {
filter: ['==', 'arbitraryFilter', true],
minZoomLevel: 3,
maxZoomLevel: 8,
- style: {visibility: 'none'},
+ style: { visibility: 'none' },
};
- const {queryByTestId} = render();
- const circleLayer = queryByTestId('rctmglCircleLayer');
- const {props} = circleLayer;
+ const { container: circleLayer } = render();
+ const { props } = circleLayer;
expect(props.id).toStrictEqual(customProps.id);
expect(props.sourceID).toStrictEqual(customProps.sourceID);
@@ -39,10 +39,13 @@ describe('CircleLayer', () => {
expect(props.filter).toStrictEqual(customProps.filter);
expect(props.minZoomLevel).toStrictEqual(customProps.minZoomLevel);
expect(props.maxZoomLevel).toStrictEqual(customProps.maxZoomLevel);
- expect(props.reactStyle).toStrictEqual({
+ expect(props.style).toStrictEqual(customProps.style);
+
+ // abstract layer props
+ expect(circleLayer.children[0].props.reactStyle).toStrictEqual({
visibility: {
styletype: 'constant',
- stylevalue: {type: 'string', value: customProps.style.visibility},
+ stylevalue: { type: 'string', value: customProps.style.visibility },
},
});
});
diff --git a/__tests__/components/HeatmapLayer.test.js b/__tests__/components/HeatmapLayer.test.js
index 2c5e8e034..b32b62977 100644
--- a/__tests__/components/HeatmapLayer.test.js
+++ b/__tests__/components/HeatmapLayer.test.js
@@ -1,15 +1,14 @@
import React from 'react';
-import {render} from 'react-native-testing-library';
+import { render } from '@testing-library/react-native';
-import HeatmapLayer from '../../javascript/components/HeatmapLayer';
+import HeatmapLayer from '../../src/components/HeatmapLayer';
describe('HeatmapLayer', () => {
test('renders correctly with default props', () => {
- const {UNSAFE_getByType} = render(
+ const { container: heatmapLayer } = render(
,
);
- const heatmapLayer = UNSAFE_getByType('RCTMGLHeatmapLayer');
- const {props} = heatmapLayer;
+ const { props } = heatmapLayer;
expect(props.sourceID).toStrictEqual('DefaultSourceID');
});
@@ -24,10 +23,10 @@ describe('HeatmapLayer', () => {
filter: ['==', 'arbitraryFilter', true],
minZoomLevel: 3,
maxZoomLevel: 8,
- style: {visibility: 'none'},
+ style: { visibility: 'none' },
};
- const {UNSAFE_getByType} = render();
- const {props} = UNSAFE_getByType('RCTMGLHeatmapLayer');
+ const { container: heatmapLayer } = render();
+ const { props } = heatmapLayer;
expect(props.id).toStrictEqual(testProps.id);
expect(props.sourceID).toStrictEqual(testProps.sourceID);
@@ -38,10 +37,13 @@ describe('HeatmapLayer', () => {
expect(props.filter).toStrictEqual(testProps.filter);
expect(props.minZoomLevel).toStrictEqual(testProps.minZoomLevel);
expect(props.maxZoomLevel).toStrictEqual(testProps.maxZoomLevel);
- expect(props.reactStyle).toStrictEqual({
+ expect(props.style).toStrictEqual(testProps.style);
+
+ // abstract layer props
+ expect(heatmapLayer.children[0].props.reactStyle).toStrictEqual({
visibility: {
styletype: 'constant',
- stylevalue: {type: 'string', value: testProps.style.visibility},
+ stylevalue: { type: 'string', value: testProps.style.visibility },
},
});
});
diff --git a/__tests__/components/Light.test.js b/__tests__/components/Light.test.js
new file mode 100644
index 000000000..fd21585b3
--- /dev/null
+++ b/__tests__/components/Light.test.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import { render } from '@testing-library/react-native';
+
+import Light from '../../src/components/Light';
+
+describe('Light', () => {
+ test('renders correctly', () => {
+ const { queryByTestId } = render();
+ const light = queryByTestId('rctmglLight');
+ expect(light).toBeDefined();
+ });
+
+ test('renders correctly with custom styles', () => {
+ const testStyles = {
+ position: [1234, 1234, 1234],
+ color: '#FA0000', // === ProcessedTestColor
+ anchor: 'map',
+ intensity: 1,
+ };
+ const processedTestColor = 4294574080;
+
+ const { queryByTestId } = render();
+
+ const customStyles = queryByTestId('rctmglLight').props.reactStyle;
+ const { anchor } = customStyles;
+ const { color } = customStyles;
+ const { position } = customStyles;
+ const { intensity } = customStyles;
+
+ expect(anchor.stylevalue.value).toStrictEqual(testStyles.anchor);
+ expect(color.stylevalue.value).toStrictEqual(processedTestColor);
+ expect(intensity.stylevalue.value).toStrictEqual(testStyles.intensity);
+ expect(position.stylevalue.value[0].value).toStrictEqual(
+ testStyles.position[0],
+ );
+ });
+});
diff --git a/__tests__/components/MapView.test.js b/__tests__/components/MapView.test.js
index 46eb2cac5..e580fe217 100644
--- a/__tests__/components/MapView.test.js
+++ b/__tests__/components/MapView.test.js
@@ -1,16 +1,16 @@
import * as React from 'react';
-import {render} from 'react-native-testing-library';
+import { render } from '@testing-library/react-native';
-import MapView from '../../javascript/components/MapView';
+import MapView from '../../src/components/MapView';
describe('MapView', () => {
test('renders with testID', () => {
const expectedTestId = 'im used for identification in tests';
- const {getByTestId} = render();
+ const { getByTestId } = render();
expect(() => {
getByTestId(expectedTestId);
- }).not.toThrowError();
+ }).not.toThrow();
});
});
diff --git a/__tests__/components/Style.test.js b/__tests__/components/Style.test.js
index 115641588..7df5eea4d 100644
--- a/__tests__/components/Style.test.js
+++ b/__tests__/components/Style.test.js
@@ -1,19 +1,19 @@
import React from 'react';
-import {render} from 'react-native-testing-library';
+import { render } from '@testing-library/react-native';
-import VectorSource from '../../javascript/components/VectorSource';
-import RasterSource from '../../javascript/components/RasterSource';
-import ImageSource from '../../javascript/components/ImageSource';
-import ShapeSource from '../../javascript/components/ShapeSource';
-import Style from '../../javascript/components/Style';
-import HeatmapLayer from '../../javascript/components/HeatmapLayer';
-import CircleLayer from '../../javascript/components/CircleLayer';
-import SymbolLayer from '../../javascript/components/SymbolLayer';
-import RasterLayer from '../../javascript/components/RasterLayer';
-import LineLayer from '../../javascript/components/LineLayer';
-import FillLayer from '../../javascript/components/FillLayer';
-import FillExtrusionLayer from '../../javascript/components/FillExtrusionLayer';
-import BackgroundLayer from '../../javascript/components/BackgroundLayer';
+import VectorSource from '../../src/components/VectorSource';
+import RasterSource from '../../src/components/RasterSource';
+import ImageSource from '../../src/components/ImageSource';
+import { ShapeSource } from '../../src/components/ShapeSource';
+import Style from '../../src/components/Style';
+import HeatmapLayer from '../../src/components/HeatmapLayer';
+import CircleLayer from '../../src/components/CircleLayer';
+import { SymbolLayer } from '../../src/components/SymbolLayer';
+import RasterLayer from '../../src/components/RasterLayer';
+import LineLayer from '../../src/components/LineLayer';
+import FillLayer from '../../src/components/FillLayer';
+import FillExtrusionLayer from '../../src/components/FillExtrusionLayer';
+import BackgroundLayer from '../../src/components/BackgroundLayer';
describe('Style', () => {
test('renders vectory source correctly', () => {
@@ -34,9 +34,9 @@ describe('Style', () => {
},
};
- const {UNSAFE_getByType} = render();
+ const { UNSAFE_getByType } = render();
const component = UNSAFE_getByType(VectorSource);
- const {props} = component;
+ const { props } = component;
expect(props.id).toStrictEqual(Object.keys(json.sources)[0]);
expect(props.url).toStrictEqual(vectorSource.url);
@@ -66,9 +66,9 @@ describe('Style', () => {
},
};
- const {UNSAFE_getByType} = render();
+ const { UNSAFE_getByType } = render();
const component = UNSAFE_getByType(RasterSource);
- const {props} = component;
+ const { props } = component;
expect(props.id).toStrictEqual(Object.keys(json.sources)[0]);
expect(props.url).toStrictEqual(rasterSource.url);
@@ -99,9 +99,9 @@ describe('Style', () => {
},
};
- const {UNSAFE_getByType} = render();
+ const { UNSAFE_getByType } = render();
const component = UNSAFE_getByType(ImageSource);
- const {props} = component;
+ const { props } = component;
expect(props.id).toStrictEqual(Object.keys(json.sources)[0]);
expect(props.url).toStrictEqual(imageSource.url);
@@ -128,9 +128,9 @@ describe('Style', () => {
},
};
- const {UNSAFE_getByType} = render();
+ const { UNSAFE_getByType } = render();
const component = UNSAFE_getByType(ShapeSource);
- const {props} = component;
+ const { props } = component;
expect(props.id).toStrictEqual(Object.keys(json.sources)[0]);
expect(props.url).toStrictEqual(shapeSource.data);
@@ -158,9 +158,9 @@ describe('Style', () => {
},
};
- const {UNSAFE_getByType} = render();
+ const { UNSAFE_getByType } = render();
const component = UNSAFE_getByType(ShapeSource);
- const {props} = component;
+ const { props } = component;
expect(props.id).toStrictEqual(Object.keys(json.sources)[0]);
expect(props.shape).toStrictEqual(shapeSource.data);
@@ -205,7 +205,7 @@ describe('Style', () => {
],
};
- const {UNSAFE_getByType} = render();
+ const { UNSAFE_getByType } = render();
const circleLayer = UNSAFE_getByType(CircleLayer);
const symbolLayer = UNSAFE_getByType(SymbolLayer);
const rasterLayer = UNSAFE_getByType(RasterLayer);
@@ -245,9 +245,9 @@ describe('Style', () => {
layers: [circleLayer],
};
- const {UNSAFE_getByType} = render();
+ const { UNSAFE_getByType } = render();
const layerComponent = UNSAFE_getByType(CircleLayer);
- const {props} = layerComponent;
+ const { props } = layerComponent;
expect(props.sourceID).toStrictEqual(circleLayer.source);
expect(props.sourceLayerID).toStrictEqual(circleLayer['source-layer']);
expect(props.filter).toStrictEqual(circleLayer.filter);
diff --git a/__tests__/components/SymbolLayer.test.js b/__tests__/components/SymbolLayer.test.js
index 9e33bfc34..c4ef1eb82 100644
--- a/__tests__/components/SymbolLayer.test.js
+++ b/__tests__/components/SymbolLayer.test.js
@@ -1,18 +1,18 @@
import React from 'react';
-import {render} from 'react-native-testing-library';
-import PropTypes from 'prop-types';
+import { render } from '@testing-library/react-native';
-import SymbolLayer, {
+import {
+ SymbolLayer,
NATIVE_MODULE_NAME,
-} from '../../javascript/components/SymbolLayer';
+} from '../../src/components/SymbolLayer';
describe('SymbolLayer', () => {
test('renders correctly with default props', () => {
- const {UNSAFE_getByType} = render(
+ const { UNSAFE_getByType } = render(
,
);
const symbolLayer = UNSAFE_getByType(NATIVE_MODULE_NAME);
- const {props} = symbolLayer;
+ const { props } = symbolLayer;
expect(props.sourceID).toStrictEqual('DefaultSourceID');
});
@@ -28,12 +28,12 @@ describe('SymbolLayer', () => {
filter: ['==', 'arbitraryFilter', true],
minZoomLevel: 3,
maxZoomLevel: 8,
- style: {visibility: 'none'},
+ style: { visibility: 'none' },
};
- const {UNSAFE_getByType} = render();
+ const { UNSAFE_getByType } = render();
const symbolLayer = UNSAFE_getByType(NATIVE_MODULE_NAME);
- const {props} = symbolLayer;
+ const { props } = symbolLayer;
expect(props.id).toStrictEqual(customProps.id);
expect(props.sourceID).toStrictEqual(customProps.sourceID);
@@ -47,7 +47,7 @@ describe('SymbolLayer', () => {
expect(props.reactStyle).toStrictEqual({
visibility: {
styletype: 'constant',
- stylevalue: {type: 'string', value: customProps.style.visibility},
+ stylevalue: { type: 'string', value: customProps.style.visibility },
},
});
});
diff --git a/__tests__/components/UserLocation.test.js b/__tests__/components/UserLocation.test.js
index 8525da5e4..cb692d038 100644
--- a/__tests__/components/UserLocation.test.js
+++ b/__tests__/components/UserLocation.test.js
@@ -1,12 +1,10 @@
import React from 'react';
-import {render, fireEvent} from 'react-native-testing-library';
+import { render, fireEvent } from '@testing-library/react-native';
-import UserLocation, {
- normalIcon,
-} from '../../javascript/components/UserLocation';
-import ShapeSource from '../../javascript/components/ShapeSource';
-import CircleLayer from '../../javascript/components/CircleLayer';
-import locationManager from '../../javascript/modules/location/locationManager';
+import UserLocation from '../../src/components/UserLocation';
+import { ShapeSource } from '../../src/components/ShapeSource';
+import CircleLayer from '../../src/components/CircleLayer';
+import locationManager from '../../src/modules/location/locationManager';
const position = {
coords: {
@@ -16,6 +14,7 @@ const position = {
latitude: 51.5462244,
longitude: 4.1036916,
speed: 0.08543474227190018,
+ course: 251.5358428955078,
},
timestamp: 1573730357879,
};
@@ -30,38 +29,37 @@ describe('UserLocation', () => {
jest.spyOn(locationManager, 'addListener');
jest.spyOn(locationManager, 'removeListener');
+ jest
+ .spyOn(locationManager, 'setMinDisplacement')
+ .mockImplementation(jest.fn());
beforeEach(() => {
jest.clearAllMocks();
});
- test('renders with CircleLayers by default', (done) => {
- const {UNSAFE_getAllByType} = render();
+ test('renders with CircleLayers by default', async () => {
+ const { UNSAFE_getAllByType } = await render();
- setTimeout(() => {
- const shapeSource = UNSAFE_getAllByType(ShapeSource);
- const circleLayer = UNSAFE_getAllByType(CircleLayer);
+ const shapeSource = UNSAFE_getAllByType(ShapeSource);
+ const circleLayer = UNSAFE_getAllByType(CircleLayer);
- expect(shapeSource.length).toBe(1);
- expect(circleLayer.length).toBe(3);
- done();
- });
+ expect(shapeSource.length).toBe(1);
+ expect(circleLayer.length).toBe(3);
});
- test('does not render with visible set to false', (done) => {
- const {UNSAFE_queryByType} = render();
+ test('does not render with visible set to false', async () => {
+ const { UNSAFE_queryByType } = await render(
+ ,
+ );
- setTimeout(() => {
- const shapeSource = UNSAFE_queryByType(ShapeSource);
- const circleLayer = UNSAFE_queryByType(CircleLayer);
+ const shapeSource = UNSAFE_queryByType(ShapeSource);
+ const circleLayer = UNSAFE_queryByType(CircleLayer);
- expect(shapeSource).toEqual(null);
- expect(circleLayer).toEqual(null);
- done();
- });
+ expect(shapeSource).toEqual(null);
+ expect(circleLayer).toEqual(null);
});
- test('renders with CustomChild when provided', (done) => {
+ test('renders with CustomChild when provided', async () => {
const circleLayerProps = {
key: 'testUserLocationCircle',
id: 'testUserLocationCircle',
@@ -73,23 +71,20 @@ describe('UserLocation', () => {
},
};
- const {UNSAFE_queryByType, UNSAFE_queryAllByType} = render(
+ const { UNSAFE_queryByType, UNSAFE_queryAllByType } = await render(
,
);
- setTimeout(() => {
- const shapeSource = UNSAFE_queryByType(ShapeSource);
- const circleLayer = UNSAFE_queryAllByType(CircleLayer);
+ const shapeSource = UNSAFE_queryByType(ShapeSource);
+ const circleLayer = UNSAFE_queryAllByType(CircleLayer);
- expect(shapeSource).toBeDefined();
- expect(circleLayer[0]).toBeDefined();
- expect(circleLayer.length).toBe(1);
+ expect(shapeSource).toBeDefined();
+ expect(circleLayer[0]).toBeDefined();
+ expect(circleLayer.length).toBe(1);
- expect(circleLayer[0].props.style).toEqual(circleLayerProps.style);
- done();
- });
+ expect(circleLayer[0].props.style).toEqual(circleLayerProps.style);
});
test('calls onUpdate callback when new location is received', () => {
@@ -97,7 +92,7 @@ describe('UserLocation', () => {
render();
- locationManager.onUpdate({
+ locationManager._onUpdate({
coords: {
accuracy: 9.977999687194824,
altitude: 44.64373779296875,
@@ -105,6 +100,7 @@ describe('UserLocation', () => {
latitude: 51.5462244,
longitude: 4.1036916,
speed: 0.08543474227190018,
+ course: 251.5358428955078,
},
timestamp: 1573730357879,
});
@@ -115,7 +111,7 @@ describe('UserLocation', () => {
test('calls onPress callback when location icon is pressed', () => {
const onPressCallback = jest.fn();
- const {UNSAFE_queryByType} = render(
+ const { UNSAFE_queryByType } = render(
,
);
@@ -126,7 +122,7 @@ describe('UserLocation', () => {
});
test('correctly unmounts', async () => {
- const {unmount} = render();
+ const { unmount } = render();
expect(locationManager.addListener).toHaveBeenCalled();
expect(locationManager.removeListener).not.toHaveBeenCalled();
@@ -142,6 +138,7 @@ describe('UserLocation', () => {
beforeEach(() => {
ul = new UserLocation();
+
jest.spyOn(locationManager, 'start').mockImplementation(jest.fn());
jest.spyOn(locationManager, 'stop').mockImplementation(jest.fn());
jest
@@ -150,11 +147,7 @@ describe('UserLocation', () => {
ul.setState = jest.fn();
- ul.props = {
- animated: true,
- visible: true,
- minDisplacement: 0,
- };
+ ul.props = UserLocation.defaultProps;
ul._isMounted = true;
});
@@ -182,7 +175,7 @@ describe('UserLocation', () => {
expect(ul.locationManagerRunning).toStrictEqual(false);
- await ul.setLocationManager({running: true});
+ await ul.setLocationManager({ running: true });
expect(ul.locationManagerRunning).toStrictEqual(true);
expect(locationManager.start).toHaveBeenCalledTimes(1);
@@ -198,11 +191,11 @@ describe('UserLocation', () => {
test('called with "running" false', async () => {
// start
expect(ul.locationManagerRunning).toStrictEqual(false);
- await ul.setLocationManager({running: true});
+ await ul.setLocationManager({ running: true });
expect(ul.locationManagerRunning).toStrictEqual(true);
// stop
- await ul.setLocationManager({running: false});
+ await ul.setLocationManager({ running: false });
expect(ul.locationManagerRunning).toStrictEqual(false);
// only once from start
diff --git a/__tests__/interface.test.js b/__tests__/interface.test.js
index eed8c1dc8..9a57e2d40 100644
--- a/__tests__/interface.test.js
+++ b/__tests__/interface.test.js
@@ -1,4 +1,4 @@
-import MapboxGL from '../javascript';
+import MapboxGL from '../src';
describe('Public Interface', () => {
it('should contain all expected components and utils', () => {
@@ -17,6 +17,7 @@ describe('Public Interface', () => {
// modules
'offlineManager',
+ 'OfflineCreatePackOptions',
'snapshotManager',
'locationManager',
@@ -29,16 +30,23 @@ describe('Public Interface', () => {
'SymbolLayer',
'BackgroundLayer',
'RasterLayer',
+ 'SkyLayer',
+ 'Terrain',
+ 'Atmosphere',
// sources
'VectorSource',
'ShapeSource',
'RasterSource',
'ImageSource',
+ 'RasterDemSource',
'Images',
+ 'Image',
// constants
- 'UserTrackingModes',
+ 'UserTrackingModes', // deprecated
+ 'UserTrackingMode',
+ 'UserLocationRenderMode',
'StyleURL',
'EventTypes',
'CameraModes',
@@ -67,23 +75,31 @@ describe('Public Interface', () => {
'LightAnchor',
'OfflinePackDownloadState',
'OfflineCallbackName',
+ 'TileServers',
// methods
+ 'setWellKnownTileServer',
'setAccessToken',
'getAccessToken',
'setTelemetryEnabled',
'setConnected',
'requestAndroidLocationPermissions',
+ 'getAnnotationsLayerID',
+ 'addCustomHeader',
+ 'removeCustomHeader',
// animated
'Animated',
- // helpers
+ // classes
'AnimatedPoint',
+ 'AnimatedMapPoint',
'AnimatedCoordinatesArray',
'AnimatedShape',
'AnimatedExtractCoordinateFromArray',
'AnimatedRouteCoordinatesArray',
+
+ // helpers
'Logger',
'Style',
];
diff --git a/__tests__/modules/location/locationManager.test.js b/__tests__/modules/location/locationManager.test.js
index b4ba3e3ad..fb0da383a 100644
--- a/__tests__/modules/location/locationManager.test.js
+++ b/__tests__/modules/location/locationManager.test.js
@@ -1,8 +1,8 @@
-import {NativeModules} from 'react-native';
+import { NativeModules } from 'react-native';
import LocationManager, {
LocationModuleEventEmitter,
-} from '../../../javascript/modules/location/locationManager';
+} from '../../../src/modules/location/locationManager';
const MapboxGL = NativeModules.MGLModule;
const MapboxGLLocationManager = NativeModules.MGLLocationModule;
@@ -69,7 +69,7 @@ describe('LocationManager', () => {
describe('#addListener', () => {
const myListener = jest.fn();
- MapboxGL.LocationCallbackName = {Update: 'MapboxUserLocationUpdate'};
+ MapboxGL.LocationCallbackName = { Update: 'MapboxUserLocationUpdate' };
afterEach(() => {
locationManager._listeners = [];
@@ -156,7 +156,7 @@ describe('LocationManager', () => {
});
test('starts native location manager and adds event emitter listener', () => {
- MapboxGL.LocationCallbackName = {Update: 'MapboxUserLocationUpdate'};
+ MapboxGL.LocationCallbackName = { Update: 'MapboxUserLocationUpdate' };
expect(locationManager._isListening).toStrictEqual(false);
@@ -165,7 +165,7 @@ describe('LocationManager', () => {
expect(MapboxGLLocationManager.start).toHaveBeenCalledTimes(1);
expect(LocationModuleEventEmitter.addListener).toHaveBeenCalledWith(
MapboxGL.LocationCallbackName.Update,
- locationManager.onUpdate,
+ locationManager._onUpdate,
);
expect(locationManager._isListening).toStrictEqual(true);
@@ -198,19 +198,14 @@ describe('LocationManager', () => {
// native location manager has no #stop exposed in tests?
MapboxGLLocationManager.stop = jest.fn();
- jest.spyOn(LocationModuleEventEmitter, 'removeListener');
-
- MapboxGL.LocationCallbackName = {Update: 'MapboxUserLocationUpdate'};
+ MapboxGL.LocationCallbackName = { Update: 'MapboxUserLocationUpdate' };
expect(locationManager._isListening).toStrictEqual(true);
locationManager.stop();
expect(MapboxGLLocationManager.stop).toHaveBeenCalledTimes(1);
- expect(LocationModuleEventEmitter.removeListener).toHaveBeenCalledWith(
- MapboxGL.LocationCallbackName.Update,
- locationManager.onUpdate,
- );
+ expect(locationManager.subscription.remove).toHaveBeenCalled();
expect(locationManager._isListening).toStrictEqual(false);
});
@@ -221,18 +216,14 @@ describe('LocationManager', () => {
// native location manager has no #stop exposed in tests?
MapboxGLLocationManager.stop = jest.fn();
- jest.spyOn(LocationModuleEventEmitter, 'removeListener');
-
- MapboxGL.LocationCallbackName = {Update: 'MapboxUserLocationUpdate'};
+ MapboxGL.LocationCallbackName = { Update: 'MapboxUserLocationUpdate' };
expect(locationManager._isListening).toStrictEqual(false);
locationManager.stop();
expect(MapboxGLLocationManager.stop).toHaveBeenCalledTimes(1);
- expect(
- LocationModuleEventEmitter.removeListener,
- ).not.toHaveBeenCalled();
+ expect(locationManager.subscription.remove).not.toHaveBeenCalled();
});
});
@@ -246,13 +237,23 @@ describe('LocationManager', () => {
});
});
+ describe('#setRequestsAlwaysUse', () => {
+ test('calls native "setRequestsAlwaysUse"', () => {
+ MapboxGLLocationManager.setRequestsAlwaysUse = jest.fn();
+ locationManager.setRequestsAlwaysUse(true);
+ expect(
+ MapboxGLLocationManager.setRequestsAlwaysUse,
+ ).toHaveBeenCalledWith(true);
+ });
+ });
+
describe('#onUpdate', () => {
beforeEach(() => {
locationManager._lastKnownLocation = null;
});
test('sets "_lastKnownLocation"', () => {
- locationManager.onUpdate(location);
+ locationManager._onUpdate(location);
expect(locationManager._lastKnownLocation).toStrictEqual(location);
});
@@ -264,7 +265,7 @@ describe('LocationManager', () => {
locationManager.addListener(listener);
});
- locationManager.onUpdate(location);
+ locationManager._onUpdate(location);
listeners.forEach((listener) => {
expect(listener).toHaveBeenCalledTimes(1);
diff --git a/__tests__/modules/offline/OfflineCreatePackOptions.test.js b/__tests__/modules/offline/OfflineCreatePackOptions.test.js
index 3ce5a26c7..7fd9f6860 100644
--- a/__tests__/modules/offline/OfflineCreatePackOptions.test.js
+++ b/__tests__/modules/offline/OfflineCreatePackOptions.test.js
@@ -1,6 +1,6 @@
-import {featureCollection, point} from '@turf/helpers';
+import { featureCollection, point } from '@turf/helpers';
-import OfflineCreatePackOptions from '../../../javascript/modules/offline/OfflineCreatePackOptions';
+import OfflineCreatePackOptions from '../../../src/modules/offline/OfflineCreatePackOptions';
describe('OfflineCreatePackOptions', () => {
const options = {
diff --git a/__tests__/modules/offline/OfflinePack.test.js b/__tests__/modules/offline/OfflinePack.test.js
index 0e3704c78..460349751 100644
--- a/__tests__/modules/offline/OfflinePack.test.js
+++ b/__tests__/modules/offline/OfflinePack.test.js
@@ -1,6 +1,6 @@
-import {NativeModules} from 'react-native';
+import { NativeModules } from 'react-native';
-import OfflinePack from '../../../javascript/modules/offline/OfflinePack';
+import OfflinePack from '../../../src/modules/offline/OfflinePack';
describe('OfflinePack', () => {
const fakeNativePack = {
diff --git a/__tests__/modules/offline/offlineManager.test.js b/__tests__/modules/offline/offlineManager.test.js
index 53d22b509..57b341cdb 100644
--- a/__tests__/modules/offline/offlineManager.test.js
+++ b/__tests__/modules/offline/offlineManager.test.js
@@ -1,7 +1,7 @@
-import {NativeModules, Platform} from 'react-native';
+import { NativeModules, Platform } from 'react-native';
-import MapboxGL from '../../../javascript';
-import {OfflineModuleEventEmitter} from '../../../javascript/modules/offline/offlineManager';
+import MapboxGL from '../../../src';
+import { OfflineModuleEventEmitter } from '../../../src/modules/offline/offlineManager';
describe('offlineManager', () => {
const packOptions = {
@@ -69,6 +69,15 @@ describe('offlineManager', () => {
expect(offlinePack).toBeFalsy();
});
+ it('should migrate offline cache', async () => {
+ const spy = jest.spyOn(
+ NativeModules.MGLOfflineModule,
+ 'migrateOfflineCache',
+ );
+ await MapboxGL.offlineManager.migrateOfflineCache();
+ expect(spy).toHaveBeenCalled();
+ });
+
it('should set max tile count limit', () => {
const expectedLimit = 2000;
const spy = jest.spyOn(NativeModules.MGLOfflineModule, 'setTileCountLimit');
@@ -94,7 +103,7 @@ describe('offlineManager', () => {
const noop = () => {};
await MapboxGL.offlineManager.createPack(packOptions, noop, noop);
expect(spy).toHaveBeenCalledTimes(2);
- spy.mockRestore();
+ spy.mockClear();
});
it('should call progress listener', async () => {
@@ -133,12 +142,17 @@ describe('offlineManager', () => {
});
it('should unsubscribe from native events', async () => {
- const spy = jest.spyOn(OfflineModuleEventEmitter, 'removeListener');
const noop = () => {};
+
await MapboxGL.offlineManager.createPack(packOptions, noop, noop);
MapboxGL.offlineManager.unsubscribe(packOptions.name);
- expect(spy).toHaveBeenCalledTimes(2);
- spy.mockRestore();
+
+ expect(
+ MapboxGL.offlineManager.subscriptionProgress.remove,
+ ).toHaveBeenCalledTimes(1);
+ expect(
+ MapboxGL.offlineManager.subscriptionError.remove,
+ ).toHaveBeenCalledTimes(1);
});
it('should unsubscribe event listeners once a pack download has completed', async () => {
@@ -185,7 +199,7 @@ describe('offlineManager', () => {
const name = `test-${Date.now()}`;
const noop = () => {};
- const options = {...packOptions, name};
+ const options = { ...packOptions, name };
await MapboxGL.offlineManager.createPack(options);
await MapboxGL.offlineManager.subscribe(name, noop, noop);
@@ -198,7 +212,7 @@ describe('offlineManager', () => {
const name = `test-${Date.now()}`;
const noop = () => {};
- const options = {...packOptions, name};
+ const options = { ...packOptions, name };
await MapboxGL.offlineManager.createPack(options, noop, noop);
expect(spy).not.toHaveBeenCalled();
@@ -214,7 +228,7 @@ describe('offlineManager', () => {
const name = `test-${Date.now()}`;
const noop = () => {};
- const options = {...packOptions, name};
+ const options = { ...packOptions, name };
await MapboxGL.offlineManager.createPack(options);
await MapboxGL.offlineManager.subscribe(name, noop, noop);
diff --git a/__tests__/modules/snapshot/SnapshotOptions.test.js b/__tests__/modules/snapshot/SnapshotOptions.test.js
index 739a6f6a5..ee9a7523b 100644
--- a/__tests__/modules/snapshot/SnapshotOptions.test.js
+++ b/__tests__/modules/snapshot/SnapshotOptions.test.js
@@ -1,20 +1,17 @@
-import {NativeModules} from 'react-native';
+import { NativeModules } from 'react-native';
-import SnapshotOptions from '../../../javascript/modules/snapshot/SnapshotOptions';
-import {
- makePoint,
- makeFeatureCollection,
-} from '../../../javascript/utils/geoUtils';
+import SnapshotOptions from '../../../src/modules/snapshot/SnapshotOptions';
+import { makePoint, makeFeatureCollection } from '../../../src/utils/geoUtils';
describe('SnapshotOptions', () => {
it('should throw error if no centerCoordinate or bounds are provided', () => {
expect(() => new SnapshotOptions()).toThrow();
- expect(() => new SnapshotOptions({styleURL: 'test'})).toThrow();
+ expect(() => new SnapshotOptions({ styleURL: 'test' })).toThrow();
});
it('should create options with valid defaults', () => {
const centerCoordinate = [1, 2];
- const options = new SnapshotOptions({centerCoordinate});
+ const options = new SnapshotOptions({ centerCoordinate });
expect(options.toJSON()).toEqual({
styleURL: NativeModules.MGLModule.StyleURL.Street,
diff --git a/__tests__/modules/snapshot/snapshotManager.test.js b/__tests__/modules/snapshot/snapshotManager.test.js
index 950ffce01..fb07864c4 100644
--- a/__tests__/modules/snapshot/snapshotManager.test.js
+++ b/__tests__/modules/snapshot/snapshotManager.test.js
@@ -1,8 +1,8 @@
-import MapboxGL from '../../../javascript';
+import MapboxGL from '../../../src';
describe('snapshotManager', () => {
it('should resolve uri', async () => {
- const options = {centerCoordinate: [1, 2]};
+ const options = { centerCoordinate: [1, 2] };
const uri = await MapboxGL.snapshotManager.takeSnap(options);
expect(uri).toEqual('file://test.png');
});
diff --git a/__tests__/utils/BridgeValue.test.js b/__tests__/utils/BridgeValue.test.js
index be002e4eb..7eaa3526f 100644
--- a/__tests__/utils/BridgeValue.test.js
+++ b/__tests__/utils/BridgeValue.test.js
@@ -1,4 +1,4 @@
-import BridgeValue from '../../javascript/utils/BridgeValue';
+import BridgeValue from '../../src/utils/BridgeValue';
describe('BridgeValue', () => {
it('should convert to array of numbers', () => {
@@ -6,8 +6,8 @@ describe('BridgeValue', () => {
expect(bridgeValue.toJSON()).toEqual({
type: 'array',
value: [
- {type: 'number', value: 1},
- {type: 'number', value: 2},
+ { type: 'number', value: 1 },
+ { type: 'number', value: 2 },
],
});
});
@@ -17,8 +17,8 @@ describe('BridgeValue', () => {
expect(bridgeValue.toJSON()).toEqual({
type: 'array',
value: [
- {type: 'string', value: 'hello'},
- {type: 'string', value: 'world'},
+ { type: 'string', value: 'hello' },
+ { type: 'string', value: 'world' },
],
});
});
@@ -28,17 +28,17 @@ describe('BridgeValue', () => {
expect(bridgeValue.toJSON()).toEqual({
type: 'array',
value: [
- {type: 'boolean', value: true},
- {type: 'boolean', value: false},
+ { type: 'boolean', value: true },
+ { type: 'boolean', value: false },
],
});
});
it('should convert to array of hashmaps', () => {
const bridgeValue = new BridgeValue([
- {prop1: 1},
- {prop2: 'value'},
- {prop3: false},
+ { prop1: 1 },
+ { prop2: 'value' },
+ { prop3: false },
]);
expect(bridgeValue.toJSON()).toEqual({
type: 'array',
@@ -47,8 +47,8 @@ describe('BridgeValue', () => {
type: 'hashmap',
value: [
[
- {type: 'string', value: 'prop1'},
- {type: 'number', value: 1},
+ { type: 'string', value: 'prop1' },
+ { type: 'number', value: 1 },
],
],
},
@@ -56,8 +56,8 @@ describe('BridgeValue', () => {
type: 'hashmap',
value: [
[
- {type: 'string', value: 'prop2'},
- {type: 'string', value: 'value'},
+ { type: 'string', value: 'prop2' },
+ { type: 'string', value: 'value' },
],
],
},
@@ -65,8 +65,8 @@ describe('BridgeValue', () => {
type: 'hashmap',
value: [
[
- {type: 'string', value: 'prop3'},
- {type: 'boolean', value: false},
+ { type: 'string', value: 'prop3' },
+ { type: 'boolean', value: false },
],
],
},
@@ -90,15 +90,15 @@ describe('BridgeValue', () => {
{
type: 'array',
value: [
- {type: 'string', value: 'foo'},
- {type: 'string', value: 'bar'},
+ { type: 'string', value: 'foo' },
+ { type: 'string', value: 'bar' },
],
},
{
type: 'array',
value: [
- {type: 'string', value: 'baz'},
- {type: 'string', value: 'bao'},
+ { type: 'string', value: 'baz' },
+ { type: 'string', value: 'bao' },
],
},
],
@@ -110,14 +110,14 @@ describe('BridgeValue', () => {
[1],
['value'],
[true],
- [{prop: 'value'}],
+ [{ prop: 'value' }],
]);
expect(bridgeValue.toJSON()).toEqual({
type: 'array',
value: [
- {type: 'array', value: [{type: 'number', value: 1}]},
- {type: 'array', value: [{type: 'string', value: 'value'}]},
- {type: 'array', value: [{type: 'boolean', value: true}]},
+ { type: 'array', value: [{ type: 'number', value: 1 }] },
+ { type: 'array', value: [{ type: 'string', value: 'value' }] },
+ { type: 'array', value: [{ type: 'boolean', value: true }] },
{
type: 'array',
value: [
@@ -125,8 +125,8 @@ describe('BridgeValue', () => {
type: 'hashmap',
value: [
[
- {type: 'string', value: 'prop'},
- {type: 'string', value: 'value'},
+ { type: 'string', value: 'prop' },
+ { type: 'string', value: 'value' },
],
],
},
@@ -138,31 +138,31 @@ describe('BridgeValue', () => {
it('should convert to number', () => {
const bridgeValue = new BridgeValue(1);
- expect(bridgeValue.toJSON()).toEqual({type: 'number', value: 1});
+ expect(bridgeValue.toJSON()).toEqual({ type: 'number', value: 1 });
});
it('should convert to string', () => {
const bridgeValue = new BridgeValue('value');
- expect(bridgeValue.toJSON()).toEqual({type: 'string', value: 'value'});
+ expect(bridgeValue.toJSON()).toEqual({ type: 'string', value: 'value' });
});
it('should convert to boolean', () => {
const bridgeValue = new BridgeValue(true);
- expect(bridgeValue.toJSON()).toEqual({type: 'boolean', value: true});
+ expect(bridgeValue.toJSON()).toEqual({ type: 'boolean', value: true });
});
it('should convert to hashmap', () => {
- const bridgeValue = new BridgeValue({prop1: 'value1', prop2: 2});
+ const bridgeValue = new BridgeValue({ prop1: 'value1', prop2: 2 });
expect(bridgeValue.toJSON()).toEqual({
type: 'hashmap',
value: [
[
- {type: 'string', value: 'prop1'},
- {type: 'string', value: 'value1'},
+ { type: 'string', value: 'prop1' },
+ { type: 'string', value: 'value1' },
],
[
- {type: 'string', value: 'prop2'},
- {type: 'number', value: 2},
+ { type: 'string', value: 'prop2' },
+ { type: 'number', value: 2 },
],
],
});
diff --git a/__tests__/utils/animated/AnimatedCoordinatesArray.test.js b/__tests__/utils/animated/AnimatedCoordinatesArray.test.js
index c9ac54da3..19c74ff99 100644
--- a/__tests__/utils/animated/AnimatedCoordinatesArray.test.js
+++ b/__tests__/utils/animated/AnimatedCoordinatesArray.test.js
@@ -1,14 +1,13 @@
-/* eslint-disable fp/no-mutating-methods */
import FakeTimers from '@sinonjs/fake-timers';
-import {Animated, Easing} from 'react-native';
+import { Animated, Easing } from 'react-native';
import TestRenderer from 'react-test-renderer';
import React from 'react';
-import AnimatedCoordinatesArray from '../../../javascript/utils/animated/AnimatedCoordinatesArray';
-import AnimatedShape from '../../../javascript/utils/animated/AnimatedShape';
-import ShapeSource from '../../../javascript/components/ShapeSource';
+import { AnimatedShape, AnimatedCoordinatesArray } from '../../../src/classes';
+import { ShapeSource } from '../../../src/components/ShapeSource';
let clock = null;
+let oldNodeEnv = null;
beforeAll(() => {
clock = FakeTimers.install();
@@ -21,14 +20,24 @@ beforeAll(() => {
clock._requestedAnimationFrames = [];
oldRAF.forEach((cb) => cb(Date.now()));
};
+
+ // animated will not call nativeProps in test mode
+ // https://github.com/facebook/react-native/blob/34d3373bb0f7ee405292bf993163f29759ba5205/Libraries/Animated/createAnimatedComponent.js#L150-L156
+ oldNodeEnv = process.env.NODE_ENV;
+ process.env.NODE_ENV = 'dev';
});
afterAll(() => {
+ process.env.NODE_ENV = oldNodeEnv;
clock.uninstall();
});
const AnimatedShapeSource = Animated.createAnimatedComponent(ShapeSource);
+function _nativeRef(ref) {
+ return ref._nativeRef;
+}
+
describe('AnimatedShapeSource', () => {
test('testSetNativeProps', () => {
AnimatedShapeSource.__skipSetNativeProps_FOR_TESTS_ONLY = false;
@@ -41,12 +50,12 @@ describe('AnimatedShapeSource', () => {
// eslint-disable-next-line no-unused-vars
const testRenderer = TestRenderer.create(
(shapeSourceRef = ref)}
/>,
);
const setNativeProps = jest.fn();
- shapeSourceRef._component._nativeRef.setNativeProps = setNativeProps;
+ _nativeRef(shapeSourceRef).setNativeProps = setNativeProps;
coordinates
.timing({
@@ -90,12 +99,12 @@ describe('AnimatedShapeSource', () => {
// eslint-disable-next-line no-unused-vars
const testRenderer = TestRenderer.create(
(shapeSourceRef = ref)}
/>,
);
const setNativeProps = jest.fn();
- shapeSourceRef._component._nativeRef.setNativeProps = setNativeProps;
+ _nativeRef(shapeSourceRef).setNativeProps = setNativeProps;
coordinates
.timing({
@@ -142,12 +151,12 @@ describe('AnimatedShapeSource', () => {
// eslint-disable-next-line no-unused-vars
const testRenderer = TestRenderer.create(
(shapeSourceRef = ref)}
/>,
);
const setNativeProps = jest.fn();
- shapeSourceRef._component._nativeRef.setNativeProps = setNativeProps;
+ _nativeRef(shapeSourceRef).setNativeProps = setNativeProps;
coordinates
.timing({
diff --git a/__tests__/utils/filterUtils.test.js b/__tests__/utils/filterUtils.test.js
index 36422a308..3aed9673f 100644
--- a/__tests__/utils/filterUtils.test.js
+++ b/__tests__/utils/filterUtils.test.js
@@ -1,5 +1,5 @@
-import {getFilter} from '../../javascript/utils/filterUtils';
-import BridgeValue from '../../javascript/utils/BridgeValue';
+import { getFilter } from '../../src/utils/filterUtils';
+import BridgeValue from '../../src/utils/BridgeValue';
const FilterItem = BridgeValue;
diff --git a/android/build.gradle b/android/build.gradle
deleted file mode 100644
index 0c9b837ea..000000000
--- a/android/build.gradle
+++ /dev/null
@@ -1,34 +0,0 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
-
-buildscript {
- ext {
- buildToolsVersion = "28.0.3"
- minSdkVersion = 16
- compileSdkVersion = 28
- targetSdkVersion = 28
- supportLibVersion = "28.0.0"
- }
- repositories {
- google()
- jcenter()
- }
- dependencies {
- classpath 'com.android.tools.build:gradle:3.5.2'
-
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
- }
-}
-
-allprojects {
- repositories {
- mavenLocal()
- google()
- jcenter()
- maven { url "https://jitpack.io" }
- maven {
- // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
- url "$rootDir/../node_modules/react-native/android"
- }
- }
-}
diff --git a/android/install.md b/android/install.md
index 77b4d5e8e..d1d5517c4 100644
--- a/android/install.md
+++ b/android/install.md
@@ -1,4 +1,208 @@
# Android Installation
-## React-Native > `0.60.0`
-If you are using autolinking feature introduced in React-Native `0.60.0` you do not need any additional steps.
+## We're supporting 3 implementations at the moment:
+
+ - mapbox: v10 latest mapbox implementation - *recommended*, not opensource requires access for download
+ - maplibre: *DEFAULT* open source fork of older open source mapbox libraries with many improvements, will be removed in next version
+ - mapbox-gl: classic mapbox libraries - should work but will be dropped, recent versions are not open source and requires access for download, will be removed in next version
+
+## Mapbox Maps SDK v10
+
+Add `RNMapboxMapsImpl = "mapbox"` to your gradle file - see bellow for details.
+
+### Setting RNMapboxMapsImpl to v10
+
+*Warning*: If you set a custom version, make sure you revisit, any time you update @rnmapbox/maps. Setting it to earlier version than what we exepect will likely result in a build error.
+
+Overwrite mapbox dependencies within your `android/build.gradle > buildscript > ext` section
+
+
+```groovy
+buildscript {
+ ext {
+ // ...
+ RNMapboxMapsImpl = "mapbox" // required for v10
+ }
+}
+```
+
+### Adding mapbox maven repo
+
+You will need to authorize your download of the Maps SDK via a secret access token with the `DOWNLOADS:READ` scope.
+This [guide](https://docs.mapbox.com/android/maps/guides/install/#configure-credentials) explains how to `Configure credentials` and `Configure your secret token`.
+
+Then under section `allprojects/repositories` add your data:
+
+```groovy
+// android/build.gradle
+
+allprojects {
+ repositories {
+ // ...other repos
+ maven {
+ url 'https://api.mapbox.com/downloads/v2/releases/maven'
+ authentication {
+ basic(BasicAuthentication)
+ }
+ credentials {
+ // Do not change the username below.
+ // This should always be `mapbox` (not your username).
+ username = 'mapbox'
+ // Use the secret token you stored in gradle.properties as the password
+ password = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: ""
+ }
+ }
+ // ...even more repos?
+ }
+}
+```
+
+### Using non default mapbox version
+
+*Warning*: If you set a custom version, make sure you revisit, any time you update @rnmapbox/maps. Setting it to earlier version than what we exepect will likely result in a build error.
+
+Set `RNMapboxMapsLibs` in `android/build.gradle > buildscript > ext` section
+
+
+```groovy
+buildscript {
+ ext {
+ // ...
+ RNMapboxMapsImpl = "mapbox"
+
+ RNMapboxMapsLibs = { // optional - only required if you want to customize it
+ implementation 'com.mapbox.maps:android:10.6.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:5.4.1'
+ }
+ }
+}
+```
+
+
+
+If you see `2 files found with path 'lib/arm64-v8a/libc++_shared.so' from inputs` issue see [possible workaround](#workaround-for-2-files-found-with-path-libarm64-v8alibc_sharedso-from-inputs).
+
+## Using MapLibre
+
+[MapLibre](https://github.com/maplibre/maplibre-gl-native) is an OSS fork of MapboxGL.
+This is the default, and should work without any changes in gradle files.
+
+### Custom versions
+
+Overwrite mapbox dependencies within your `android/build.gradle > buildscript > ext` section
+
+```groovy
+buildscript {
+ ext {
+ // ...
+ RNMapboxMapsImpl = "maplibre" // optional - as this is the default
+
+ RNMapboxMapsLibs = { // optional - only required if you want to customize it
+ implementation ("org.maplibre.gl:android-sdk:9.5.2")
+ implementation ("org.maplibre.gl:android-sdk-turf:5.9.0")
+
+ implementation ("org.maplibre.gl:android-plugin-localization-v9:1.0.0")
+ implementation ("org.maplibre.gl:android-plugin-annotation-v9:1.0.0")
+ implementation ("org.maplibre.gl:android-plugin-markerview-v9:1.0.0")
+ }
+ }
+}
+```
+
+Feel free to check out the `/example` projects [`android/build.gradle`](https://github.com/rnmapbox/maps/blob/main/example/android/build.gradle) for inspiration!
+
+
+## Mapbox Maps GL Native SDK (pre v10)
+
+
+### Custom versions
+
+We've set up default Mapbox dependencies for you.
+Feel free to check em out [here](https://github.com/rnmapbox/maps/blob/eca4858744cab134b06ae455bcdacc63233318a5/android/rctmgl/build.gradle#L55-L76)
+
+However, it is also possible to set a custom version of the [Mapbox SDK](https://github.com/mapbox/mapbox-gl-native-android)
+Which will overwrite our defaults.
+
+Add something like the following to your `android/build.gradle > buildscript > ext` section:
+
+```groovy
+// android/build.gradle
+
+buildscript {
+ // ... stuff
+ ext {
+ RNMapboxMapsImpl = "mapbox-gl"
+
+ // ... stuff
+ RNMapboxMapsLibs = {
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:9.7.1'
+ implementation 'com.mapbox.mapboxsdk:mapbox-sdk-services:5.8.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:5.8.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-gestures:0.7.0'
+
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-annotation-v9:0.8.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-localization-v9:0.14.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-markerview-v9:0.4.0'
+ }
+ // ... more stuff?
+ }
+}
+```
+
+NOTICE, If you are using newer versions of the SDK, you will need to authorize your download of the Maps SDK via a secret access token with the `DOWNLOADS:READ` scope.
+This [guide](https://docs.mapbox.com/android/maps/guides/install/#configure-credentials) explains how to `Configure credentials` and `Configure your secret token`.
+
+Then under section `allprojects/repositories` add your data:
+
+```groovy
+// android/build.gradle
+
+allprojects {
+ repositories {
+ // ...other repos
+ maven {
+ url 'https://api.mapbox.com/downloads/v2/releases/maven'
+ authentication {
+ basic(BasicAuthentication)
+ }
+ credentials {
+ // Do not change the username below.
+ // This should always be `mapbox` (not your username).
+ username = 'mapbox'
+ // Use the secret token you stored in gradle.properties as the password
+ password = project.properties['MAPBOX_DOWNLOADS_TOKEN'] ?: ""
+ }
+ }
+ // ...even more repos?
+ }
+}
+```
+
+Feel free to check out the `/example` projects [`android/build.gradle`](https://github.com/rnmapbox/maps/blob/main/example/android/build.gradle) for inspiration!
+
+
+
+---
+
+
+
+
+### Workaround for 2 files found with path 'lib/arm64-v8a/libc++_shared.so' from inputs
+
+```sh
+code android/app/build.gradle
+```
+
+add the following
+```gradle
+android {
+ packagingOptions {
+ pickFirst 'lib/x86/libc++_shared.so'
+ pickFirst 'lib/x86_64/libc++_shared.so'
+ pickFirst 'lib/arm64-v8a/libc++_shared.so'
+ pickFirst 'lib/armeabi-v7a/libc++_shared.so'
+ }
+}
+```
+
+
diff --git a/android/rctmgl/.classpath b/android/rctmgl/.classpath
new file mode 100644
index 000000000..eb19361b5
--- /dev/null
+++ b/android/rctmgl/.classpath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/android/rctmgl/.settings/org.eclipse.buildship.core.prefs b/android/rctmgl/.settings/org.eclipse.buildship.core.prefs
index e8895216f..8d2297310 100644
--- a/android/rctmgl/.settings/org.eclipse.buildship.core.prefs
+++ b/android/rctmgl/.settings/org.eclipse.buildship.core.prefs
@@ -1,2 +1,13 @@
+arguments=--init-script /var/folders/nf/xt27lc4j4sv73tqskhkd_8xc0000gn/T/d146c9752a26f79b52047fb6dc6ed385d064e120494f96f08ca63a317c41f94c.gradle --init-script /var/folders/nf/xt27lc4j4sv73tqskhkd_8xc0000gn/T/52cde0cfcf3e28b8b7510e992210d9614505e0911af0c190bd590d7158574963.gradle
+auto.sync=false
+build.scans.enabled=false
+connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(7.4.2))
connection.project.dir=
eclipse.preferences.version=1
+gradle.user.home=
+java.home=/Library/Java/JavaVirtualMachines/jdk-11.0.14.jdk/Contents/Home
+jvm.arguments=
+offline.mode=false
+override.workspace.settings=true
+show.console.view=true
+show.executions.view=true
diff --git a/android/rctmgl/build.gradle b/android/rctmgl/build.gradle
index 14fe2c8a3..afecc80ad 100644
--- a/android/rctmgl/build.gradle
+++ b/android/rctmgl/build.gradle
@@ -1,10 +1,73 @@
-apply plugin: 'com.android.library'
+def defaultMapboxMapsImpl = "maplibre"
+def defaultMapboxMapsVersion = "10.12.0"
def safeExtGet(prop, fallback) {
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
+// expo plugin
+if (rootProject.ext.has('expoRNMapboxMapsImpl')) {
+ rootProject.ext.set('RNMapboxMapsImpl', rootProject.ext.get('expoRNMapboxMapsImpl'))
+}
+if (rootProject.ext.has('expoRNMapboxMapsVersion')) {
+ rootProject.ext.set('RNMapboxMapsVersion', rootProject.ext.get('expoRNMapboxMapsVersion'))
+}
+
+
+buildscript {
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : '1.6.21'}"
+ }
+}
+
+apply plugin: 'com.android.library'
+
+if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "mapbox") {
+ apply plugin: 'kotlin-android'
+}
+
android {
+ if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "maplibre") {
+ logger.warn('@rnmapbox/maps: Maplibre implementation is DEPRECATED and will be removed, set RNMapboxMapsImpl to mapbox- see https://github.com/rnmapbox/maps/wiki/Deprecated-RNMapboxImpl-Maplibre#android')
+ sourceSets {
+ main {
+ java.srcDirs = ['src/main/java-mapboxgl/common','src/main/java-mapboxgl/maplibre']
+ }
+ }
+ }
+ else if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "mapbox-gl") {
+ logger.warn('@rnmapbox/maps: Maplibre implementation is DEPRECATED and will be removed, set RNMapboxMapsImpl to mapbox - see https://github.com/rnmapbox/maps/wiki/Deprecated-RNMapboxImpl-Maplibre#android')
+ sourceSets {
+ main {
+ java.srcDirs = ['src/main/java-mapboxgl/common','src/main/java-mapboxgl/mapbox']
+ }
+ }
+ }
+ else if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "mapbox") {
+ sourceSets {
+ main {
+ java.srcDirs = ['src/main/java-v10']
+ }
+ }
+
+ packagingOptions {
+ pickFirst 'lib/x86/libc++_shared.so'
+ pickFirst 'lib/x86_64/libc++_shared.so'
+ pickFirst 'lib/arm64-v8a/libc++_shared.so'
+ pickFirst 'lib/armeabi-v7a/libc++_shared.so'
+ }
+ }
+ else {
+ msg = "RNMapboxMapsImpl should be one of: mapbox, mapbox-gl, maplibre got: ${safeExtGet("mapboxV10", defaultMapboxMapsImpl)}"
+ logger.error(msg)
+ throw new GradleException(msg)
+ }
+
compileSdkVersion safeExtGet("compileSdkVersion", 28)
buildToolsVersion safeExtGet("buildToolsVersion", '28.0.3')
@@ -28,6 +91,23 @@ android {
}
}
+def customizableDependencies(name, defaultDependencies) {
+ if (rootProject.ext.has(name)) {
+ def libs = rootProject.ext.get(name)
+ if (libs instanceof CharSequence) {
+ libs.split(';').each {
+ implementation it
+ }
+ } else {
+ libs.delegate = defaultDependencies.owner.delegate
+ libs.call()
+ }
+ } else {
+ defaultDependencies.delegate = defaultDependencies.owner.delegate
+ defaultDependencies.call()
+ }
+}
+
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
@@ -35,31 +115,42 @@ dependencies {
implementation "com.facebook.react:react-native:+"
// Mapbox SDK
- if (rootProject.ext.has('rnmbglMapboxLibs')) {
- rootProject.ext.get('rnmbglMapboxLibs').split(';').each {
- implementation it
+ customizableDependencies('RNMapboxMapsLibs') {
+ if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "maplibre") {
+ implementation ("org.maplibre.gl:android-sdk:9.5.2")
+ implementation ("org.maplibre.gl:android-sdk-turf:5.9.0")
+
+ implementation ("org.maplibre.gl:android-plugin-localization-v9:1.0.0")
+ implementation ("org.maplibre.gl:android-plugin-annotation-v9:1.0.0")
+ implementation ("org.maplibre.gl:android-plugin-markerview-v9:1.0.0")
+ }
+ else if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "mapbox-gl") {
+ implementation 'com.mapbox.mapboxsdk:mapbox-sdk-services:5.1.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:9.1.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-telemetry:6.1.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-annotation-v9:0.8.0'
+
+ // plugins
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-gestures:0.6.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-localization-v9:0.12.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-markerview-v9:0.4.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:5.1.0'
+ }
+ else if (safeExtGet("RNMapboxMapsImpl", defaultMapboxMapsImpl) == "mapbox") {
+ implementation "com.mapbox.maps:android:${safeExtGet("RNMapboxMapsVersion", defaultMapboxMapsVersion)}"
+ implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:6.10.0'
+ implementation 'androidx.asynclayoutinflater:asynclayoutinflater:1.0.0'
}
- } else {
- implementation 'com.mapbox.mapboxsdk:mapbox-sdk-services:5.1.0'
- implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:9.1.0'
- implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-annotation-v9:0.8.0'
}
// Dependencies
- implementation "com.android.support:support-vector-drawable:${safeExtGet('supportLibVersion', '28.0.0')}"
- implementation "com.android.support:support-annotations:${safeExtGet('supportLibVersion', '28.0.0')}"
- implementation "com.android.support:appcompat-v7:${safeExtGet('supportLibVersion', '28.0.0')}"
- implementation "com.squareup.okhttp3:okhttp:${safeExtGet('okhttpVersion', '3.12.1')}"
-
- // Mapbox plugins
- if (rootProject.ext.has('rnmbglMapboxPlugins')) {
- rootProject.ext.get('rnmbglMapboxPlugins').split(';').each {
- implementation it
- }
- } else {
- implementation 'com.mapbox.mapboxsdk:mapbox-android-gestures:0.6.0'
- implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-localization-v9:0.12.0'
- implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-markerview-v9:0.4.0'
- implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:5.1.0'
+ customizableDependencies('RNMapboxMapsSupportLibs') {
+ implementation "com.android.support:support-vector-drawable:28.0.0"
+ implementation "com.android.support:support-annotations:28.0.0"
+ implementation "com.android.support:appcompat-v7:28.0.0"
+ }
+ customizableDependencies('RNMapboxMapsOkHTTPLibs') {
+ implementation "com.squareup.okhttp3:okhttp:4.9.0"
+ implementation "com.squareup.okhttp3:okhttp-urlconnection:4.9.0"
}
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/RCTMGLPackage.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/RCTMGLPackage.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/RCTMGLPackage.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/RCTMGLPackage.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/AbstractEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/AbstractEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/AbstractEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/AbstractEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/AbstractEventEmitter.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/AbstractEventEmitter.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/AbstractEventEmitter.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/AbstractEventEmitter.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/AbstractMapFeature.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/AbstractMapFeature.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/AbstractMapFeature.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/AbstractMapFeature.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/MarkerView.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/MarkerView.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/MarkerView.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/MarkerView.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/MarkerViewManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/MarkerViewManager.java
similarity index 58%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/MarkerViewManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/MarkerViewManager.java
index 900083a0e..96020faf1 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/MarkerViewManager.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/MarkerViewManager.java
@@ -8,17 +8,26 @@
import java.util.ArrayList;
import java.util.List;
+import java.lang.reflect.InvocationTargetException;
+
/**
* Subclass of MarkerViewManager implementing removeViews and restoreViews
*/
public class MarkerViewManager extends com.mapbox.mapboxsdk.plugins.markerview.MarkerViewManager {
private final List markers = new ArrayList<>();
private MapView mapView;
+ private java.lang.reflect.Method markerUpdate;
public MarkerViewManager(MapView mapView, MapboxMap mapboxMap) {
super(mapView, mapboxMap);
this.mapView = mapView;
// this.mapboxMap = mapboxMap;
+
+ try {
+ markerUpdate = MarkerView.class.getSuperclass().getDeclaredMethod("update");
+ markerUpdate.setAccessible(true);
+ }
+ catch (NoSuchMethodException e) {System.out.println(e.toString());}
}
public void addMarker(@NonNull MarkerView markerView) {
@@ -42,4 +51,19 @@ public void restoreViews() {
mapView.addView(marker.getView());
}
}
-}
\ No newline at end of file
+
+ public void updateMarkers(){
+
+ try {
+ if (markerUpdate != null) {
+ for( int i = 0; i < markers.size(); i++ ){
+ markerUpdate.invoke(markers.get(i));
+ }
+ }
+ }
+ catch (IllegalArgumentException e) { System.out.println(e.toString()); }
+ catch (IllegalAccessException e) { System.out.println(e.toString()); }
+ catch (InvocationTargetException e) { System.out.println(e.toString()); }
+ }
+
+}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLCallout.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLCallout.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLCallout.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLCallout.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLCalloutManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLCalloutManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLCalloutManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLCalloutManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerView.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerView.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerView.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerView.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotation.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotation.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotation.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotation.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotationManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotationManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotationManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotationManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/CameraStop.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/CameraStop.java
similarity index 68%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/CameraStop.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/CameraStop.java
index f6623b56c..e1abeb4d6 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/CameraStop.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/CameraStop.java
@@ -29,10 +29,10 @@ public class CameraStop {
private LatLng mLatLng;
private LatLngBounds mBounds;
- private int mBoundsPaddingLeft = 0;
- private int mBoundsPaddingRight = 0;
- private int mBoundsPaddingBottom = 0;
- private int mBoundsPaddingTop = 0;
+ private int mPaddingLeft = 0;
+ private int mPaddingRight = 0;
+ private int mPaddingBottom = 0;
+ private int mPaddingTop = 0;
private int mMode = CameraMode.EASE;
private int mDuration = 2000;
@@ -65,12 +65,15 @@ public void setCallback(MapboxMap.CancelableCallback callback) {
mCallback = callback;
}
- public void setBounds(LatLngBounds bounds, int paddingLeft, int paddingRight, int paddingTop, int paddingBottom) {
+ public void setBounds(LatLngBounds bounds) {
mBounds = bounds;
- mBoundsPaddingLeft = paddingLeft;
- mBoundsPaddingRight = paddingRight;
- mBoundsPaddingTop = paddingTop;
- mBoundsPaddingBottom = paddingBottom;
+ }
+
+ public void setPadding(int paddingLeft, int paddingRight, int paddingTop, int paddingBottom) {
+ mPaddingLeft = paddingLeft;
+ mPaddingRight = paddingRight;
+ mPaddingTop = paddingTop;
+ mPaddingBottom = paddingBottom;
}
public void setMode(@CameraMode.Mode int mode) {
@@ -82,32 +85,32 @@ public CameraUpdateItem toCameraUpdate(RCTMGLMapView mapView) {
CameraPosition currentCamera = map.getCameraPosition();
CameraPosition.Builder builder = new CameraPosition.Builder(currentCamera);
- if (mBearing != null) {
- builder.bearing(mBearing);
- }
+ // Adding map padding to the camera padding which is the same behavior as
+ // mapbox native does on iOS
+ double[] contentInset = mapView.getContentInset();
- if (mTilt != null) {
- builder.tilt(mTilt);
- }
+ int paddingLeft = Double.valueOf(contentInset[0] + mPaddingLeft).intValue();
+ int paddingTop = Double.valueOf(contentInset[1] + mPaddingTop).intValue();
+ int paddingRight = Double.valueOf(contentInset[2] + mPaddingRight).intValue();
+ int paddingBottom = Double.valueOf(contentInset[3] + mPaddingBottom).intValue();
+
+ int[] cameraPadding = {paddingLeft, paddingTop, paddingRight, paddingBottom};
+ int[] cameraPaddingClipped = clippedPadding(cameraPadding, mapView);
+
+ boolean hasSetZoom = false;
if (mLatLng != null) {
builder.target(mLatLng);
+ builder.padding(
+ cameraPaddingClipped[0],
+ cameraPaddingClipped[1],
+ cameraPaddingClipped[2],
+ cameraPaddingClipped[3]
+ );
} else if (mBounds != null) {
double tilt = mTilt != null ? mTilt : currentCamera.tilt;
double bearing = mBearing != null ? mBearing : currentCamera.bearing;
- // Adding map padding to the camera padding which is the same behavior as
- // mapbox native does on iOS
- double[] contentInset = mapView.getContentInset();
-
- int paddingLeft = Double.valueOf(contentInset[0] + mBoundsPaddingLeft).intValue();
- int paddingTop = Double.valueOf(contentInset[1] + mBoundsPaddingTop).intValue();
- int paddingRight = Double.valueOf(contentInset[2] + mBoundsPaddingRight).intValue();
- int paddingBottom = Double.valueOf(contentInset[3] + mBoundsPaddingBottom).intValue();
-
- int[] cameraPadding = {paddingLeft, paddingTop, paddingRight, paddingBottom};
- int[] cameraPaddingClipped = clippedPadding(cameraPadding, mapView);
-
CameraPosition boundsCamera = map.getCameraForLatLngBounds(mBounds, cameraPaddingClipped, bearing, tilt);
if (boundsCamera != null) {
builder.target(boundsCamera.target);
@@ -115,17 +118,26 @@ public CameraUpdateItem toCameraUpdate(RCTMGLMapView mapView) {
builder.padding(boundsCamera.padding);
} else {
CameraUpdate update = CameraUpdateFactory.newLatLngBounds(
- mBounds,
- cameraPaddingClipped[0],
- cameraPaddingClipped[1],
- cameraPaddingClipped[2],
- cameraPaddingClipped[3]
+ mBounds,
+ cameraPaddingClipped[0],
+ cameraPaddingClipped[1],
+ cameraPaddingClipped[2],
+ cameraPaddingClipped[3]
);
return new CameraUpdateItem(map, update, mDuration, mCallback, mMode);
}
+ hasSetZoom = true;
+ }
+
+ if (mBearing != null) {
+ builder.bearing(mBearing);
+ }
+
+ if (mTilt != null) {
+ builder.tilt(mTilt);
}
- if (mZoom != null) {
+ if (mZoom != null && !hasSetZoom) {
builder.zoom(mZoom);
}
@@ -143,6 +155,25 @@ public static CameraStop fromReadableMap(Context context, @NonNull ReadableMap r
stop.setBearing(readableMap.getDouble("heading"));
}
+ int paddingTop = getPaddingByKey(readableMap, "paddingTop");
+ int paddingRight = getPaddingByKey(readableMap, "paddingRight");
+ int paddingBottom = getPaddingByKey(readableMap, "paddingBottom");
+ int paddingLeft = getPaddingByKey(readableMap, "paddingLeft");
+
+ // scale padding by pixel ratio
+ DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ paddingTop = Float.valueOf(paddingTop * metrics.density).intValue();
+ paddingRight = Float.valueOf(paddingRight * metrics.density).intValue();
+ paddingBottom = Float.valueOf(paddingBottom * metrics.density).intValue();
+ paddingLeft = Float.valueOf(paddingLeft * metrics.density).intValue();
+
+ stop.setPadding(
+ paddingLeft,
+ paddingRight,
+ paddingTop,
+ paddingBottom
+ );
+
if (readableMap.hasKey("centerCoordinate")) {
Point target = GeoJSONUtils.toPointGeometry(readableMap.getString("centerCoordinate"));
stop.setLatLng(GeoJSONUtils.toLatLng(target));
@@ -157,21 +188,8 @@ public static CameraStop fromReadableMap(Context context, @NonNull ReadableMap r
}
if (readableMap.hasKey("bounds")) {
- int paddingTop = getBoundsPaddingByKey(readableMap, "boundsPaddingTop");
- int paddingRight = getBoundsPaddingByKey(readableMap, "boundsPaddingRight");
- int paddingBottom = getBoundsPaddingByKey(readableMap, "boundsPaddingBottom");
- int paddingLeft = getBoundsPaddingByKey(readableMap, "boundsPaddingLeft");
-
- // scale padding by pixel ratio
- DisplayMetrics metrics = context.getResources().getDisplayMetrics();
- paddingTop = Float.valueOf(paddingTop * metrics.scaledDensity).intValue();
- paddingRight = Float.valueOf(paddingRight * metrics.scaledDensity).intValue();
- paddingBottom = Float.valueOf(paddingBottom * metrics.scaledDensity).intValue();
- paddingLeft = Float.valueOf(paddingLeft * metrics.scaledDensity).intValue();
-
FeatureCollection collection = FeatureCollection.fromJson(readableMap.getString("bounds"));
- stop.setBounds(GeoJSONUtils.toLatLngBounds(collection), paddingLeft, paddingRight,
- paddingTop, paddingBottom);
+ stop.setBounds(GeoJSONUtils.toLatLngBounds(collection));
}
if (readableMap.hasKey("mode")) {
@@ -179,6 +197,9 @@ public static CameraStop fromReadableMap(Context context, @NonNull ReadableMap r
case CameraMode.FLIGHT:
stop.setMode(CameraMode.FLIGHT);
break;
+ case CameraMode.LINEAR:
+ stop.setMode(CameraMode.LINEAR);
+ break;
case CameraMode.NONE:
stop.setMode(CameraMode.NONE);
break;
@@ -222,7 +243,7 @@ private static int[] clippedPadding(int[] padding, RCTMGLMapView mapView) {
return new int[] {resultLeft, resultTop, resultRight, resultBottom};
}
- private static int getBoundsPaddingByKey(ReadableMap map, String key) {
+ private static int getPaddingByKey(ReadableMap map, String key) {
return map.hasKey(key) ? map.getInt(key) : 0;
}
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/CameraUpdateItem.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/CameraUpdateItem.java
similarity index 94%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/CameraUpdateItem.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/CameraUpdateItem.java
index 11053f463..4bfb472bd 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/CameraUpdateItem.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/CameraUpdateItem.java
@@ -76,8 +76,10 @@ public void onFinish() {
if (mCameraMode == CameraMode.FLIGHT) {
map.animateCamera(mCameraUpdate, duration, callback);
+ } else if (mCameraMode == CameraMode.LINEAR) {
+ map.easeCamera(mCameraUpdate, duration, false, callback);
} else if (mCameraMode == CameraMode.EASE) {
- map.easeCamera(mCameraUpdate, duration, callback);
+ map.easeCamera(mCameraUpdate, duration, true, callback);
}
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/CameraUpdateQueue.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/CameraUpdateQueue.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/CameraUpdateQueue.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/CameraUpdateQueue.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/RCTMGLCamera.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/RCTMGLCamera.java
similarity index 97%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/RCTMGLCamera.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/RCTMGLCamera.java
index daa51cb2e..ed0fe2e32 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/RCTMGLCamera.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/RCTMGLCamera.java
@@ -40,7 +40,7 @@
import com.mapbox.geojson.Point;
-import com.mapbox.android.core.permissions.PermissionsManager;
+import com.mapbox.rctmgl.impl.PermissionsManagerImpl;
import androidx.annotation.NonNull;
@@ -327,14 +327,14 @@ public void onFinish() {
};
if (isAnimated) {
- mMapView.easeCamera(cameraUpdate, USER_LOCATION_CAMERA_MOVE_DURATION, callback);
+ mMapView.easeCamera(cameraUpdate, USER_LOCATION_CAMERA_MOVE_DURATION, true, callback);
} else {
mMapView.moveCamera(cameraUpdate, callback);
}
}
private void enableLocation() {
- if (!PermissionsManager.areLocationPermissionsGranted(mContext)) {
+ if (!PermissionsManagerImpl.areLocationPermissionsGranted(mContext)) {
return;
}
@@ -517,7 +517,10 @@ private WritableMap makeLocationChangePayload(Location location) {
coords.putDouble("latitude", location.getLatitude());
coords.putDouble("altitude", location.getAltitude());
coords.putDouble("accuracy", location.getAccuracy());
+ // A better solution will be to pull the heading from the compass engine,
+ // unfortunately the api is not publicly available in the mapbox sdk
coords.putDouble("heading", location.getBearing());
+ coords.putDouble("course", location.getBearing());
coords.putDouble("speed", location.getSpeed());
positionProperties.putMap("coords", coords);
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/RCTMGLCameraManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/RCTMGLCameraManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/RCTMGLCameraManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/RCTMGLCameraManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/constants/CameraMode.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/constants/CameraMode.java
similarity index 76%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/constants/CameraMode.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/constants/CameraMode.java
index 016fa7096..4d0bc1bcc 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/camera/constants/CameraMode.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/camera/constants/CameraMode.java
@@ -11,11 +11,12 @@
public class CameraMode {
- @IntDef({ FLIGHT, EASE, NONE })
+ @IntDef({ FLIGHT, EASE, LINEAR, NONE })
@Retention(RetentionPolicy.SOURCE)
public @interface Mode {}
public static final int FLIGHT = 1;
public static final int EASE = 2;
- public static final int NONE = 3;
+ public static final int LINEAR = 3;
+ public static final int NONE = 4;
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/images/RCTMGLImages.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/images/RCTMGLImages.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/images/RCTMGLImages.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/images/RCTMGLImages.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/images/RCTMGLImagesManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/images/RCTMGLImagesManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/images/RCTMGLImagesManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/images/RCTMGLImagesManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/location/LocationComponentManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/location/LocationComponentManager.java
similarity index 90%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/location/LocationComponentManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/location/LocationComponentManager.java
index 69fe1d50f..3aa268268 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/location/LocationComponentManager.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/location/LocationComponentManager.java
@@ -1,11 +1,8 @@
package com.mapbox.rctmgl.components.location;
+import android.annotation.SuppressLint;
import android.content.Context;
-import android.location.Location;
-import androidx.annotation.NonNull;
-
-import com.mapbox.android.core.permissions.PermissionsManager;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions;
import com.mapbox.mapboxsdk.location.LocationComponentOptions;
@@ -17,7 +14,8 @@
import com.mapbox.rctmgl.R;
import com.mapbox.rctmgl.components.mapview.RCTMGLMapView;
import com.mapbox.rctmgl.location.LocationManager;
-import com.mapbox.rctmgl.location.UserTrackingMode;
+
+import androidx.annotation.NonNull;
/**
* The LocationComponent on android implements both location tracking and display of user's current location.
@@ -32,8 +30,6 @@ public class LocationComponentManager {
private LocationComponent mLocationComponent = null;
private Context mContext = null;
- // state
- private @CameraMode.Mode int mCameraMode = CameraMode.NONE;
private @RenderMode.Mode int mRenderMode = RenderMode.COMPASS;
public LocationComponentManager(RCTMGLMapView rctmglMapView, Context context) {
@@ -75,6 +71,7 @@ public void addOnCameraTrackingChangedListener(OnCameraTrackingChangedListener o
mLocationComponent.addOnCameraTrackingChangedListener(onCameraTrackingChangedListener);
}
+ @SuppressLint("MissingPermission")
private void stateChanged() {
mLocationComponent.setLocationComponentEnabled((mFollowUserLocation || mShowUserLocation));
@@ -98,20 +95,14 @@ public boolean hasLocationComponent() {
return (mLocationComponent != null);
}
- public void forceLocationUpdate(Location location) {
- mLocationComponent.forceLocationUpdate(location);
- }
-
public void update(@NonNull Style style) {
- if (mLocationComponent == null) {
- update(mShowUserLocation, style);
- } else {
- update(mShowUserLocation, style);
- }
+ update(mShowUserLocation, style);
}
public void update(boolean displayUserLocation, @NonNull Style style) {
- if (mLocationComponent == null) {
+ Integer tintColor = mMapView.getTintColor();
+
+ if (mLocationComponent == null || tintColor != null ) {
mLocationComponent = mMap.getLocationComponent();
LocationComponentActivationOptions locationComponentActivationOptions = LocationComponentActivationOptions
@@ -119,7 +110,7 @@ public void update(boolean displayUserLocation, @NonNull Style style) {
.locationComponentOptions(options(displayUserLocation))
.build();
mLocationComponent.activateLocationComponent(locationComponentActivationOptions);
- mLocationComponent.setLocationEngine(mLocationManager.getEngine());
+ mLocationComponent.setLocationEngine(mLocationManager.getEngine().getEngine());
mShowingUserLocation = displayUserLocation;
}
@@ -135,6 +126,7 @@ private void updateShowUserLocation(boolean displayUserLocation) {
LocationComponentOptions options(boolean displayUserLocation) {
LocationComponentOptions.Builder builder = LocationComponentOptions.builder(mContext);
+ Integer tintColor = mMapView.getTintColor();
if (!displayUserLocation) {
builder = builder
.padding(mMap.getPadding())
@@ -145,6 +137,12 @@ LocationComponentOptions options(boolean displayUserLocation) {
.foregroundDrawableStale(R.drawable.empty)
.gpsDrawable(R.drawable.empty)
.accuracyAlpha(0.0f);
+ } else if (tintColor != null) {
+ builder = builder
+ .enableStaleState(false)
+ .bearingTintColor(tintColor)
+ .foregroundTintColor(tintColor)
+ .accuracyColor(tintColor);
}
return builder.build();
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocation.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocation.java
similarity index 88%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocation.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocation.java
index 559c4823e..3dfc01276 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocation.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocation.java
@@ -4,9 +4,8 @@
import android.content.Context;
import androidx.annotation.NonNull;
-import com.mapbox.android.core.permissions.PermissionsManager;
-import com.mapbox.mapboxsdk.location.LocationComponent;
-import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions;
+import com.mapbox.rctmgl.impl.PermissionsManagerImpl;
+
import com.mapbox.mapboxsdk.location.modes.RenderMode;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
@@ -49,11 +48,12 @@ public void onMapReady(@NonNull MapboxMap mapboxMap) {
@Override
public void onStyleLoaded(@NonNull Style style) {
Context context = getContext();
- if (!PermissionsManager.areLocationPermissionsGranted(context)) {
+ if (!PermissionsManagerImpl.areLocationPermissionsGranted(context)) {
return;
}
LocationComponentManager locationComponent = mMapView.getLocationComponentManager();
+ locationComponent.update(style);
locationComponent.showUserLocation(mEnabled);
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocationManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocationManager.java
similarity index 92%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocationManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocationManager.java
index 074cd70c6..834246537 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocationManager.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocationManager.java
@@ -8,7 +8,7 @@
import javax.annotation.Nonnull;
public class RCTMGLNativeUserLocationManager extends ViewGroupManager {
- public static final String REACT_CLASS = RCTMGLNativeUserLocation.class.getSimpleName();
+ public static final String REACT_CLASS = "RCTMGLNativeUserLocation";
@Nonnull
@Override
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/LayerSourceInfo.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/LayerSourceInfo.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/LayerSourceInfo.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/LayerSourceInfo.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapView.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapView.java
similarity index 83%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapView.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapView.java
index 08a1ec8ef..df81804e4 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapView.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapView.java
@@ -8,7 +8,7 @@
@SuppressWarnings({"MissingPermission"})
public class RCTMGLAndroidTextureMapView extends RCTMGLMapView {
- public static final String LOG_TAG = RCTMGLAndroidTextureMapView.class.getSimpleName();
+ public static final String LOG_TAG = "RCTMGLAndroidTextureMapView";
public RCTMGLAndroidTextureMapView(Context context, RCTMGLAndroidTextureMapViewManager manager, MapboxMapOptions options) {
super(context, manager, options);
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.java
similarity index 90%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.java
index f96af25b7..39964b87a 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.java
@@ -10,7 +10,7 @@
*/
public class RCTMGLAndroidTextureMapViewManager extends RCTMGLMapViewManager {
- public static final String LOG_TAG = RCTMGLAndroidTextureMapViewManager.class.getSimpleName();
+ public static final String LOG_TAG = "RCTMGLAndroidTextureMapViewManager";
public static final String REACT_CLASS = "RCTMGLAndroidTextureMapView";
public RCTMGLAndroidTextureMapViewManager(ReactApplicationContext context) {
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java
similarity index 91%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java
index c896fad4a..4267e8c39 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.java
@@ -73,6 +73,8 @@
import com.mapbox.rctmgl.utils.GeoJSONUtils;
import com.mapbox.rctmgl.utils.GeoViewport;
+import com.mapbox.rctmgl.impl.SymbolClickListenerImpl;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -80,6 +82,7 @@
import java.util.List;
import java.util.Map;
import java.util.Locale;
+import org.json.*;
import javax.annotation.Nullable;
@@ -96,7 +99,7 @@ public class RCTMGLMapView extends MapView implements OnMapReadyCallback, Mapbox
MapView.OnWillStartRenderingFrameListener, MapView.OnDidFinishRenderingFrameListener,
MapView.OnWillStartRenderingMapListener, MapView.OnDidFinishRenderingMapListener,
MapView.OnDidFinishLoadingStyleListener, MapView.OnStyleImageMissingListener {
- public static final String LOG_TAG = RCTMGLMapView.class.getSimpleName();
+ public static final String LOG_TAG = "RCTMGLMapView";
private RCTMGLMapViewManager mManager;
private Context mContext;
@@ -130,6 +133,8 @@ public class RCTMGLMapView extends MapView implements OnMapReadyCallback, Mapbox
private Integer mAttributionGravity;
private int[] mAttributionMargin;
private Boolean mLogoEnabled;
+ private Integer mLogoGravity;
+ private int[] mLogoMargins;
private Boolean mCompassEnabled;
private ReadableMap mCompassViewMargins;
private int mCompassViewPosition = -1;
@@ -150,6 +155,8 @@ public class RCTMGLMapView extends MapView implements OnMapReadyCallback, Mapbox
private LocationComponentManager mLocationComponentManager = null;
+ private @Nullable Integer mTintColor = null;
+
public RCTMGLMapView(Context context, RCTMGLMapViewManager manager, MapboxMapOptions options) {
super(context, options);
@@ -319,9 +326,9 @@ public VisibleRegion getVisibleRegion(LatLng center, double zoomLevel) {
int[] contentPadding = mMap.getPadding();
int mapWidth = (int) ((mMap.getWidth() * 0.75 - (contentPadding[0] + contentPadding[2]))
- / metrics.scaledDensity);
+ / metrics.density);
int mapHeight = (int) ((mMap.getHeight() * 0.75 - (contentPadding[1] + contentPadding[3]))
- / metrics.scaledDensity);
+ / metrics.density);
VisibleRegion region = GeoViewport.getRegion(center, (int) zoomLevel, mapWidth, mapHeight);
return region;
}
@@ -342,8 +349,8 @@ public void moveCamera(CameraUpdate cameraUpdate) {
mMap.moveCamera(cameraUpdate);
}
- public void easeCamera(CameraUpdate cameraUpdate, int duration, MapboxMap.CancelableCallback callback) {
- mMap.easeCamera(cameraUpdate, duration, callback);
+ public void easeCamera(CameraUpdate cameraUpdate, int duration, boolean easingInterpolator, MapboxMap.CancelableCallback callback) {
+ mMap.easeCamera(cameraUpdate, duration, easingInterpolator, callback);
}
public void easeCamera(CameraUpdate cameraUpdate) {
@@ -418,16 +425,27 @@ public void waitForLayer(String layerID, FoundLayerCallback callback) {
}
}
+ public boolean isJSONValid(String test) {
+ try {
+ new JSONObject(test);
+ } catch (JSONException ex) {
+ return false;
+ }
+ return true;
+ }
+
+
@Override
public void onMapReady(final MapboxMap mapboxMap) {
mMap = mapboxMap;
- //if the myStyleURL contains "mapbox" the library will get the style from internet, else myStyleURL is a json and the library will load it
- if(mStyleURL.substring(0,6).contains("mapbox"))
- mMap.setStyle(new Style.Builder().fromUrl(mStyleURL));
- else
+ if (isJSONValid(mStyleURL)) {
mMap.setStyle(new Style.Builder().fromJson(mStyleURL));
-
+ } else {
+ mMap.setStyle(new Style.Builder().fromUri(mStyleURL));
+ }
+
+
reflow();
mMap.getStyle(new Style.OnStyleLoaded() {
@@ -459,6 +477,15 @@ public void onCameraMoveStarted(int reason) {
}
});
+ mMap.addOnCameraMoveListener(new MapboxMap.OnCameraMoveListener() {
+ @Override
+ public void onCameraMove() {
+ if (markerViewManager != null) {
+ markerViewManager.updateMarkers();
+ }
+ }
+ });
+
mMap.addOnMoveListener(new MapboxMap.OnMoveListener() {
@Override
public void onMoveBegin(MoveGestureDetector detector) {
@@ -491,12 +518,14 @@ public void run() {
public void createSymbolManager(Style style) {
symbolManager = new SymbolManager(this, mMap, style);
symbolManager.setIconAllowOverlap(true);
- symbolManager.addClickListener(new OnSymbolClickListener() {
- @Override
- public void onAnnotationClick(Symbol symbol) {
- onMarkerClick(symbol);
- }
- });
+ symbolManager.addClickListener(
+ SymbolClickListenerImpl.annotationClickListener(new SymbolClickListenerImpl.Listener() {
+ @Override
+ public boolean onAnnotationClick(Symbol symbol) {
+ onMarkerClick(symbol); return true;
+ }
+ })
+ );
symbolManager.addDragListener(new OnSymbolDragListener() {
@Override
public void onAnnotationDragStarted(Symbol symbol) {
@@ -722,6 +751,7 @@ public void onDidFinishRenderingMap(boolean fully) {
for (Pair preRenderMethod : mPreRenderMethods) {
Integer methodID = preRenderMethod.first;
ReadableArray args = preRenderMethod.second;
+
mManager.receiveCommand(this, methodID, args);
}
mPreRenderMethods.clear();
@@ -758,12 +788,21 @@ public void setReactStyleURL(String styleURL) {
if (mMap != null) {
removeAllSourcesFromMap();
- mMap.setStyle(styleURL, new Style.OnStyleLoaded() {
- @Override
- public void onStyleLoaded(@NonNull Style style) {
- addAllSourcesToMap();
- }
- });
+ if (isJSONValid(mStyleURL)) {
+ mMap.setStyle(new Style.Builder().fromJson(mStyleURL), new Style.OnStyleLoaded() {
+ @Override
+ public void onStyleLoaded(@NonNull Style style) {
+ addAllSourcesToMap();
+ }
+ });
+ } else {
+ mMap.setStyle(styleURL, new Style.OnStyleLoaded() {
+ @Override
+ public void onStyleLoaded(@NonNull Style style) {
+ addAllSourcesToMap();
+ }
+ });
+ }
}
}
@@ -806,6 +845,41 @@ public void setReactLogoEnabled(boolean logoEnabled) {
updateUISettings();
}
+ public void setReactLogoPosition(ReadableMap position) {
+ if (position == null) {
+ // reset from explicit to default
+ if (mLogoGravity != null) {
+ MapboxMapOptions defaultOptions = MapboxMapOptions.createFromAttributes(mContext);
+ mLogoGravity = defaultOptions.getLogoGravity();
+ mLogoMargins = Arrays.copyOf(defaultOptions.getLogoMargins(), 4);
+ updateUISettings();
+ }
+ return;
+ }
+
+ mLogoGravity = Gravity.NO_GRAVITY;
+ if (position.hasKey("left")) {
+ mLogoGravity |= Gravity.START;
+ }
+ if (position.hasKey("right")) {
+ mLogoGravity |= Gravity.END;
+ }
+ if (position.hasKey("top")) {
+ mLogoGravity |= Gravity.TOP;
+ }
+ if (position.hasKey("bottom")) {
+ mLogoGravity |= Gravity.BOTTOM;
+ }
+ float density = getDisplayDensity();
+ mLogoMargins = new int[]{
+ position.hasKey("left") ? (int) density * position.getInt("left") : 0,
+ position.hasKey("top") ? (int) density * position.getInt("top") : 0,
+ position.hasKey("right") ? (int) density * position.getInt("right") : 0,
+ position.hasKey("bottom") ? (int) density * position.getInt("bottom") : 0
+ };
+ updateUISettings();
+ }
+
public void setReactCompassEnabled(boolean compassEnabled) {
mCompassEnabled = compassEnabled;
updateUISettings();
@@ -1059,10 +1133,33 @@ private void updateUISettings() {
);
}
+ if (mTintColor != null) {
+ uiSettings.setAttributionTintColor(mTintColor);
+ }
+
if (mLogoEnabled != null && uiSettings.isLogoEnabled() != mLogoEnabled) {
uiSettings.setLogoEnabled(mLogoEnabled);
}
+ if (mLogoGravity != null && uiSettings.getLogoGravity() != mLogoGravity) {
+ uiSettings.setLogoGravity(mLogoGravity);
+ }
+
+ if (mLogoMargins != null &&
+ (uiSettings.getLogoMarginLeft() != mLogoMargins[0] ||
+ uiSettings.getLogoMarginTop() != mLogoMargins[1] ||
+ uiSettings.getLogoMarginRight() != mLogoMargins[2] ||
+ uiSettings.getLogoMarginBottom() != mLogoMargins[3]
+ )
+ ) {
+ uiSettings.setLogoMargins(
+ mLogoMargins[0],
+ mLogoMargins[1],
+ mLogoMargins[2],
+ mLogoMargins[3]
+ );
+ }
+
if (mCompassEnabled != null && uiSettings.isCompassEnabled() != mCompassEnabled) {
uiSettings.setCompassEnabled(mCompassEnabled);
}
@@ -1076,7 +1173,7 @@ private void updateUISettings() {
uiSettings.setCompassGravity(Gravity.TOP | Gravity.END);
break;
case 2:
- uiSettings.setCompassGravity(Gravity.BOTTOM | Gravity.END);
+ uiSettings.setCompassGravity(Gravity.BOTTOM | Gravity.START);
break;
case 3:
uiSettings.setCompassGravity(Gravity.BOTTOM | Gravity.END);
@@ -1125,7 +1222,7 @@ private void updatePreferredFramesPerSecond() {
public double[] getContentInset() {
if (mInsets == null) {
double[] result = {0,0,0,0};
-
+
return result;
}
double top = 0, right = 0, bottom = 0, left = 0;
@@ -1148,8 +1245,8 @@ public double[] getContentInset() {
}
final DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
-
- double[] result = {left * metrics.scaledDensity, top * metrics.scaledDensity, right * metrics.scaledDensity, bottom * metrics.scaledDensity};
+
+ double[] result = {left * metrics.density, top * metrics.density, right * metrics.density, bottom * metrics.density};
return result;
}
@@ -1363,7 +1460,10 @@ private WritableMap makeLocationChangePayload(Location location) {
coords.putDouble("latitude", location.getLatitude());
coords.putDouble("altitude", location.getAltitude());
coords.putDouble("accuracy", location.getAccuracy());
+ // A better solution will be to pull the heading from the compass engine,
+ // unfortunately the api is not publicly available in the mapbox sdk
coords.putDouble("heading", location.getBearing());
+ coords.putDouble("course", location.getBearing());
coords.putDouble("speed", location.getSpeed());
positionProperties.putMap("coords", coords);
@@ -1413,4 +1513,16 @@ public LocationComponentManager getLocationComponentManager() {
}
return mLocationComponentManager;
}
+
+ public @Nullable Integer getTintColor() {
+ return mTintColor;
+ }
+
+ public void setTintColor(@Nullable Integer tintColor) {
+ if (mTintColor == tintColor) return;
+ mTintColor = tintColor;
+ updateUISettings();
+ if (mLocationComponentManager == null) return;
+ mLocationComponentManager.update(getMapboxMap().getStyle());
+ }
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.java
similarity index 90%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.java
index c6cd92c03..32ed74561 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.java
@@ -38,7 +38,7 @@
*/
public class RCTMGLMapViewManager extends AbstractEventEmitter {
- public static final String LOG_TAG = RCTMGLMapViewManager.class.getSimpleName();
+ public static final String LOG_TAG = "RCTMGLMapViewManager";
public static final String REACT_CLASS = "RCTMGLMapView";
private Map mViews;
@@ -165,6 +165,11 @@ public void setLogoEnabled(RCTMGLMapView mapView, boolean logoEnabled) {
mapView.setReactLogoEnabled(logoEnabled);
}
+ @ReactProp(name="logoPosition")
+ public void setLogoPosition(RCTMGLMapView mapView, ReadableMap logoPosition) {
+ mapView.setReactLogoPosition(logoPosition);
+ }
+
@ReactProp(name="compassEnabled")
public void setCompassEnabled(RCTMGLMapView mapView, boolean compassEnabled) {
mapView.setReactCompassEnabled(compassEnabled);
@@ -185,6 +190,11 @@ public void setContentInset(RCTMGLMapView mapView, ReadableArray array) {
mapView.setReactContentInset(array);
}
+ @ReactProp(name = "tintColor", customType = "Color")
+ public void setTintColor(RCTMGLMapView mapView, @Nullable Integer tintColor) {
+ mapView.setTintColor(tintColor);
+ }
+
//endregion
//region Custom Events
@@ -236,6 +246,7 @@ public Map getCommandsMap() {
@Override
public void receiveCommand(RCTMGLMapView mapView, int commandID, @Nullable ReadableArray args) {
+ String callbackID = args.getString(0);
// allows method calls to work with componentDidMount
MapboxMap mapboxMap = mapView.getMapboxMap();
if (mapboxMap == null) {
@@ -246,41 +257,42 @@ public void receiveCommand(RCTMGLMapView mapView, int commandID, @Nullable Reada
switch (commandID) {
case METHOD_QUERY_FEATURES_POINT:
mapView.queryRenderedFeaturesAtPoint(
- args.getString(0),
+ callbackID,
ConvertUtils.toPointF(args.getArray(1)),
ExpressionParser.from(args.getArray(2)),
ConvertUtils.toStringList(args.getArray(3)));
break;
case METHOD_QUERY_FEATURES_RECT:
mapView.queryRenderedFeaturesInRect(
- args.getString(0),
+ callbackID,
ConvertUtils.toRectF(args.getArray(1)),
ExpressionParser.from(args.getArray(2)),
ConvertUtils.toStringList(args.getArray(3)));
break;
case METHOD_VISIBLE_BOUNDS:
- mapView.getVisibleBounds(args.getString(0));
+ mapView.getVisibleBounds(callbackID);
break;
case METHOD_GET_POINT_IN_VIEW:
- mapView.getPointInView(args.getString(0), GeoJSONUtils.toLatLng(args.getArray(1)));
+ mapView.getPointInView(callbackID, GeoJSONUtils.toLatLng(args.getArray(1)));
break;
case METHOD_GET_COORDINATE_FROM_VIEW:
- mapView.getCoordinateFromView(args.getString(0), ConvertUtils.toPointF(args.getArray(1)));
+ mapView.getCoordinateFromView(callbackID, ConvertUtils.toPointF(args.getArray(1)));
break;
case METHOD_TAKE_SNAP:
- mapView.takeSnap(args.getString(0), args.getBoolean(1));
+ mapView.takeSnap(callbackID, args.getBoolean(1));
break;
case METHOD_GET_ZOOM:
- mapView.getZoom(args.getString(0));
+ mapView.getZoom(callbackID);
break;
case METHOD_GET_CENTER:
- mapView.getCenter(args.getString(0));
+ mapView.getCenter(callbackID);
break;
case METHOD_SET_HANDLED_MAP_EVENTS:
if(args != null) {
+ ReadableArray events = args.getArray(1);
ArrayList eventsArray = new ArrayList<>();
- for (int i = 1; i < args.size(); i++) {
- eventsArray.add(args.getString(i));
+ for (int i = 0; i < events.size(); i++) {
+ eventsArray.add(events.getString(i));
}
mapView.setHandledMapChangedEvents(eventsArray);
}
@@ -332,7 +344,7 @@ public void run()
}
catch (Exception ex)
{
- Log.e(getClass().getSimpleName() , " disposeNativeMapView() exception destroying map view", ex);
+ Log.e(LOG_TAG , " disposeNativeMapView() exception destroying map view", ex);
}
}
});
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/helpers/CameraChangeTracker.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/helpers/CameraChangeTracker.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/mapview/helpers/CameraChangeTracker.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/mapview/helpers/CameraChangeTracker.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyle.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/RCTMGLStyle.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyle.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/RCTMGLStyle.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java
similarity index 97%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java
index 2e9d75677..613ae7b24 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java
@@ -36,6 +36,9 @@ public static void setFillLayerStyle(final FillLayer layer, RCTMGLStyle style) {
final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
switch (styleKey) {
+ case "fillSortKey":
+ RCTMGLStyleFactory.setFillSortKey(layer, styleValue);
+ break;
case "visibility":
RCTMGLStyleFactory.setVisibility(layer, styleValue);
break;
@@ -77,9 +80,6 @@ public void onAllImagesLoaded() {
}
});
break;
- case "fillPatternTransition":
- RCTMGLStyleFactory.setFillPatternTransition(layer, styleValue);
- break;
}
}
}
@@ -106,6 +106,9 @@ public static void setLineLayerStyle(final LineLayer layer, RCTMGLStyle style) {
case "lineRoundLimit":
RCTMGLStyleFactory.setLineRoundLimit(layer, styleValue);
break;
+ case "lineSortKey":
+ RCTMGLStyleFactory.setLineSortKey(layer, styleValue);
+ break;
case "visibility":
RCTMGLStyleFactory.setVisibility(layer, styleValue);
break;
@@ -157,9 +160,6 @@ public static void setLineLayerStyle(final LineLayer layer, RCTMGLStyle style) {
case "lineDasharray":
RCTMGLStyleFactory.setLineDasharray(layer, styleValue);
break;
- case "lineDasharrayTransition":
- RCTMGLStyleFactory.setLineDasharrayTransition(layer, styleValue);
- break;
case "linePattern":
style.addImage(styleValue, new DownloadMapImageTask.OnAllImagesLoaded() {
@Override
@@ -168,9 +168,6 @@ public void onAllImagesLoaded() {
}
});
break;
- case "linePatternTransition":
- RCTMGLStyleFactory.setLinePatternTransition(layer, styleValue);
- break;
case "lineGradient":
RCTMGLStyleFactory.setLineGradient(layer, styleValue);
break;
@@ -558,9 +555,6 @@ public void onAllImagesLoaded() {
}
});
break;
- case "fillExtrusionPatternTransition":
- RCTMGLStyleFactory.setFillExtrusionPatternTransition(layer, styleValue);
- break;
case "fillExtrusionHeight":
RCTMGLStyleFactory.setFillExtrusionHeight(layer, styleValue);
break;
@@ -573,6 +567,9 @@ public void onAllImagesLoaded() {
case "fillExtrusionBaseTransition":
RCTMGLStyleFactory.setFillExtrusionBaseTransition(layer, styleValue);
break;
+ case "fillExtrusionVerticalGradient":
+ RCTMGLStyleFactory.setFillExtrusionVerticalGradient(layer, styleValue);
+ break;
}
}
}
@@ -710,9 +707,6 @@ public void onAllImagesLoaded() {
}
});
break;
- case "backgroundPatternTransition":
- RCTMGLStyleFactory.setBackgroundPatternTransition(layer, styleValue);
- break;
case "backgroundOpacity":
RCTMGLStyleFactory.setBackgroundOpacity(layer, styleValue);
break;
@@ -758,6 +752,14 @@ public static void setLightLayerStyle(final Light layer, RCTMGLStyle style) {
}
}
+ public static void setFillSortKey(FillLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.setProperties(PropertyFactory.fillSortKey(styleValue.getExpression()));
+ } else {
+ layer.setProperties(PropertyFactory.fillSortKey(styleValue.getFloat(VALUE_KEY)));
+ }
+ }
+
public static void setVisibility(FillLayer layer, RCTMGLStyleValue styleValue) {
layer.setProperties(PropertyFactory.visibility(styleValue.getString(VALUE_KEY)));
}
@@ -854,14 +856,6 @@ public static void setFillPattern(FillLayer layer, RCTMGLStyleValue styleValue)
}
}
-
- public static void setFillPatternTransition(FillLayer layer, RCTMGLStyleValue styleValue) {
- TransitionOptions transition = styleValue.getTransition();
- if (transition != null) {
- layer.setFillPatternTransition(transition);
- }
- }
-
public static void setLineCap(LineLayer layer, RCTMGLStyleValue styleValue) {
if (styleValue.isExpression()) {
layer.setProperties(PropertyFactory.lineCap(styleValue.getExpression()));
@@ -894,6 +888,14 @@ public static void setLineRoundLimit(LineLayer layer, RCTMGLStyleValue styleValu
}
}
+ public static void setLineSortKey(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.setProperties(PropertyFactory.lineSortKey(styleValue.getExpression()));
+ } else {
+ layer.setProperties(PropertyFactory.lineSortKey(styleValue.getFloat(VALUE_KEY)));
+ }
+ }
+
public static void setVisibility(LineLayer layer, RCTMGLStyleValue styleValue) {
layer.setProperties(PropertyFactory.visibility(styleValue.getString(VALUE_KEY)));
}
@@ -1026,14 +1028,6 @@ public static void setLineDasharray(LineLayer layer, RCTMGLStyleValue styleValue
}
}
-
- public static void setLineDasharrayTransition(LineLayer layer, RCTMGLStyleValue styleValue) {
- TransitionOptions transition = styleValue.getTransition();
- if (transition != null) {
- layer.setLineDasharrayTransition(transition);
- }
- }
-
public static void setLinePattern(LineLayer layer, RCTMGLStyleValue styleValue) {
if (styleValue.isExpression()) {
if (styleValue.isImageStringValue()) {
@@ -1046,14 +1040,6 @@ public static void setLinePattern(LineLayer layer, RCTMGLStyleValue styleValue)
}
}
-
- public static void setLinePatternTransition(LineLayer layer, RCTMGLStyleValue styleValue) {
- TransitionOptions transition = styleValue.getTransition();
- if (transition != null) {
- layer.setLinePatternTransition(transition);
- }
- }
-
public static void setLineGradient(LineLayer layer, RCTMGLStyleValue styleValue) {
if (styleValue.isExpression()) {
layer.setProperties(PropertyFactory.lineGradient(styleValue.getExpression()));
@@ -1902,14 +1888,6 @@ public static void setFillExtrusionPattern(FillExtrusionLayer layer, RCTMGLStyle
}
}
-
- public static void setFillExtrusionPatternTransition(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
- TransitionOptions transition = styleValue.getTransition();
- if (transition != null) {
- layer.setFillExtrusionPatternTransition(transition);
- }
- }
-
public static void setFillExtrusionHeight(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
if (styleValue.isExpression()) {
layer.setProperties(PropertyFactory.fillExtrusionHeight(styleValue.getExpression()));
@@ -1942,6 +1920,14 @@ public static void setFillExtrusionBaseTransition(FillExtrusionLayer layer, RCTM
}
}
+ public static void setFillExtrusionVerticalGradient(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.setProperties(PropertyFactory.fillExtrusionVerticalGradient(styleValue.getExpression()));
+ } else {
+ layer.setProperties(PropertyFactory.fillExtrusionVerticalGradient(styleValue.getBoolean(VALUE_KEY)));
+ }
+ }
+
public static void setVisibility(RasterLayer layer, RCTMGLStyleValue styleValue) {
layer.setProperties(PropertyFactory.visibility(styleValue.getString(VALUE_KEY)));
}
@@ -2174,14 +2160,6 @@ public static void setBackgroundPattern(BackgroundLayer layer, RCTMGLStyleValue
}
}
-
- public static void setBackgroundPatternTransition(BackgroundLayer layer, RCTMGLStyleValue styleValue) {
- TransitionOptions transition = styleValue.getTransition();
- if (transition != null) {
- layer.setBackgroundPatternTransition(transition);
- }
- }
-
public static void setBackgroundOpacity(BackgroundLayer layer, RCTMGLStyleValue styleValue) {
if (styleValue.isExpression()) {
layer.setProperties(PropertyFactory.backgroundOpacity(styleValue.getExpression()));
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFunctionParser.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/RCTMGLStyleFunctionParser.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleFunctionParser.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/RCTMGLStyleFunctionParser.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.java
similarity index 97%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.java
index f3560322a..9a0c8dd1c 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.java
@@ -95,6 +95,10 @@ public String getString(String key) {
return mPayload.getString(key);
}
+ public String getEnumName() {
+ return mPayload.getString("value").toUpperCase().replaceAll("-","_");
+ }
+
public Double getDouble(String key) {
return mPayload.getDouble(key);
}
@@ -204,7 +208,7 @@ public TransitionOptions getTransition() {
duration = config.getMap("duration").getInt("value");
}
if (config.hasKey("delay") && ReadableType.Map.equals(config.getType("delay"))) {
- duration = config.getMap("delay").getInt("value");
+ delay = config.getMap("delay").getInt("value");
}
return new TransitionOptions(duration, delay, enablePlacementTransitions);
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTLayer.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTLayer.java
similarity index 97%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTLayer.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTLayer.java
index 249e89402..477197525 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTLayer.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTLayer.java
@@ -5,6 +5,7 @@
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.common.logging.FLog;
+import com.mapbox.mapboxsdk.location.LocationComponentConstants;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.expressions.Expression;
@@ -13,7 +14,6 @@
import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
import com.mapbox.rctmgl.components.AbstractMapFeature;
import com.mapbox.rctmgl.components.mapview.RCTMGLMapView;
-import com.mapbox.rctmgl.location.UserLocationLayerConstants;
import com.mapbox.rctmgl.utils.ExpressionParser;
import java.util.Arrays;
@@ -25,7 +25,7 @@
*/
public abstract class RCTLayer extends AbstractMapFeature {
- public static final String LOG_TAG = RCTLayer.class.getSimpleName();
+ public static final String LOG_TAG = "RCTLayer";
protected String mID;
protected String mSourceID;
@@ -155,7 +155,7 @@ public void add() {
}
if (getStyle() == null) return;
- String userBackgroundID = UserLocationLayerConstants.BACKGROUND_LAYER_ID;
+ String userBackgroundID = LocationComponentConstants.BACKGROUND_LAYER;
Layer userLocationBackgroundLayer = getStyle().getLayer(userBackgroundID);
// place below user location layer
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayerManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayerManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayerManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayerManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayerManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayerManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayerManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayerManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayerManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayerManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayerManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayerManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayerManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayerManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayerManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayerManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayerManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayerManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayerManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayerManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayerManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayerManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayerManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayerManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayerManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayerManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayerManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayerManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayerManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayerManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayerManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayerManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/light/RCTMGLLight.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/light/RCTMGLLight.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/light/RCTMGLLight.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/light/RCTMGLLight.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/light/RCTMGLLightManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/light/RCTMGLLightManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/light/RCTMGLLightManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/light/RCTMGLLightManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSource.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSource.java
similarity index 87%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSource.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSource.java
index 2d97fdb61..d39c22ef3 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSource.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSource.java
@@ -19,7 +19,7 @@
*/
public class RCTMGLImageSource extends RCTSource {
- public static final String LOG_TAG = RCTMGLImageSource.class.getSimpleName();
+ public static final String LOG_TAG = "RCTMGLImageSource";
private URL mURL;
private int mResourceId;
@@ -70,8 +70,12 @@ public void setURL(String url) {
public void setCoordinates(LatLngQuad coordQuad) {
mCoordQuad = coordQuad;
- if (mSource != null) {
- mSource.setCoordinates(this.mCoordQuad);
+ try {
+ if (mSource != null) {
+ mSource.setCoordinates(this.mCoordQuad);
+ }
+ } catch (Exception e) {
+ Log.w(LOG_TAG, e.getLocalizedMessage());
}
}
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSourceManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSourceManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSourceManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSourceManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSource.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSource.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSource.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSource.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSourceManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSourceManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSourceManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSourceManager.java
diff --git a/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSource.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSource.java
new file mode 100644
index 000000000..6894ab372
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSource.java
@@ -0,0 +1,316 @@
+package com.mapbox.rctmgl.components.styles.sources;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.Size;
+import androidx.core.content.res.ResourcesCompat;
+
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.bridge.WritableNativeMap;
+import com.mapbox.geojson.Feature;
+import com.mapbox.geojson.FeatureCollection;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.Style;
+import com.mapbox.mapboxsdk.style.expressions.Expression;
+import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions;
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
+import com.mapbox.mapboxsdk.utils.BitmapUtils;
+import com.mapbox.rctmgl.R;
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView;
+import com.mapbox.rctmgl.events.AndroidCallbackEvent;
+import com.mapbox.rctmgl.events.FeatureClickEvent;
+import com.mapbox.rctmgl.utils.ClusterPropertyEntry;
+import com.mapbox.rctmgl.utils.DownloadMapImageTask;
+import com.mapbox.rctmgl.utils.ImageEntry;
+
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by nickitaliano on 9/19/17.
+ */
+
+public class RCTMGLShapeSource extends RCTSource {
+ private URL mURL;
+ private RCTMGLShapeSourceManager mManager;
+
+ private String mShape;
+
+ private Boolean mCluster;
+ private Integer mClusterRadius;
+ private Integer mClusterMaxZoom;
+ private List> mClusterProperties;
+
+ private Integer mMaxZoom;
+ private Integer mBuffer;
+ private Double mTolerance;
+ private Boolean mLineMetrics;
+
+ private static Bitmap mImagePlaceholder;
+ private List> mImages;
+ private List> mNativeImages;
+
+ public RCTMGLShapeSource(Context context, RCTMGLShapeSourceManager manager) {
+ super(context);
+ mManager = manager;
+ }
+
+ @Override
+ public void addToMap(final RCTMGLMapView mapView) {
+ // Wait for style before adding the source to the map
+ mapView.getMapboxMap().getStyle(new Style.OnStyleLoaded() {
+ @Override
+ public void onStyleLoaded(@NonNull Style style) {
+ MapboxMap map = mapView.getMapboxMap();
+ RCTMGLShapeSource.super.addToMap(mapView);
+ }
+ });
+ }
+
+ @Override
+ public GeoJsonSource makeSource() {
+ GeoJsonOptions options = getOptions();
+
+ if (mShape != null) {
+ return new GeoJsonSource(mID, mShape, options);
+ }
+
+ return new GeoJsonSource(mID, mURL, options);
+ }
+
+ public void setURL(URL url) {
+ mURL = url;
+
+ if (mSource != null && mMapView != null && !mMapView.isDestroyed() ) {
+ mSource.setUrl(mURL);
+ }
+ }
+
+ public void setShape(String geoJSONStr) {
+ mShape = geoJSONStr;
+
+ if (mSource != null && mMapView != null && !mMapView.isDestroyed() ) {
+ mSource.setGeoJson(mShape);
+ }
+ }
+
+ public void setCluster(boolean cluster) {
+ mCluster = cluster;
+ }
+
+ public void setClusterRadius(int clusterRadius) {
+ mClusterRadius = clusterRadius;
+ }
+
+ public void setClusterMaxZoom(int clusterMaxZoom) {
+ mClusterMaxZoom = clusterMaxZoom;
+ }
+
+ public void setClusterProperties(List> clusterProperties) {
+ mClusterProperties = clusterProperties;
+ }
+
+ public void setMaxZoom(int maxZoom) {
+ mMaxZoom = maxZoom;
+ }
+
+ public void setBuffer(int buffer) {
+ mBuffer = buffer;
+ }
+
+ public void setTolerance(double tolerance) {
+ mTolerance = tolerance;
+ }
+
+ public void setLineMetrics(boolean lineMetrics) {
+ mLineMetrics = lineMetrics;
+ }
+
+ public void onPress(OnPressEvent event) {
+ mManager.handleEvent(FeatureClickEvent.makeShapeSourceEvent(this, event));
+ }
+
+ private GeoJsonOptions getOptions() {
+ GeoJsonOptions options = new GeoJsonOptions();
+
+ if (mCluster != null) {
+ options.withCluster(mCluster);
+ }
+
+ if (mClusterRadius != null) {
+ options.withClusterRadius(mClusterRadius);
+ }
+
+ if (mClusterMaxZoom != null) {
+ options.withClusterMaxZoom(mClusterMaxZoom);
+ }
+
+ if (mClusterProperties != null) {
+ for (Map.Entry entry : mClusterProperties) {
+ ClusterPropertyEntry property = entry.getValue();
+
+ options.withClusterProperty(entry.getKey(), property.operator, property.mapping);
+ }
+ }
+
+ if (mMaxZoom != null) {
+ options.withMaxZoom(mMaxZoom);
+ }
+
+ if (mBuffer != null) {
+ options.withBuffer(mBuffer);
+ }
+
+ if (mTolerance != null) {
+ options.withTolerance(mTolerance.floatValue());
+ }
+
+ if (mLineMetrics != null) {
+ options.withLineMetrics(mLineMetrics);
+ }
+
+ return options;
+ }
+
+ public void querySourceFeatures(String callbackID,
+ @Nullable Expression filter) {
+ if (mSource == null) {
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("error", "source is not yet loaded");
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ return;
+ }
+ List features = mSource.querySourceFeatures(filter);
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("data", FeatureCollection.fromFeatures(features).toJson());
+
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ }
+
+ public void getClusterExpansionZoom(String callbackID, String featureJSON) {
+ if (mSource == null) {
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("error", "source is not yet loaded");
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ return;
+ }
+ Feature feature = Feature.fromJson(featureJSON);
+
+ int zoom = mSource.getClusterExpansionZoom(feature);
+
+ WritableMap payload = new WritableNativeMap();
+ payload.putInt("data", zoom);
+
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ }
+
+ public void getClusterLeaves(String callbackID, String featureJSON, int number, int offset) {
+ if (mSource == null) {
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("error", "source is not yet loaded");
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ return;
+ }
+ Feature clusterFeature = Feature.fromJson(featureJSON);
+ FeatureCollection leaves = mSource.getClusterLeaves(clusterFeature, number, offset);
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("data", leaves.toJson());
+
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ }
+
+ public void getClusterChildren(String callbackID, String featureJSON) {
+ if (mSource == null) {
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("error", "source is not yet loaded");
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ return;
+ }
+ Feature clusterFeature = Feature.fromJson(featureJSON);
+ FeatureCollection leaves = mSource.getClusterChildren(clusterFeature);
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("data", leaves.toJson());
+
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ }
+
+ // Deprecated. Will be removed in 9+ ver.
+ public void getClusterExpansionZoomById(String callbackID, int clusterId) {
+ if (mSource == null) {
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("error", "source is not yet loaded");
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ return;
+ }
+ List features = mSource.querySourceFeatures(Expression.eq(Expression.id(), clusterId));
+ int zoom = -1;
+ if (features.size() > 0) {
+ zoom = mSource.getClusterExpansionZoom(features.get(0));
+ }
+
+ if (zoom == -1) {
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("error", "Could not get zoom for cluster id " + clusterId);
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ return;
+ }
+
+ WritableMap payload = new WritableNativeMap();
+ payload.putInt("data", zoom);
+
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ }
+
+ // Deprecated. Will be removed in 9+ ver.
+ public void getClusterLeavesById(String callbackID, int clusterId, int number, int offset) {
+ if (mSource == null) {
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("error", "source is not yet loaded");
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ return;
+ }
+ Feature clusterFeature = mSource.querySourceFeatures(Expression.eq(Expression.get("cluster_id"), clusterId)).get(0);
+ FeatureCollection leaves = mSource.getClusterLeaves(clusterFeature, number, offset);
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("data", leaves.toJson());
+
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ }
+
+ // Deprecated. Will be removed in 9+ ver.
+ public void getClusterChildrenById(String callbackID, int clusterId) {
+ if (mSource == null) {
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("error", "source is not yet loaded");
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ return;
+ }
+ Feature clusterFeature = mSource.querySourceFeatures(Expression.eq(Expression.get("cluster_id"), clusterId)).get(0);
+ FeatureCollection leaves = mSource.getClusterChildren(clusterFeature);
+ WritableMap payload = new WritableNativeMap();
+ payload.putString("data", leaves.toJson());
+
+ AndroidCallbackEvent event = new AndroidCallbackEvent(this, callbackID, payload);
+ mManager.handleEvent(event);
+ }
+}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.java
similarity index 59%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.java
index 75669814a..22bb0eca2 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.java
@@ -18,11 +18,13 @@
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
+import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.rctmgl.components.AbstractEventEmitter;
import com.mapbox.rctmgl.components.annotation.RCTMGLCallout;
import com.mapbox.rctmgl.components.mapview.RCTMGLMapView;
import com.mapbox.rctmgl.components.styles.layers.RCTLayer;
import com.mapbox.rctmgl.events.constants.EventKeys;
+import com.mapbox.rctmgl.utils.ClusterPropertyEntry;
import com.mapbox.rctmgl.utils.ExpressionParser;
import com.mapbox.rctmgl.utils.ImageEntry;
import com.mapbox.rctmgl.utils.ResourceUtils;
@@ -39,7 +41,7 @@
*/
public class RCTMGLShapeSourceManager extends AbstractEventEmitter {
- public static final String LOG_TAG = RCTMGLShapeSourceManager.class.getSimpleName();
+ public static final String LOG_TAG = "RCTMGLShapeSourceManager";
public static final String REACT_CLASS = "RCTMGLShapeSource";
private ReactApplicationContext mContext;
@@ -113,6 +115,30 @@ public void setClusterMaxZoomLevel(RCTMGLShapeSource source, int clusterMaxZoom)
source.setClusterMaxZoom(clusterMaxZoom);
}
+ @ReactProp(name = "clusterProperties")
+ public void setClusterProperties(RCTMGLShapeSource source, ReadableMap map) {
+ List> properties = new ArrayList<>();
+
+ ReadableMapKeySetIterator iterator = map.keySetIterator();
+ while (iterator.hasNextKey()) {
+ String name = iterator.nextKey();
+ ReadableArray expressions = map.getArray(name);
+
+ Expression operator;
+ if (expressions.getType(0) == ReadableType.Array) {
+ operator = ExpressionParser.from(expressions.getArray(0));
+ } else {
+ operator = Expression.literal(expressions.getString(0));
+ }
+
+ Expression mapping = ExpressionParser.from(expressions.getArray(1));
+
+ properties.add(new AbstractMap.SimpleEntry<>(name, new ClusterPropertyEntry(operator, mapping)));
+ }
+
+ source.setClusterProperties(properties);
+ }
+
@ReactProp(name = "maxZoomLevel")
public void setMaxZoomLevel(RCTMGLShapeSource source, int maxZoom) {
source.setMaxZoom(maxZoom);
@@ -128,6 +154,11 @@ public void setTolerance(RCTMGLShapeSource source, double tolerance) {
source.setTolerance(tolerance);
}
+ @ReactProp(name = "lineMetrics")
+ public void setLineMetrics(RCTMGLShapeSource source, boolean lineMetrics) {
+ source.setLineMetrics(lineMetrics);
+ }
+
@ReactProp(name = "hasPressListener")
public void setHasPressListener(RCTMGLShapeSource source, boolean hasPressListener) {
source.setHasPressListener(hasPressListener);
@@ -148,12 +179,29 @@ public Map customEvents() {
//region React Methods
public static final int METHOD_FEATURES = 103;
+ public static final int METHOD_GET_CLUSTER_EXPANSION_ZOOM = 104;
+ public static final int METHOD_GET_CLUSTER_LEAVES = 105;
+ public static final int METHOD_GET_CLUSTER_CHILDREN = 106;
+
+ // Deprecated. Will be removed in 9+ ver.
+ public static final int METHOD_GET_CLUSTER_EXPANSION_ZOOM_BY_ID = 107;
+ public static final int METHOD_GET_CLUSTER_LEAVES_BY_ID = 108;
+ public static final int METHOD_GET_CLUSTER_CHILDREN_BY_ID = 109;
@Nullable
@Override
public Map getCommandsMap() {
return MapBuilder.builder()
.put("features", METHOD_FEATURES)
+ .put("getClusterExpansionZoom", METHOD_GET_CLUSTER_EXPANSION_ZOOM)
+ .put("getClusterLeaves", METHOD_GET_CLUSTER_LEAVES)
+ .put("getClusterChildren", METHOD_GET_CLUSTER_CHILDREN)
+
+ // Deprecated. Will be removed in 9+ ver.
+ .put("getClusterExpansionZoomById", METHOD_GET_CLUSTER_EXPANSION_ZOOM_BY_ID)
+ .put("getClusterLeavesById", METHOD_GET_CLUSTER_LEAVES_BY_ID)
+ .put("getClusterChildrenById", METHOD_GET_CLUSTER_CHILDREN_BY_ID)
+
.build();
}
@@ -164,7 +212,41 @@ public void receiveCommand(RCTMGLShapeSource source, int commandID, @Nullable Re
source.querySourceFeatures(
args.getString(0),
ExpressionParser.from(args.getArray(1))
- );
+ );
+ break;
+ case METHOD_GET_CLUSTER_EXPANSION_ZOOM:
+ source.getClusterExpansionZoom(args.getString(0), args.getString(1));
+ break;
+ case METHOD_GET_CLUSTER_LEAVES:
+ source.getClusterLeaves(
+ args.getString(0),
+ args.getString(1),
+ args.getInt(2),
+ args.getInt((3))
+ );
+ break;
+ case METHOD_GET_CLUSTER_CHILDREN:
+ source.getClusterChildren(
+ args.getString(0),
+ args.getString(1)
+ );
+ break;
+ case METHOD_GET_CLUSTER_EXPANSION_ZOOM_BY_ID:
+ source.getClusterExpansionZoomById(args.getString(0), args.getInt(1));
+ break;
+ case METHOD_GET_CLUSTER_LEAVES_BY_ID:
+ source.getClusterLeavesById(
+ args.getString(0),
+ args.getInt(1),
+ args.getInt(2),
+ args.getInt((3))
+ );
+ break;
+ case METHOD_GET_CLUSTER_CHILDREN_BY_ID:
+ source.getClusterChildrenById(
+ args.getString(0),
+ args.getInt(1)
+ );
break;
}
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSource.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSource.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSource.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSource.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSourceManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSourceManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSourceManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSourceManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSource.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSource.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSource.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSource.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSourceManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSourceManager.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSourceManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSourceManager.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTSource.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTSource.java
similarity index 95%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTSource.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTSource.java
index 92ce50dd0..6b8d8c197 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/components/styles/sources/RCTSource.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/components/styles/sources/RCTSource.java
@@ -10,6 +10,7 @@
import com.facebook.react.common.MapBuilder;
import com.mapbox.geojson.Feature;
import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.log.Logger;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.sources.Source;
@@ -28,6 +29,7 @@
public abstract class RCTSource extends AbstractMapFeature {
public static final String DEFAULT_ID = "composite";
+ public static final String LOG_TAG = "RCTSource";
public static final double DEFAULT_HITBOX_WIDTH = 44.0;
public static final double DEFAULT_HITBOX_HEIGHT = 44.0;
@@ -155,7 +157,11 @@ public void removeFromMap(RCTMGLMapView mapView) {
mQueuedLayers.clear();
}
if (mMap != null && mSource != null && mMap.getStyle() != null) {
- mMap.getStyle().removeSource(mSource);
+ try {
+ mMap.getStyle().removeSource(mSource);
+ } catch (Throwable ex) {
+ Logger.w(LOG_TAG, String.format("RCTSource.removeFromMap: %s - %s", mSource, ex.getMessage()), ex);
+ }
}
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/AbstractEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/AbstractEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/AbstractEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/AbstractEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/AndroidCallbackEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/AndroidCallbackEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/AndroidCallbackEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/AndroidCallbackEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/EventEmitter.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/EventEmitter.java
similarity index 95%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/EventEmitter.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/EventEmitter.java
index f33f61b51..da009739e 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/EventEmitter.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/EventEmitter.java
@@ -11,7 +11,7 @@
public class EventEmitter {
- public static final String LOG_TAG = EventEmitter.class.getSimpleName();
+ public static final String LOG_TAG = "EventEmitter";
private static ReactContext getCurrentReactContext(ReactApplicationContext reactApplicationContext) {
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/FeatureClickEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/FeatureClickEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/FeatureClickEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/FeatureClickEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/IEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/IEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/IEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/IEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/ImageMissingEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/ImageMissingEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/ImageMissingEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/ImageMissingEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/LocationEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/LocationEvent.java
similarity index 92%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/LocationEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/LocationEvent.java
index c6f1d601d..91718dc3c 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/LocationEvent.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/LocationEvent.java
@@ -73,7 +73,10 @@ public WritableMap getPayload() {
coords.putDouble("latitude", location.getLatitude());
coords.putDouble("altitude", location.getAltitude());
coords.putDouble("accuracy", location.getAccuracy());
+ // A better solution will be to pull the heading from the compass engine,
+ // unfortunately the api is not publicly available in the mapbox sdk
coords.putDouble("heading", location.getBearing());
+ coords.putDouble("course", location.getBearing());
coords.putDouble("speed", location.getSpeed());
positionProperties.putMap("coords", coords);
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/MapChangeEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/MapChangeEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/MapChangeEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/MapChangeEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/MapClickEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/MapClickEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/MapClickEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/MapClickEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/MapUserTrackingModeEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/MapUserTrackingModeEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/MapUserTrackingModeEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/MapUserTrackingModeEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/OfflineEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/OfflineEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/OfflineEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/OfflineEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/PointAnnotationClickEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/PointAnnotationClickEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/PointAnnotationClickEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/PointAnnotationClickEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/PointAnnotationDragEvent.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/PointAnnotationDragEvent.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/PointAnnotationDragEvent.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/PointAnnotationDragEvent.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/constants/EventKeys.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/constants/EventKeys.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/constants/EventKeys.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/constants/EventKeys.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/events/constants/EventTypes.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/constants/EventTypes.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/events/constants/EventTypes.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/events/constants/EventTypes.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/http/CustomHeadersInterceptor.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/http/CustomHeadersInterceptor.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/http/CustomHeadersInterceptor.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/http/CustomHeadersInterceptor.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/location/LocationManager.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/LocationManager.java
similarity index 57%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/location/LocationManager.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/LocationManager.java
index 1489a50d9..db0201030 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/location/LocationManager.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/LocationManager.java
@@ -5,18 +5,10 @@
import android.os.Looper;
import android.util.Log;
-import com.mapbox.android.core.location.LocationEngine;
-import com.mapbox.android.core.location.LocationEngineCallback;
-
-/*
-import com.mapbox.android.core.location.LocationEngineListener;
-import com.mapbox.android.core.location.LocationEnginePriority;
-*/
-
-import com.mapbox.android.core.location.LocationEngineProvider;
-import com.mapbox.android.core.location.LocationEngineRequest;
-import com.mapbox.android.core.location.LocationEngineResult;
-import com.mapbox.android.core.permissions.PermissionsManager;
+import com.mapbox.rctmgl.impl.LocationManagerImpl;
+import com.mapbox.rctmgl.impl.LocationEngineCallbackImpl;
+import com.mapbox.rctmgl.impl.LocationEngineResultImpl;
+import com.mapbox.rctmgl.impl.PermissionsManagerImpl;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -28,13 +20,13 @@
*/
@SuppressWarnings({"MissingPermission"})
-public class LocationManager implements LocationEngineCallback {
+public class LocationManager extends LocationEngineCallbackImpl {
static final long DEFAULT_FASTEST_INTERVAL_MILLIS = 1000;
static final long DEFAULT_INTERVAL_MILLIS = 1000;
- public static final String LOG_TAG = LocationManager.class.getSimpleName();
+ public static final String LOG_TAG = "LocationManager";
- private LocationEngine locationEngine;
+ LocationManagerImpl locationManagerImpl;
private Context context;
private List listeners = new ArrayList<>();
@@ -42,7 +34,6 @@ public class LocationManager implements LocationEngineCallback INSTANCE = null;
@@ -63,12 +54,7 @@ private LocationManager(Context context) {
}
private void buildEngineRequest() {
- locationEngine = LocationEngineProvider.getBestLocationEngine(this.context.getApplicationContext());
- locationEngineRequest = new LocationEngineRequest.Builder(DEFAULT_INTERVAL_MILLIS)
- .setFastestInterval(DEFAULT_FASTEST_INTERVAL_MILLIS)
- .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
- .setDisplacement(mMinDisplacement)
- .build();
+ locationManagerImpl = LocationManagerImpl.buildEngineRequest(this.context.getApplicationContext(), DEFAULT_INTERVAL_MILLIS, DEFAULT_FASTEST_INTERVAL_MILLIS, mMinDisplacement);
}
public void addLocationListener(OnUserLocationChange listener) {
@@ -86,58 +72,51 @@ public void setMinDisplacement(float minDisplacement) {
mMinDisplacement = minDisplacement;
}
public void enable() {
- if (!PermissionsManager.areLocationPermissionsGranted(context)) {
+ if (!PermissionsManagerImpl.areLocationPermissionsGranted(context)) {
return;
}
// remove existing listeners
- locationEngine.removeLocationUpdates(this);
+ locationManagerImpl.removeExistingListeners(this);
// refresh location engine request with new values
this.buildEngineRequest();
// add new listeners
- locationEngine.requestLocationUpdates(
- locationEngineRequest,
- this,
- Looper.getMainLooper()
- );
+ locationManagerImpl.addNewListeners(this);
isActive = true;
}
public void disable() {
- locationEngine.removeLocationUpdates(this);
+ locationManagerImpl.removeExistingListeners(this);
isActive = false;
}
public void dispose() {
- if (locationEngine == null) {
- return;
- }
- disable();
- locationEngine.removeLocationUpdates(this);
+ locationManagerImpl.dispose(this);
+ isActive = false;
}
public boolean isActive() {
- return locationEngine != null && this.isActive;
+ return locationManagerImpl.isActive() && this.isActive;
}
public Location getLastKnownLocation() {
- if (locationEngine == null) {
+ if (! locationManagerImpl.isActive()) {
return null;
}
return lastLocation;
}
- public void getLastKnownLocation(LocationEngineCallback callback) {
- if (locationEngine == null) {
+ public void getLastKnownLocation(LocationEngineCallbackImpl callback) {
+ if (! locationManagerImpl.isActive()) {
callback.onFailure(new Exception("LocationEngine not initialized"));
}
try {
- locationEngine.getLastLocation(callback);
+ locationManagerImpl.getLastLocation(callback);
}
catch(Exception exception) {
Log.w(LOG_TAG, exception);
@@ -145,8 +124,8 @@ public void getLastKnownLocation(LocationEngineCallback ca
}
}
- public LocationEngine getEngine() {
- return locationEngine;
+ public LocationManagerImpl getEngine() {
+ return locationManagerImpl;
}
public void onLocationChanged(Location location) {
@@ -162,7 +141,7 @@ public void onFailure(Exception exception) {
}
@Override
- public void onSuccess(LocationEngineResult result) {
+ public void onSuccess(LocationEngineResultImpl result) {
onLocationChanged(result.getLastLocation());
}
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/location/UserLocation.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/UserLocation.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/location/UserLocation.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/UserLocation.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/location/UserLocationVerticalAlignment.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/UserLocationVerticalAlignment.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/location/UserLocationVerticalAlignment.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/UserLocationVerticalAlignment.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/location/UserTrackingMode.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/UserTrackingMode.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/location/UserTrackingMode.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/UserTrackingMode.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/location/UserTrackingState.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/UserTrackingState.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/location/UserTrackingState.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/location/UserTrackingState.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLLocationModule.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLLocationModule.java
similarity index 76%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLLocationModule.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLLocationModule.java
index 44a4d2bfd..b786aeae5 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLLocationModule.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLLocationModule.java
@@ -10,8 +10,10 @@
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.RCTNativeAppEventEmitter;
-import com.mapbox.android.core.location.LocationEngineCallback;
-import com.mapbox.android.core.location.LocationEngineResult;
+
+import com.mapbox.rctmgl.impl.LocationEngineCallbackImpl;
+import com.mapbox.rctmgl.impl.LocationEngineResultImpl;
+
import com.mapbox.rctmgl.events.EventEmitter;
import com.mapbox.rctmgl.events.IEvent;
import com.mapbox.rctmgl.events.LocationEvent;
@@ -43,7 +45,7 @@ public void onHostPause() {
@Override
public void onHostDestroy() {
- startLocationManager();
+ stopLocationManager();
}
};
@@ -92,6 +94,11 @@ public void setMinDisplacement(float minDisplacement) {
}
}
+ @ReactMethod
+ public void setRequestsAlwaysUse(boolean requestsAlwaysUse) {
+ // IOS only. Ignored on Android.
+ }
+
@ReactMethod
public void stop() {
stopLocationManager();
@@ -104,22 +111,30 @@ public void pause() {
@ReactMethod
public void getLastKnownLocation(final Promise promise) {
- locationManager.getLastKnownLocation(
- new LocationEngineCallback() {
- public void onSuccess(LocationEngineResult result) {
- Location location = result.getLastLocation();
- if (result.getLastLocation() != null) {
- LocationEvent locationEvent = new LocationEvent(location);
- promise.resolve(locationEvent.getPayload());
- } else {
- promise.resolve(null);
- }
- }
- public void onFailure(@NonNull Exception exception) {
- promise.reject(exception);
- }
- }
- );
+ locationManager.getLastKnownLocation(new LocationEngineCallbackImpl() {
+ public void onSuccess(LocationEngineResultImpl result){
+ Location location = result.getLastLocation();
+ if (result.getLastLocation() != null) {
+ LocationEvent locationEvent = new LocationEvent(location);
+ promise.resolve(locationEvent.getPayload());
+ } else {
+ promise.resolve(null);
+ }
+ }
+ public void onFailure(@NonNull Exception exception) {
+ promise.reject(exception);
+ }
+ });
+ }
+
+ @ReactMethod
+ public void addListener(String eventName) {
+ // Set up any upstream listeners or background tasks as necessary
+ }
+
+ @ReactMethod
+ public void removeListeners(Integer count) {
+ // Remove upstream listeners, stop unnecessary background tasks
}
private void startLocationManager() {
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLLogging.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLLogging.java
similarity index 93%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLLogging.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLLogging.java
index 6eecc7b17..dbf2ee751 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLLogging.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLLogging.java
@@ -116,6 +116,16 @@ public void setLogLevel(String level) {
Logger.setVerbosity(logLevel);
}
+ @ReactMethod
+ public void addListener(String eventName) {
+ // Set up any upstream listeners or background tasks as necessary
+ }
+
+ @ReactMethod
+ public void removeListeners(Integer count) {
+ // Remove upstream listeners, stop unnecessary background tasks
+ }
+
public void onLog(String level, String tag, String msg, Throwable tr) {
WritableMap event = Arguments.createMap();
event.putString("message", msg);
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLModule.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLModule.java
similarity index 90%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLModule.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLModule.java
index 6a58d304b..98cf1d1af 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLModule.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLModule.java
@@ -10,9 +10,9 @@
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.module.annotations.ReactModule;
-import com.mapbox.mapboxsdk.maps.TelemetryDefinition;
+import com.mapbox.rctmgl.impl.TelemetryImpl;
+import com.mapbox.rctmgl.impl.InstanceManagerImpl;
import com.mapbox.mapboxsdk.Mapbox;
-// import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.rctmgl.components.camera.constants.CameraMode;
import com.mapbox.rctmgl.components.styles.RCTMGLStyleValue;
@@ -61,14 +61,14 @@ public String getName() {
public Map getConstants() {
// map style urls
Map styleURLS = new HashMap<>();
- styleURLS.put("Street", Style.MAPBOX_STREETS);
- styleURLS.put("Dark", Style.DARK);
- styleURLS.put("Light", Style.LIGHT);
- styleURLS.put("Outdoors", Style.OUTDOORS);
- styleURLS.put("Satellite", Style.SATELLITE);
- styleURLS.put("SatelliteStreet", Style.SATELLITE_STREETS);
- styleURLS.put("TrafficDay", Style.TRAFFIC_DAY);
- styleURLS.put("TrafficNight", Style.TRAFFIC_NIGHT);
+ styleURLS.put("Street", "mapbox://styles/mapbox/streets-v11");
+ styleURLS.put("Dark", "mapbox://styles/mapbox/dark-v10");
+ styleURLS.put("Light", "mapbox://styles/mapbox/light-v10");
+ styleURLS.put("Outdoors", "mapbox://styles/mapbox/outdoors-v1");
+ styleURLS.put("Satellite", "mapbox://styles/mapbox/satellite-v9");
+ styleURLS.put("SatelliteStreet", "mapbox://styles/mapbox/satellite-streets-v11");
+ styleURLS.put("TrafficDay", "mapbox://styles/mapbox/navigation-preview-day-v4");
+ styleURLS.put("TrafficNight", "mapbox://styles/mapbox/navigation-preview-night-v4");
// events
Map eventTypes = new HashMap<>();
@@ -106,6 +106,7 @@ public Map getConstants() {
Map cameraModes = new HashMap<>();
cameraModes.put("Flight", CameraMode.FLIGHT);
cameraModes.put("Ease", CameraMode.EASE);
+ cameraModes.put("Linear", CameraMode.LINEAR);
cameraModes.put("None", CameraMode.NONE);
// style source constants
@@ -248,7 +249,16 @@ public Map getConstants() {
Map locationModuleCallbackNames = new HashMap<>();
locationModuleCallbackNames.put("Update", RCTMGLLocationModule.LOCATION_UPDATE);
+ // tileServer
+ Map tileServers = InstanceManagerImpl.getTileServers();
+
+ // implementation
+ Map implementation = new HashMap<>();
+ implementation.put("Library", InstanceManagerImpl.getLibraryName());
+
return MapBuilder.builder()
+ .put("TileServers", tileServers)
+ .put("Implementation", implementation)
.put("StyleURL", styleURLS)
.put("EventTypes", eventTypes)
.put("UserTrackingModes", userTrackingModes)
@@ -284,11 +294,17 @@ public Map getConstants() {
}
@ReactMethod
- public void setAccessToken(final String accessToken) {
+ public void setWellKnownTileServer(final String tileServer) {
+ InstanceManagerImpl.setWellKnownTileServer(tileServer);
+ }
+
+ @ReactMethod
+ public void setAccessToken(final String accessToken, Promise promise) {
mReactContext.runOnUiQueueThread(new Runnable() {
@Override
public void run() {
- Mapbox.getInstance(getReactApplicationContext(), accessToken);
+ InstanceManagerImpl.getInstance(getReactApplicationContext(), accessToken);
+ promise.resolve(accessToken);
}
});
}
@@ -323,7 +339,7 @@ public void run() {
@ReactMethod
public void getAccessToken(Promise promise) {
- String token = Mapbox.getAccessToken();
+ String token = InstanceManagerImpl.getAccessToken();
if(token == null) {
promise.reject("missing_access_token", "No access token has been set");
} else {
@@ -336,8 +352,7 @@ public void setTelemetryEnabled(final boolean telemetryEnabled) {
mReactContext.runOnUiQueueThread(new Runnable() {
@Override
public void run() {
- TelemetryDefinition telemetry = Mapbox.getTelemetry();
- telemetry.setUserTelemetryRequestState(telemetryEnabled);
+ TelemetryImpl.setUserTelemetryRequestState(telemetryEnabled);
}
});
}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLOfflineModule.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLOfflineModule.java
similarity index 98%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLOfflineModule.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLOfflineModule.java
index 6d9d2b7ec..8f480cc3e 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLOfflineModule.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLOfflineModule.java
@@ -54,7 +54,7 @@ public class RCTMGLOfflineModule extends ReactContextBaseJavaModule {
public static final String OFFLINE_ERROR = "MapboxOfflineRegionError";
public static final String OFFLINE_PROGRESS = "MapboxOfflineRegionProgress";
- public static final String DEFAULT_STYLE_URL = Style.MAPBOX_STREETS;
+ public static final String DEFAULT_STYLE_URL = "mapbox://styles/mapbox/streets-v11";
public static final Double DEFAULT_MIN_ZOOM_LEVEL = 10.0;
public static final Double DEFAULT_MAX_ZOOM_LEVEL = 20.0;
@@ -71,6 +71,16 @@ public String getName () {
return REACT_CLASS;
}
+ @ReactMethod
+ public void addListener(String eventName) {
+ // Set up any upstream listeners or background tasks as necessary
+ }
+
+ @ReactMethod
+ public void removeListeners(Integer count) {
+ // Remove upstream listeners, stop unnecessary background tasks
+ }
+
@ReactMethod
public void createPack(ReadableMap options, final Promise promise) {
final String name = ConvertUtils.getString("name", options, "");
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLSnapshotModule.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLSnapshotModule.java
similarity index 98%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLSnapshotModule.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLSnapshotModule.java
index 54bd8f668..a9208d35b 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/modules/RCTMGLSnapshotModule.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/modules/RCTMGLSnapshotModule.java
@@ -107,7 +107,7 @@ private MapSnapshotter.Options getOptions(ReadableMap jsOptions) {
options.withLogo(jsOptions.getBoolean("withLogo"));
options.withStyle(jsOptions.getString("styleURL"));
- options.withPixelRatio(Float.valueOf(mContext.getResources().getDisplayMetrics().scaledDensity).intValue());
+ options.withPixelRatio(Float.valueOf(mContext.getResources().getDisplayMetrics().density).intValue());
if (jsOptions.hasKey("bounds")) {
FeatureCollection bounds = FeatureCollection.fromJson(jsOptions.getString("bounds"));
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/BitmapUtils.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/BitmapUtils.java
similarity index 98%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/BitmapUtils.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/BitmapUtils.java
index ef2e77212..5551bd1e6 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/BitmapUtils.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/BitmapUtils.java
@@ -25,7 +25,7 @@
*/
public class BitmapUtils {
- public static final String LOG_TAG = BitmapUtils.class.getSimpleName();
+ public static final String LOG_TAG = "BitmapUtils";
private static int CACHE_SIZE = 1024 * 1024;
private static LruCache mCache = new LruCache(CACHE_SIZE) {
diff --git a/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ClusterPropertyEntry.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ClusterPropertyEntry.java
new file mode 100644
index 000000000..d333d03d7
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ClusterPropertyEntry.java
@@ -0,0 +1,13 @@
+package com.mapbox.rctmgl.utils;
+
+import com.mapbox.mapboxsdk.style.expressions.Expression;
+
+public class ClusterPropertyEntry {
+ public Expression operator;
+ public Expression mapping;
+
+ public ClusterPropertyEntry(Expression _operator, Expression _mapping) {
+ operator = _operator;
+ mapping = _mapping;
+ }
+}
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/ConvertUtils.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ConvertUtils.java
similarity index 99%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/ConvertUtils.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ConvertUtils.java
index 4014f5d1a..3c739dd5c 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/ConvertUtils.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ConvertUtils.java
@@ -28,7 +28,7 @@
*/
public class ConvertUtils {
- public static final String LOG_TAG = ConvertUtils.class.getSimpleName();
+ public static final String LOG_TAG = "ConvertUtils";
public static JsonObject toJsonObject(ReadableMap map) {
if (map == null) return null;
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/DownloadMapImageTask.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/DownloadMapImageTask.java
similarity index 98%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/DownloadMapImageTask.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/DownloadMapImageTask.java
index 097d45e32..c13fae5bc 100644
--- a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/DownloadMapImageTask.java
+++ b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/DownloadMapImageTask.java
@@ -38,7 +38,7 @@
*/
public class DownloadMapImageTask extends AsyncTask, Void, List>> {
- public static final String LOG_TAG = DownloadMapImageTask.class.getSimpleName();
+ public static final String LOG_TAG = "DownloadMapImageTask";
private WeakReference mContext;
private WeakReference mMap;
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/ExpressionParser.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ExpressionParser.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/ExpressionParser.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ExpressionParser.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/GeoJSONUtils.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/GeoJSONUtils.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/GeoJSONUtils.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/GeoJSONUtils.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/GeoViewport.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/GeoViewport.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/GeoViewport.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/GeoViewport.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/ImageEntry.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ImageEntry.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/ImageEntry.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ImageEntry.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/ResourceUtils.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ResourceUtils.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/ResourceUtils.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/ResourceUtils.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/SimpleEventCallback.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/SimpleEventCallback.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/SimpleEventCallback.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/SimpleEventCallback.java
diff --git a/android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/SphericalMercator.java b/android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/SphericalMercator.java
similarity index 100%
rename from android/rctmgl/src/main/java/com/mapbox/rctmgl/utils/SphericalMercator.java
rename to android/rctmgl/src/main/java-mapboxgl/common/com/mapbox/rctmgl/utils/SphericalMercator.java
diff --git a/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/InstanceManagerImpl.java b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/InstanceManagerImpl.java
new file mode 100644
index 000000000..9df95b99e
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/InstanceManagerImpl.java
@@ -0,0 +1,35 @@
+package com.mapbox.rctmgl.impl;
+
+import android.content.Context;
+import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.log.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class InstanceManagerImpl {
+ public static void getInstance(Context context, String accessToken) {
+ Mapbox.getInstance(context, accessToken);
+ }
+
+ public static void setWellKnownTileServer(String wellKnownTileServer) {
+ if (wellKnownTileServer != "mapbox") {
+ Logger.w("InstanceManagerImpl", "setWellKnownTileServer: only mapbox is supported");
+ return;
+ }
+ }
+
+ public static String getAccessToken() {
+ return Mapbox.getAccessToken();
+ }
+
+ public static String getLibraryName() {
+ return "mapbox-gl";
+ }
+
+ public static Map getTileServers() {
+ HashMap result = new HashMap();
+ result.put("Mapbox", "mapbox");
+ return result;
+ }
+}
diff --git a/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/LocationEngineCallbackImpl.java b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/LocationEngineCallbackImpl.java
new file mode 100644
index 000000000..6ceca46bd
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/LocationEngineCallbackImpl.java
@@ -0,0 +1,12 @@
+package com.mapbox.rctmgl.impl;
+
+import com.mapbox.android.core.location.LocationEngineCallback;
+import com.mapbox.android.core.location.LocationEngineResult;
+
+public abstract class LocationEngineCallbackImpl implements LocationEngineCallback {
+ public void onSuccess(LocationEngineResult result) {
+ onSuccess(new LocationEngineResultImpl(result));
+ }
+
+ abstract public void onSuccess(LocationEngineResultImpl result);
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/LocationEngineResultImpl.java b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/LocationEngineResultImpl.java
new file mode 100644
index 000000000..8d7101022
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/LocationEngineResultImpl.java
@@ -0,0 +1,18 @@
+package com.mapbox.rctmgl.impl;
+
+import android.location.Location;
+
+import com.mapbox.android.core.location.LocationEngineCallback;
+import com.mapbox.android.core.location.LocationEngineResult;
+
+public class LocationEngineResultImpl {
+ LocationEngineResult impl;
+
+ LocationEngineResultImpl(LocationEngineResult impl) {
+ this.impl = impl;
+ }
+
+ public Location getLastLocation() {
+ return impl.getLastLocation();
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/LocationManagerImpl.java b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/LocationManagerImpl.java
new file mode 100644
index 000000000..e887b3358
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/LocationManagerImpl.java
@@ -0,0 +1,64 @@
+package com.mapbox.rctmgl.impl;
+
+import android.content.Context;
+
+import android.os.Looper;
+
+import com.mapbox.android.core.location.LocationEngine;
+import com.mapbox.android.core.location.LocationEngineCallback;
+import com.mapbox.android.core.location.LocationEngineProvider;
+import com.mapbox.android.core.location.LocationEngineRequest;
+import com.mapbox.android.core.location.LocationEngineResult;
+import com.mapbox.android.core.permissions.PermissionsManager;
+
+public class LocationManagerImpl {
+ LocationEngine locationEngine;
+ LocationEngineRequest locationEngineRequest;
+
+ LocationManagerImpl(LocationEngine locationEngine, LocationEngineRequest locationEngineRequest) {
+ this.locationEngine = locationEngine;
+ this.locationEngineRequest = locationEngineRequest;
+ }
+
+ public static LocationManagerImpl buildEngineRequest(Context context, long default_interval, long fastest_interval, float minDisplacement) {
+ return new LocationManagerImpl(
+ LocationEngineProvider.getBestLocationEngine(context),
+ new LocationEngineRequest.Builder(default_interval)
+ .setFastestInterval(fastest_interval)
+ .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
+ .setDisplacement(minDisplacement)
+ .build()
+ );
+ }
+
+ public void removeExistingListeners(LocationEngineCallbackImpl callback) {
+ locationEngine.removeLocationUpdates(callback);
+ }
+
+ public void addNewListeners(LocationEngineCallbackImpl callback) {
+ locationEngine.requestLocationUpdates(
+ locationEngineRequest,
+ callback,
+ Looper.getMainLooper()
+ );
+ }
+
+ public void dispose(LocationEngineCallbackImpl callback) {
+ if (locationEngine == null) {
+ return;
+ }
+ locationEngine.removeLocationUpdates(callback);
+ }
+
+ public boolean isActive() {
+ return (locationEngine != null);
+ }
+
+ public void getLastLocation(LocationEngineCallbackImpl callback) {
+ locationEngine.getLastLocation(callback);
+ }
+
+ public LocationEngine getEngine() {
+ return locationEngine;
+ }
+}
diff --git a/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/PermissionsManagerImpl.java b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/PermissionsManagerImpl.java
new file mode 100644
index 000000000..d7351a29b
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/PermissionsManagerImpl.java
@@ -0,0 +1,10 @@
+package com.mapbox.rctmgl.impl;
+
+import android.content.Context;
+import com.mapbox.android.core.permissions.PermissionsManager;
+
+public class PermissionsManagerImpl {
+ public static boolean areLocationPermissionsGranted(Context context) {
+ return PermissionsManager.areLocationPermissionsGranted(context);
+ }
+}
diff --git a/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/SymbolClickListenerImpl.java b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/SymbolClickListenerImpl.java
new file mode 100644
index 000000000..6d97d232d
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/SymbolClickListenerImpl.java
@@ -0,0 +1,18 @@
+package com.mapbox.rctmgl.impl;
+
+import com.mapbox.mapboxsdk.plugins.annotation.OnSymbolClickListener;
+import com.mapbox.mapboxsdk.plugins.annotation.Symbol;
+
+
+public class SymbolClickListenerImpl {
+ public static interface Listener {
+ public boolean onAnnotationClick(Symbol symbol);
+ }
+
+ public static OnSymbolClickListener annotationClickListener(Listener listener) {
+ return new OnSymbolClickListener() {
+ @Override
+ public void onAnnotationClick(Symbol symbol) { listener.onAnnotationClick(symbol); }
+ };
+ }
+}
diff --git a/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/TelemetryImpl.java b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/TelemetryImpl.java
new file mode 100644
index 000000000..efcccc1a2
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/mapbox/com/mapbox/rctmgl/impl/TelemetryImpl.java
@@ -0,0 +1,11 @@
+package com.mapbox.rctmgl.impl;
+
+import com.mapbox.mapboxsdk.maps.TelemetryDefinition;
+import com.mapbox.mapboxsdk.Mapbox;
+
+public class TelemetryImpl {
+ static public void setUserTelemetryRequestState(final boolean telemetryEnabled) {
+ TelemetryDefinition telemetry = Mapbox.getTelemetry();
+ telemetry.setUserTelemetryRequestState(telemetryEnabled);
+ }
+}
diff --git a/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/InstanceManagerImpl.java b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/InstanceManagerImpl.java
new file mode 100644
index 000000000..866405dab
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/InstanceManagerImpl.java
@@ -0,0 +1,42 @@
+package com.mapbox.rctmgl.impl;
+
+import android.content.Context;
+
+import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.WellKnownTileServer;
+import com.mapbox.mapboxsdk.log.Logger;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class InstanceManagerImpl {
+ public static void getInstance(Context context, String accessToken) {
+ if (wellKnownTileServer == null) {
+ Logger.w("InstanceManagerImpl", "setAccessToken requires setWellKnownTileServer for MapLibre, see setWellKnownTileServer docs for implications");
+ wellKnownTileServer = WellKnownTileServer.MapLibre.name();
+ }
+ Mapbox.getInstance(context, accessToken, WellKnownTileServer.valueOf(wellKnownTileServer) );
+ }
+
+ public static Map getTileServers() {
+ HashMap result = new HashMap();
+ result.put("Mapbox", WellKnownTileServer.Mapbox.name());
+ result.put("MapLibre", WellKnownTileServer.MapLibre.name());
+ result.put("MapTiler", WellKnownTileServer.MapTiler.name());
+ return result;
+ }
+
+ static String wellKnownTileServer = null;
+
+ public static void setWellKnownTileServer(String wellKnownTileServer) {
+ InstanceManagerImpl.wellKnownTileServer = wellKnownTileServer;
+ }
+
+ public static String getAccessToken() {
+ return Mapbox.getApiKey();
+ }
+
+ public static String getLibraryName() {
+ return "maplibre";
+ }
+}
diff --git a/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/LocationEngineCallbackImpl.java b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/LocationEngineCallbackImpl.java
new file mode 100644
index 000000000..ca2fc6cc0
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/LocationEngineCallbackImpl.java
@@ -0,0 +1,12 @@
+package com.mapbox.rctmgl.impl;
+
+import com.mapbox.mapboxsdk.location.engine.LocationEngineCallback;
+import com.mapbox.mapboxsdk.location.engine.LocationEngineResult;
+
+public abstract class LocationEngineCallbackImpl implements LocationEngineCallback {
+ public void onSuccess(LocationEngineResult result) {
+ onSuccess(new LocationEngineResultImpl(result));
+ }
+
+ abstract public void onSuccess(LocationEngineResultImpl result);
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/LocationEngineResultImpl.java b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/LocationEngineResultImpl.java
new file mode 100644
index 000000000..1222f4812
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/LocationEngineResultImpl.java
@@ -0,0 +1,18 @@
+package com.mapbox.rctmgl.impl;
+
+import android.location.Location;
+
+import com.mapbox.mapboxsdk.location.engine.LocationEngineCallback;
+import com.mapbox.mapboxsdk.location.engine.LocationEngineResult;
+
+public class LocationEngineResultImpl {
+ LocationEngineResult impl;
+
+ LocationEngineResultImpl(LocationEngineResult impl) {
+ this.impl = impl;
+ }
+
+ public Location getLastLocation() {
+ return impl.getLastLocation();
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/LocationManagerImpl.java b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/LocationManagerImpl.java
new file mode 100644
index 000000000..306fb98f0
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/LocationManagerImpl.java
@@ -0,0 +1,64 @@
+package com.mapbox.rctmgl.impl;
+
+import android.content.Context;
+
+import android.os.Looper;
+
+import com.mapbox.mapboxsdk.location.engine.LocationEngine;
+import com.mapbox.mapboxsdk.location.engine.LocationEngineProvider;
+import com.mapbox.mapboxsdk.location.engine.LocationEngineResult;
+import com.mapbox.mapboxsdk.location.engine.LocationEngineCallback;
+import com.mapbox.mapboxsdk.location.engine.LocationEngineRequest;
+import com.mapbox.mapboxsdk.location.permissions.PermissionsManager;
+
+public class LocationManagerImpl {
+ LocationEngine locationEngine;
+ LocationEngineRequest locationEngineRequest;
+
+ LocationManagerImpl(LocationEngine locationEngine, LocationEngineRequest locationEngineRequest) {
+ this.locationEngine = locationEngine;
+ this.locationEngineRequest = locationEngineRequest;
+ }
+
+ public static LocationManagerImpl buildEngineRequest(Context context, long default_interval, long fastest_interval, float minDisplacement) {
+ return new LocationManagerImpl(
+ LocationEngineProvider.getBestLocationEngine(context),
+ new LocationEngineRequest.Builder(default_interval)
+ .setFastestInterval(fastest_interval)
+ .setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
+ .setDisplacement(minDisplacement)
+ .build()
+ );
+ }
+
+ public void removeExistingListeners(LocationEngineCallbackImpl callback) {
+ locationEngine.removeLocationUpdates(callback);
+ }
+
+ public void addNewListeners(LocationEngineCallbackImpl callback) {
+ locationEngine.requestLocationUpdates(
+ locationEngineRequest,
+ callback,
+ Looper.getMainLooper()
+ );
+ }
+
+ public void dispose(LocationEngineCallbackImpl callback) {
+ if (locationEngine == null) {
+ return;
+ }
+ locationEngine.removeLocationUpdates(callback);
+ }
+
+ public boolean isActive() {
+ return (locationEngine != null);
+ }
+
+ public void getLastLocation(LocationEngineCallbackImpl callback) {
+ locationEngine.getLastLocation(callback);
+ }
+
+ public LocationEngine getEngine() {
+ return locationEngine;
+ }
+}
diff --git a/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/PermissionsManagerImpl.java b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/PermissionsManagerImpl.java
new file mode 100644
index 000000000..f607203c1
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/PermissionsManagerImpl.java
@@ -0,0 +1,10 @@
+package com.mapbox.rctmgl.impl;
+
+import android.content.Context;
+import com.mapbox.mapboxsdk.location.permissions.PermissionsManager;
+
+public class PermissionsManagerImpl {
+ public static boolean areLocationPermissionsGranted(Context context) {
+ return PermissionsManager.areLocationPermissionsGranted(context);
+ }
+}
diff --git a/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/SymbolClickListenerImpl.java b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/SymbolClickListenerImpl.java
new file mode 100644
index 000000000..ace800578
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/SymbolClickListenerImpl.java
@@ -0,0 +1,18 @@
+package com.mapbox.rctmgl.impl;
+
+import com.mapbox.mapboxsdk.plugins.annotation.OnSymbolClickListener;
+import com.mapbox.mapboxsdk.plugins.annotation.Symbol;
+
+
+public class SymbolClickListenerImpl {
+ public static interface Listener {
+ public boolean onAnnotationClick(Symbol symbol);
+ }
+
+ public static OnSymbolClickListener annotationClickListener(Listener listener) {
+ return new OnSymbolClickListener() {
+ @Override
+ public boolean onAnnotationClick(Symbol symbol) { return listener.onAnnotationClick(symbol); }
+ };
+ }
+}
diff --git a/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/TelemetryImpl.java b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/TelemetryImpl.java
new file mode 100644
index 000000000..56d148656
--- /dev/null
+++ b/android/rctmgl/src/main/java-mapboxgl/maplibre/com/mapbox/rctmgl/impl/TelemetryImpl.java
@@ -0,0 +1,7 @@
+package com.mapbox.rctmgl.impl;
+
+public class TelemetryImpl {
+ public static void setUserTelemetryRequestState(final boolean enabled) {
+ // No-op in maplibre
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/README.md b/android/rctmgl/src/main/java-v10/README.md
new file mode 100644
index 000000000..e69de29bb
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/RCTMGLPackage.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/RCTMGLPackage.java
new file mode 100644
index 000000000..cc3418978
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/RCTMGLPackage.java
@@ -0,0 +1,118 @@
+package com.mapbox.rctmgl;
+
+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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import com.mapbox.rctmgl.components.camera.RCTMGLCameraManager;
+
+import com.mapbox.rctmgl.components.annotation.RCTMGLCalloutManager;
+import com.mapbox.rctmgl.components.annotation.RCTMGLPointAnnotationManager;
+import com.mapbox.rctmgl.components.annotation.RCTMGLMarkerViewManager;
+import com.mapbox.rctmgl.components.images.RCTMGLImageManager;
+import com.mapbox.rctmgl.components.images.RCTMGLImagesManager;
+import com.mapbox.rctmgl.components.location.RCTMGLNativeUserLocationManager;
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapViewManager;
+import com.mapbox.rctmgl.components.mapview.RCTMGLAndroidTextureMapViewManager;
+import com.mapbox.rctmgl.components.styles.atmosphere.RCTMGLAtmosphereManager;
+import com.mapbox.rctmgl.components.styles.layers.RCTMGLBackgroundLayerManager;
+import com.mapbox.rctmgl.components.styles.layers.RCTMGLCircleLayerManager;
+import com.mapbox.rctmgl.components.styles.layers.RCTMGLFillExtrusionLayerManager;
+import com.mapbox.rctmgl.components.styles.layers.RCTMGLFillLayerManager;
+import com.mapbox.rctmgl.components.styles.layers.RCTMGLHeatmapLayerManager;
+import com.mapbox.rctmgl.components.styles.layers.RCTMGLLineLayerManager;
+import com.mapbox.rctmgl.components.styles.layers.RCTMGLRasterLayerManager;
+import com.mapbox.rctmgl.components.styles.layers.RCTMGLSkyLayerManager;
+import com.mapbox.rctmgl.components.styles.layers.RCTMGLSymbolLayerManager;
+
+import com.mapbox.rctmgl.components.styles.light.RCTMGLLightManager;
+import com.mapbox.rctmgl.components.styles.terrain.RCTMGLTerrainManager;
+
+import com.mapbox.rctmgl.components.styles.sources.RCTMGLImageSourceManager;
+import com.mapbox.rctmgl.components.styles.sources.RCTMGLRasterSourceManager;
+import com.mapbox.rctmgl.components.styles.sources.RCTMGLRasterDemSourceManager;
+import com.mapbox.rctmgl.components.styles.sources.RCTMGLShapeSourceManager;
+import com.mapbox.rctmgl.components.styles.sources.RCTMGLVectorSourceManager;
+
+import com.mapbox.rctmgl.modules.RCTMGLLogging;
+
+import com.mapbox.rctmgl.modules.RCTMGLOfflineModule;
+import com.mapbox.rctmgl.modules.RCTMGLSnapshotModule;
+import com.mapbox.rctmgl.modules.RCTMGLLocationModule;
+
+import com.mapbox.rctmgl.modules.RCTMGLModule;
+
+
+public class RCTMGLPackage implements ReactPackage {
+
+ @Override
+ public List createNativeModules(ReactApplicationContext reactApplicationContext) {
+ List modules = new ArrayList<>();
+ modules.add(new RCTMGLModule(reactApplicationContext));
+ modules.add(new RCTMGLLocationModule(reactApplicationContext));
+
+ modules.add(new RCTMGLOfflineModule(reactApplicationContext));
+ modules.add(new RCTMGLSnapshotModule(reactApplicationContext));
+
+ modules.add(new RCTMGLLogging(reactApplicationContext));
+
+ return modules;
+ }
+
+ @Deprecated
+ public List> createJSModules() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactApplicationContext) {
+ List managers = new ArrayList<>();
+
+ // components
+ managers.add(new RCTMGLCameraManager(reactApplicationContext));
+ managers.add(new RCTMGLAndroidTextureMapViewManager(reactApplicationContext));
+ managers.add(new RCTMGLMapViewManager(reactApplicationContext));
+
+ // annotations
+ managers.add(new RCTMGLMarkerViewManager(reactApplicationContext));
+ managers.add(new RCTMGLPointAnnotationManager(reactApplicationContext));
+ managers.add(new RCTMGLCalloutManager());
+
+ managers.add(new RCTMGLNativeUserLocationManager());
+
+ // sources
+ managers.add(new RCTMGLVectorSourceManager(reactApplicationContext));
+ managers.add(new RCTMGLShapeSourceManager(reactApplicationContext));
+ managers.add(new RCTMGLRasterDemSourceManager(reactApplicationContext));
+ managers.add(new RCTMGLRasterSourceManager(reactApplicationContext));
+ managers.add(new RCTMGLImageSourceManager());
+
+ // images
+ managers.add(new RCTMGLImagesManager(reactApplicationContext));
+ managers.add(new RCTMGLImageManager(reactApplicationContext));
+
+ // layers
+ managers.add(new RCTMGLFillLayerManager());
+ managers.add(new RCTMGLFillExtrusionLayerManager());
+ managers.add(new RCTMGLHeatmapLayerManager());
+
+ managers.add(new RCTMGLLineLayerManager());
+ managers.add(new RCTMGLCircleLayerManager());
+ managers.add(new RCTMGLSymbolLayerManager());
+ managers.add(new RCTMGLRasterLayerManager());
+ managers.add(new RCTMGLSkyLayerManager());
+ managers.add(new RCTMGLTerrainManager());
+ managers.add(new RCTMGLAtmosphereManager());
+ managers.add(new RCTMGLBackgroundLayerManager());
+
+ managers.add(new RCTMGLLightManager());
+
+ return managers;
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEvent.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEvent.java
new file mode 100644
index 000000000..cf8082f3b
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEvent.java
@@ -0,0 +1,35 @@
+package com.mapbox.rctmgl.components;
+
+import com.facebook.react.bridge.WritableMap;
+import com.facebook.react.uimanager.events.Event;
+import com.facebook.react.uimanager.events.RCTEventEmitter;
+
+import javax.annotation.Nullable;
+
+public class AbstractEvent extends Event {
+ private String mEventName;
+ private final boolean mCanCoalesce;
+ private WritableMap mEvent;
+
+ public AbstractEvent(int viewId, String eventName, boolean canCoalesce, @Nullable WritableMap event) {
+ super(viewId);
+ mEventName = eventName;
+ mCanCoalesce = canCoalesce;
+ mEvent = event;
+ }
+
+ @Override
+ public String getEventName() {
+ return mEventName;
+ }
+
+ @Override
+ public void dispatch(RCTEventEmitter rctEventEmitter) {
+ rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEvent);
+ }
+
+ @Override
+ public boolean canCoalesce() {
+ return mCanCoalesce;
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEventEmitter.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEventEmitter.kt
new file mode 100644
index 000000000..400ff4277
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractEventEmitter.kt
@@ -0,0 +1,75 @@
+package com.mapbox.rctmgl.components
+
+import android.app.Activity
+import android.view.ViewGroup
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.common.MapBuilder
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.UIManagerModule
+import com.facebook.react.uimanager.ViewGroupManager
+import com.facebook.react.uimanager.events.EventDispatcher
+import com.mapbox.rctmgl.events.IEvent
+import javax.annotation.Nonnull
+
+/**
+ * Created by nickitaliano on 8/23/17.
+ */
+abstract class AbstractEventEmitter(reactApplicationContext: ReactApplicationContext) :
+ ViewGroupManager() {
+ private val mRateLimitedEvents: MutableMap
+ private var mEventDispatcher: EventDispatcher? = null
+ private val mRCTAppContext: ReactApplicationContext
+
+ init {
+ mRateLimitedEvents = HashMap()
+ mRCTAppContext = reactApplicationContext
+ }
+
+ val activity : Activity?
+ get() = mRCTAppContext.currentActivity
+
+ fun handleEvent(event: IEvent) {
+ val eventCacheKey = getEventCacheKey(event)
+
+ // fail safe to protect bridge from being spammed
+ if (shouldDropEvent(eventCacheKey, event)) {
+ return
+ }
+ mRateLimitedEvents[eventCacheKey] = System.currentTimeMillis()
+ mEventDispatcher!!.dispatchEvent(
+ AbstractEvent(
+ event.id,
+ event.key,
+ event.canCoalesce(),
+ event.toJSON()
+ )
+ )
+ }
+
+ override fun addEventEmitters(context: ThemedReactContext, @Nonnull view: T) {
+ mEventDispatcher = context.getNativeModule(UIManagerModule::class.java)!!.eventDispatcher
+ }
+
+ override fun getExportedCustomDirectEventTypeConstants(): Map? {
+ val events = customEvents() ?: return null
+ val exportedEvents: MutableMap = HashMap()
+ for ((key, value) in events) {
+ exportedEvents[key] = MapBuilder.of("registrationName", value)
+ }
+ return exportedEvents
+ }
+
+ abstract fun customEvents(): Map?
+ private fun shouldDropEvent(cacheKey: String, event: IEvent): Boolean {
+ val lastEventTimestamp = mRateLimitedEvents[cacheKey]
+ return lastEventTimestamp != null && event.timestamp - lastEventTimestamp <= BRIDGE_TIMEOUT_MS
+ }
+
+ private fun getEventCacheKey(event: IEvent): String {
+ return String.format("%s-%s", event.key, event.type)
+ }
+
+ companion object {
+ private const val BRIDGE_TIMEOUT_MS = 10.0
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractMapFeature.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractMapFeature.kt
new file mode 100644
index 000000000..7554a69a6
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/AbstractMapFeature.kt
@@ -0,0 +1,40 @@
+package com.mapbox.rctmgl.components
+
+import android.content.Context
+import com.facebook.react.views.view.ReactViewGroup
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+
+enum class RemovalReason {
+ VIEW_REMOVAL,
+ STYLE_CHANGE,
+ ON_DESTROY,
+ REORDER
+}
+
+abstract class AbstractMapFeature(context: Context?) : ReactViewGroup(context) {
+ protected var mMapView: RCTMGLMapView? = null;
+ private var mWithMapViewCallbacks: Array<((RCTMGLMapView) -> Unit)>? = null;
+
+ open fun addToMap(mapView: RCTMGLMapView) {
+ mMapView = mapView;
+ mWithMapViewCallbacks?.forEach { it(mapView) }
+ mWithMapViewCallbacks = null;
+ }
+
+ // return false if you don not want to remove this feature based on reason
+ open fun removeFromMap(mapView: RCTMGLMapView,reason: RemovalReason) : Boolean {
+ mMapView = null;
+ return true;
+ }
+
+ internal fun withMapView(callback: (mapView: RCTMGLMapView) -> Unit) {
+ val mapView = mMapView;
+ if (mapView == null) {
+ val callbacks = mWithMapViewCallbacks ?: arrayOf();
+ callbacks.plus(callback)
+ mWithMapViewCallbacks = callbacks
+ } else {
+ callback(mapView)
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLCallout.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLCallout.kt
new file mode 100644
index 000000000..a62f25d18
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLCallout.kt
@@ -0,0 +1,6 @@
+package com.mapbox.rctmgl.components.annotation
+
+import android.content.Context
+import com.facebook.react.views.view.ReactViewGroup
+
+class RCTMGLCallout(context: Context?) : ReactViewGroup(context)
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLCalloutManager.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLCalloutManager.java
new file mode 100644
index 000000000..f0b244387
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLCalloutManager.java
@@ -0,0 +1,18 @@
+package com.mapbox.rctmgl.components.annotation;
+
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewGroupManager;
+
+public class RCTMGLCalloutManager extends ViewGroupManager {
+ public static final String REACT_CLASS = "RCTMGLCallout";
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+
+ @Override
+ protected RCTMGLCallout createViewInstance(ThemedReactContext reactContext) {
+ return new RCTMGLCallout(reactContext);
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerView.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerView.kt
new file mode 100644
index 000000000..fbed08913
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerView.kt
@@ -0,0 +1,201 @@
+package com.mapbox.rctmgl.components.annotation
+
+import android.content.Context
+import android.os.Handler
+import android.os.Looper
+import android.util.Log
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import com.mapbox.geojson.Point
+import com.mapbox.maps.ViewAnnotationAnchor
+import com.mapbox.maps.ViewAnnotationOptions
+import com.mapbox.maps.viewannotation.viewAnnotationOptions
+import com.mapbox.rctmgl.components.AbstractMapFeature
+import com.mapbox.rctmgl.components.RemovalReason
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.utils.Logger
+import java.util.Vector
+
+private data class Vec2(val dx: Double, val dy: Double)
+
+class RCTMGLMarkerView(context: Context?, private val mManager: RCTMGLMarkerViewManager):
+ AbstractMapFeature(context),
+ View.OnLayoutChangeListener
+{
+ // region Instance variables
+ private var mView: View? = null
+ private var didAddToMap = false
+
+ private var mCoordinate: Point? = null
+ private var mAnchor: Vec2 = Vec2(0.5, 0.5)
+ private var mAllowOverlap = false
+ private var mIsSelected = false
+
+ fun setCoordinate(point: Point?) {
+ mCoordinate = point
+ update()
+ }
+
+ fun setAnchor(x: Float, y: Float) {
+ mAnchor = Vec2(x.toDouble(), y.toDouble())
+ update()
+ }
+
+ fun setAllowOverlap(allowOverlap: Boolean) {
+ mAllowOverlap = allowOverlap
+ update()
+ }
+
+ fun setIsSelected(isSelected: Boolean) {
+ mIsSelected = isSelected
+ update()
+ }
+
+ // endregion
+
+ // region View methods
+
+ override fun addView(childView: View, childPosition: Int) {
+ mView = childView
+ // Note: Do not call this method on `super`. The view is added manually.
+ }
+
+ override fun onLayoutChange(
+ v: View,
+ left: Int, top: Int, right: Int, bottom: Int,
+ oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int
+ ) {
+ addOrUpdate()
+ }
+
+ // endregion
+
+ // region AbstractMapFeature methods
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ add()
+ }
+
+ override fun removeFromMap(mapView: RCTMGLMapView, reason: RemovalReason): Boolean {
+ super.removeFromMap(mapView, reason)
+ remove(mapView)
+ return true
+ }
+
+ // endregion
+
+ // region Create, update, and remove methods
+
+ private fun addOrUpdate() {
+ if (didAddToMap) {
+ update()
+ } else {
+ add()
+ }
+ }
+
+ private fun add() {
+ if (didAddToMap) {
+ return
+ }
+
+ if (mView == null || mCoordinate == null) {
+ return
+ }
+ val view = mView!!
+
+ view.addOnLayoutChangeListener(this)
+
+ if (view.layoutParams == null && !view.isAttachedToWindow) {
+ mMapView?.offscreenAnnotationViewContainer?.addView(view)
+ mMapView?.offscreenAnnotationViewContainer?.removeView(view)
+ }
+
+ val options = getOptions()
+
+ val annotation = mMapView?.viewAnnotationManager?.addViewAnnotation(
+ view,
+ options
+ )
+ didAddToMap = true
+ }
+
+ fun update() {
+ if (!didAddToMap) {
+ return
+ }
+
+ if (mView == null || mCoordinate == null) {
+ return
+ }
+ val view = mView!!
+
+ val options = getOptions()
+
+ val annotation = mMapView?.viewAnnotationManager?.updateViewAnnotation(
+ view,
+ options
+ )
+ }
+
+ private fun remove(mapView: RCTMGLMapView) {
+ this.removeOnLayoutChangeListener(this)
+
+ mView?.let { view ->
+ val parent = view.parent
+ if (parent is ViewGroup) {
+ parent.endViewTransition(view) // https://github.com/mapbox/mapbox-maps-android/issues/1723
+ }
+ val removed = mapView.viewAnnotationManager?.removeViewAnnotation(view)
+ if (removed == false) {
+ Logger.w("RCTMGLMarkerView", "Unable to remove view")
+ }
+ didAddToMap = false
+ }
+ }
+
+ // endregion
+
+ // region Helper functions
+
+ private fun getOptions(): ViewAnnotationOptions {
+ val view = mView!!
+ val width = view.width
+ val height = view.height
+ val coordinate = mCoordinate
+
+ val offset = getOffset()
+
+ val options = viewAnnotationOptions {
+ geometry(coordinate)
+ width(width)
+ height(height)
+ allowOverlap(mAllowOverlap)
+ offsetX(offset.dx.toInt())
+ offsetY(offset.dy.toInt())
+ selected(mIsSelected)
+ }
+ return options
+ }
+
+ private fun getOffset(): Vec2 {
+ if (mView == null) {
+ return Vec2(0.0, 0.0)
+ }
+ val view = mView!!
+
+ val width = view.width
+ val height = view.height
+
+ // Create a modified offset, normalized from 0..1 to -1..1 and scaled to
+ // the view size.
+ val offsetX = (mAnchor.dx * 2 - 1) * (width / 2) * -1
+ val offsetY = (mAnchor.dy * 2 - 1) * (height / 2)
+
+ return Vec2(offsetX, offsetY)
+ }
+
+ // endregion
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewManager.kt
new file mode 100644
index 000000000..2000d1c03
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLMarkerViewManager.kt
@@ -0,0 +1,78 @@
+package com.mapbox.rctmgl.components.annotation
+
+import android.view.View
+import android.widget.FrameLayout
+import com.mapbox.rctmgl.utils.GeoJSONUtils.toPointGeometry
+import com.facebook.react.bridge.ReactApplicationContext
+import com.mapbox.rctmgl.components.AbstractEventEmitter
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.facebook.react.bridge.ReadableMap
+import com.facebook.react.common.MapBuilder
+import com.facebook.react.uimanager.ThemedReactContext
+import com.mapbox.maps.ScreenCoordinate
+import com.mapbox.maps.viewannotation.OnViewAnnotationUpdatedListener
+import com.mapbox.maps.viewannotation.ViewAnnotationManager
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+
+class RCTMGLMarkerViewManager(reactApplicationContext: ReactApplicationContext) :
+ AbstractEventEmitter(reactApplicationContext) {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ @ReactProp(name = "coordinate")
+ fun setCoordinate(markerView: RCTMGLMarkerView, geoJSONStr: String?) {
+ markerView.setCoordinate(toPointGeometry(geoJSONStr))
+ }
+
+ @ReactProp(name = "anchor")
+ fun setAnchor(markerView: RCTMGLMarkerView, map: ReadableMap) {
+ markerView.setAnchor(map.getDouble("x").toFloat(), map.getDouble("y").toFloat())
+ }
+
+ @ReactProp(name = "allowOverlap")
+ fun setAllowOverlap(markerView: RCTMGLMarkerView, allowOverlap: Boolean) {
+ markerView.setAllowOverlap(allowOverlap)
+ }
+
+ @ReactProp(name = "isSelected")
+ fun setIsSelected(markerView: RCTMGLMarkerView, isSelected: Boolean) {
+ markerView.setIsSelected(isSelected)
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLMarkerView {
+ return RCTMGLMarkerView(reactContext, this)
+ }
+
+ override fun customEvents(): Map? {
+ return MapBuilder.builder()
+ .build()
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLMarkerView"
+
+ fun markerViewContainerSizeFixer(mapView: RCTMGLMapView, viewAnnotationManager: ViewAnnotationManager) {
+ // see https://github.com/rnmapbox/maps/issues/2376
+ viewAnnotationManager.addOnViewAnnotationUpdatedListener(object :
+ OnViewAnnotationUpdatedListener {
+ override fun onViewAnnotationVisibilityUpdated(view: View, visible: Boolean) {
+ val parent = view.parent
+ if (parent is FrameLayout) {
+ if ((parent.width == 0 && parent.height == 0) && (mapView.width != 0 || mapView.height != 0)) {
+ parent.layout(0,0,mapView.width, mapView.height)
+ }
+ }
+ }
+
+ override fun onViewAnnotationPositionUpdated(
+ view: View,
+ leftTopCoordinate: ScreenCoordinate,
+ width: Int,
+ height: Int
+ ) {
+ }
+ })
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotation.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotation.kt
new file mode 100644
index 000000000..c250086bc
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotation.kt
@@ -0,0 +1,313 @@
+package com.mapbox.rctmgl.components.annotation
+
+import android.content.Context
+import android.graphics.Bitmap
+import com.mapbox.rctmgl.components.AbstractMapFeature
+import com.mapbox.maps.plugin.annotation.generated.PointAnnotation
+import com.mapbox.maps.MapboxMap
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.annotation.RCTMGLCallout
+import com.mapbox.rctmgl.utils.GeoJSONUtils
+import com.mapbox.rctmgl.events.constants.EventTypes
+import com.mapbox.maps.plugin.annotation.generated.PointAnnotationOptions
+import com.mapbox.maps.plugin.annotation.generated.PointAnnotationManager
+import com.mapbox.rctmgl.components.annotation.RCTMGLPointAnnotation
+import com.mapbox.maps.extension.style.layers.properties.generated.IconAnchor
+import com.mapbox.rctmgl.events.PointAnnotationClickEvent
+import android.graphics.PointF
+import android.view.View
+import com.mapbox.geojson.Point
+import com.mapbox.maps.ScreenCoordinate
+import com.mapbox.maps.Style
+import com.mapbox.rctmgl.components.RemovalReason
+import com.mapbox.rctmgl.events.PointAnnotationDragEvent
+import com.mapbox.rctmgl.utils.BitmapUtils
+import com.mapbox.rctmgl.utils.LatLng
+import java.util.*
+
+class RCTMGLPointAnnotation(private val mContext: Context, private val mManager: RCTMGLPointAnnotationManager) : AbstractMapFeature(mContext), View.OnLayoutChangeListener {
+ var marker: PointAnnotation? = null
+ private set
+ private var mMap: MapboxMap? = null
+ private val mHasChildren = false
+ private var mCoordinate: Point? = null
+ var iD: String? = null
+ private val mTitle: String? = null
+ private val mSnippet: String? = null
+ private var mAnchor: Array? = null
+ private val mIsSelected = false
+ private var mDraggable = false
+ private var mChildView: View? = null
+ private var mChildBitmap: Bitmap? = null
+ private var mChildBitmapId: String? = null
+ var calloutView: View? = null
+ private set
+ private var mCalloutSymbol: PointAnnotation? = null
+ private var mCalloutBitmap: Bitmap? = null
+ private var mCalloutBitmapId: String? = null
+ override fun addView(childView: View, childPosition: Int) {
+ if (childView is RCTMGLCallout) {
+ calloutView = childView
+ } else {
+ mChildView = childView
+ }
+ childView.addOnLayoutChangeListener(this)
+
+ mMapView?.offscreenAnnotationViewContainer?.addView(childView)
+ }
+
+ override fun removeView(childView: View) {
+ if (mChildView != null) {
+ mMap?.getStyle(object : Style.OnStyleLoaded {
+ override fun onStyleLoaded(style: Style) {
+ mChildBitmapId?.let { style.removeStyleImage(it) }
+ mChildView = null
+ calloutView = null
+ mChildBitmap = null
+ mChildBitmapId = null
+ updateOptions()
+ }
+ })
+ }
+ mMapView?.offscreenAnnotationViewContainer?.removeView(childView)
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ mMap = mapView.getMapboxMap()
+ makeMarker()
+ if (mChildView != null) {
+ if (!mChildView!!.isAttachedToWindow) {
+ mMapView!!.offscreenAnnotationViewContainer?.addView(mChildView)
+ }
+ addBitmapToStyle(mChildBitmap, mChildBitmapId)
+ updateOptions()
+ }
+ if (calloutView != null) {
+ if (!calloutView!!.isAttachedToWindow && mMapView != null) {
+ mMapView!!.offscreenAnnotationViewContainer?.addView(calloutView)
+ }
+ addBitmapToStyle(mCalloutBitmap, mCalloutBitmapId)
+ }
+ }
+
+ override fun removeFromMap(mapView: RCTMGLMapView, reason: RemovalReason): Boolean {
+ val map = (if (mMapView != null) mMapView else mapView) ?: return true
+ if (marker != null) {
+ map.pointAnnotationManager?.delete(marker!!)
+ }
+ if (mChildView != null) {
+ map.offscreenAnnotationViewContainer?.removeView(mChildView)
+ }
+ if (calloutView != null) {
+ map.offscreenAnnotationViewContainer?.removeView(calloutView)
+ }
+ return super.removeFromMap(mapView, reason)
+ }
+
+ override fun onLayoutChange(v: View, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int,
+ oldRight: Int, oldBottom: Int) {
+ if (left == 0 && top == 0 && right == 0 && bottom == 0) {
+ return
+ }
+ if (left != oldLeft || right != oldRight || top != oldTop || bottom != oldBottom) {
+ refreshBitmap(v, left, top, right, bottom)
+ }
+ }
+
+ private fun refreshBitmap(v: View, left: Int = v.left, top: Int = v.top, right: Int = v.right, bottom: Int = v.bottom) {
+ val bitmap = BitmapUtils.viewToBitmap(v, left, top, right, bottom)
+ val bitmapId = Integer.toString(v.id)
+ addBitmapToStyle(bitmap, bitmapId)
+ if (v is RCTMGLCallout) {
+ mCalloutBitmap = bitmap
+ mCalloutBitmapId = bitmapId
+ } else {
+ if (bitmap != null) {
+ mChildBitmap = bitmap
+ mChildBitmapId = bitmapId
+ updateOptions()
+ }
+ }
+ }
+
+ val latLng: LatLng?
+ get() = mCoordinate?.let { GeoJSONUtils.toLatLng(it) }
+ val mapboxID: Long
+ get() = if (marker == null) -1 else marker!!.id
+
+ fun setCoordinate(point: Point) {
+ mCoordinate = point
+ if (marker != null) {
+ marker!!.point = point
+ mMapView?.pointAnnotationManager?.update(marker!!)
+ }
+ if (mCalloutSymbol != null) {
+ mCalloutSymbol!!.point = point
+ mMapView?.pointAnnotationManager?.update(mCalloutSymbol!!)
+ }
+ }
+
+ fun setAnchor(x: Float, y: Float) {
+ mAnchor = arrayOf(x, y)
+ if (marker != null) {
+ updateAnchor()
+ mMapView?.pointAnnotationManager?.update(marker!!)
+ }
+ }
+
+ fun setDraggable(draggable: Boolean) {
+ mDraggable = draggable
+ if (marker != null) {
+ marker!!.isDraggable = draggable
+ mMapView?.pointAnnotationManager?.update(marker!!)
+ }
+ }
+
+ fun onSelect(shouldSendEvent: Boolean) {
+ if (calloutView != null) {
+ makeCallout()
+ }
+ if (shouldSendEvent) {
+ mManager.handleEvent(makeEvent(true))
+ }
+ }
+
+ fun onDeselect() {
+ mManager.handleEvent(makeEvent(false))
+ if (mCalloutSymbol != null) {
+ mMapView?.pointAnnotationManager?.delete(mCalloutSymbol!!)
+ }
+ }
+
+ fun onDragStart() {
+ mCoordinate = marker!!.point
+ mManager.handleEvent(makeDragEvent(EventTypes.ANNOTATION_DRAG_START))
+ }
+
+ fun onDrag() {
+ mCoordinate = marker!!.point
+ mManager.handleEvent(makeDragEvent(EventTypes.ANNOTATION_DRAG))
+ }
+
+ fun onDragEnd() {
+ mCoordinate = marker!!.point
+ mManager.handleEvent(makeDragEvent(EventTypes.ANNOTATION_DRAG_END))
+ }
+
+ fun makeMarker() {
+ val options = mCoordinate?.let {
+ PointAnnotationOptions()
+ .withPoint(it)
+ .withDraggable(mDraggable)
+ .withIconSize(1.0)
+ .withSymbolSortKey(10.0)
+ }
+ val symbolManager = mMapView?.pointAnnotationManager
+ if (symbolManager != null && options != null) {
+ marker = symbolManager.create(options)
+ updateOptions()
+ }
+ }
+
+ private fun updateOptions() {
+ if (marker != null) {
+ updateIconImage()
+ updateAnchor()
+ mMapView?.pointAnnotationManager?.update(marker!!)
+ }
+ }
+
+ private fun updateIconImage() {
+ if (mChildView != null) {
+ if (mChildBitmapId != null) {
+ marker?.iconImage = mChildBitmapId
+ }
+ } else {
+ marker?.iconImage = MARKER_IMAGE_ID
+ marker?.iconAnchor = IconAnchor.BOTTOM
+ }
+ }
+
+ private fun updateAnchor() {
+ if (mAnchor != null && mChildView != null && mChildBitmap != null && marker != null) {
+ var w = mChildBitmap!!.width
+ var h = mChildBitmap!!.height
+ val scale = resources.displayMetrics.density
+ w = (w / scale).toInt()
+ h = (h / scale).toInt()
+ marker?.iconAnchor = IconAnchor.TOP_LEFT
+ marker?.iconOffset = Arrays.asList(w.toDouble() * mAnchor!![0] * -1.0, h.toDouble() * mAnchor!![1] * -1.0)
+ }
+ }
+
+ private fun makeCallout() {
+ var yOffset = -28f
+ if (mChildView != null) {
+ if (mChildBitmap != null) {
+ val scale = resources.displayMetrics.density
+ var h = mChildBitmap!!.height / 2
+ h = (h / scale).toInt()
+ yOffset = h.toFloat() * -1
+ }
+ }
+ val options = mCoordinate?.let {
+ mCalloutBitmapId?.let { _mCalloutBitmapId ->
+ PointAnnotationOptions()
+ .withPoint(it)
+ .withIconImage(_mCalloutBitmapId)
+ .withIconSize(1.0)
+ .withIconAnchor(IconAnchor.BOTTOM)
+ .withIconOffset(Arrays.asList(0.0, yOffset.toDouble()))
+ .withSymbolSortKey(11.0)
+ .withDraggable(false)
+ }
+ }
+ val symbolManager = mMapView?.pointAnnotationManager
+ if (symbolManager != null && options != null) {
+ mCalloutSymbol = symbolManager.create(options)
+ }
+ }
+
+ private fun addBitmapToStyle(bitmap: Bitmap?, bitmapId: String?) {
+ if (mMap != null && bitmapId != null && bitmap != null) {
+ mMap!!.getStyle(object : Style.OnStyleLoaded {
+ override fun onStyleLoaded(style: Style) {
+ style.addImage(bitmapId, bitmap)
+ }
+ })
+ }
+ }
+
+ private fun makeEvent(isSelect: Boolean): PointAnnotationClickEvent {
+ val type = if (isSelect) EventTypes.ANNOTATION_SELECTED else EventTypes.ANNOTATION_DESELECTED
+ val latLng = GeoJSONUtils.toLatLng(mCoordinate!!)
+ val screenPos = getScreenPosition(latLng)
+ return PointAnnotationClickEvent(this, latLng, ScreenCoordinate(screenPos.x.toDouble(), screenPos.y.toDouble()), type)
+ }
+
+ private fun makeDragEvent(type: String): PointAnnotationDragEvent {
+ val latLng = GeoJSONUtils.toLatLng(mCoordinate!!)
+ val screenPos = getScreenPosition(latLng)
+ return PointAnnotationDragEvent(this, latLng, screenPos, type)
+ }
+
+ private val displayDensity: Float
+ private get() = mContext.resources.displayMetrics.density
+
+ private fun getScreenPosition(latLng: LatLng): PointF {
+ val screenPos = mMap!!.pixelForCoordinate(latLng.point)
+ val density = displayDensity
+ return PointF((screenPos.x / density).toFloat(), (screenPos.y / density).toFloat())
+ }
+
+ fun refresh() {
+ if (mChildView != null) {
+ refreshBitmap(mChildView!!)
+ }
+ }
+
+ companion object {
+ private const val MARKER_IMAGE_ID = "MARKER_IMAGE_ID"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotationManager.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotationManager.java
new file mode 100644
index 000000000..1250f6e88
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/annotation/RCTMGLPointAnnotationManager.java
@@ -0,0 +1,84 @@
+package com.mapbox.rctmgl.components.annotation;
+
+import androidx.annotation.Nullable;
+
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReadableArray;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.common.MapBuilder;
+import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.annotations.ReactProp;
+import com.mapbox.rctmgl.components.AbstractEventEmitter;
+import com.mapbox.rctmgl.events.constants.EventKeys;
+import com.mapbox.rctmgl.utils.GeoJSONUtils;
+
+import java.util.Map;
+
+public class RCTMGLPointAnnotationManager extends AbstractEventEmitter {
+ public static final String REACT_CLASS = "RCTMGLPointAnnotation";
+
+ public RCTMGLPointAnnotationManager(ReactApplicationContext reactApplicationContext) {
+ super(reactApplicationContext);
+ }
+
+ @Override
+ public Map customEvents() {
+ return MapBuilder.builder()
+ .put(EventKeys.POINT_ANNOTATION_SELECTED, "onMapboxPointAnnotationSelected")
+ .put(EventKeys.POINT_ANNOTATION_DESELECTED, "onMapboxPointAnnotationDeselected")
+ .put(EventKeys.POINT_ANNOTATION_DRAG_START, "onMapboxPointAnnotationDragStart")
+ .put(EventKeys.POINT_ANNOTATION_DRAG, "onMapboxPointAnnotationDrag")
+ .put(EventKeys.POINT_ANNOTATION_DRAG_END, "onMapboxPointAnnotationDragEnd")
+ .build();
+ }
+
+ //region React Methods
+ public static final int METHOD_REFRESH = 2;
+
+ @Nullable
+ @Override
+ public Map getCommandsMap() {
+ return MapBuilder.builder()
+ .put("refresh", METHOD_REFRESH)
+ .build();
+ }
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+
+ @Override
+ protected RCTMGLPointAnnotation createViewInstance(ThemedReactContext reactContext) {
+ return new RCTMGLPointAnnotation(reactContext, this);
+ }
+
+ @ReactProp(name="id")
+ public void setId(RCTMGLPointAnnotation annotation, String id) {
+ annotation.setID(id);
+ }
+
+ @ReactProp(name="coordinate")
+ public void setCoordinate(RCTMGLPointAnnotation annotation, String geoJSONStr) {
+ annotation.setCoordinate(GeoJSONUtils.toPointGeometry(geoJSONStr));
+ }
+
+ @ReactProp(name="anchor")
+ public void setAnchor(RCTMGLPointAnnotation annotation, ReadableMap map) {
+ annotation.setAnchor((float) map.getDouble("x"), (float) map.getDouble("y"));
+ }
+
+ @ReactProp(name="draggable")
+ public void setDraggable(RCTMGLPointAnnotation annotation, Boolean draggable) {
+ annotation.setDraggable(draggable);
+ }
+
+ @Override
+ public void receiveCommand(RCTMGLPointAnnotation annotation, int commandID, @Nullable ReadableArray args) {
+ switch (commandID) {
+ case METHOD_REFRESH:
+ annotation.refresh();
+ break;
+ }
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/CameraStop.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/CameraStop.kt
new file mode 100644
index 000000000..9d07bd61b
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/CameraStop.kt
@@ -0,0 +1,243 @@
+package com.mapbox.rctmgl.components.camera
+
+import android.animation.Animator
+import android.content.Context
+import com.mapbox.rctmgl.utils.GeoJSONUtils.toPointGeometry
+import com.mapbox.rctmgl.utils.GeoJSONUtils.toLatLng
+import com.mapbox.rctmgl.utils.GeoJSONUtils.toLatLngBounds
+import com.mapbox.rctmgl.utils.LatLngBounds
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.maps.CameraOptions
+import com.facebook.react.bridge.ReadableMap
+import com.mapbox.geojson.FeatureCollection
+import com.mapbox.maps.EdgeInsets
+import com.mapbox.rctmgl.components.camera.constants.CameraMode
+import com.mapbox.rctmgl.utils.LatLng
+
+class CameraStop {
+ private var mBearing: Double? = null
+ private var mTilt: Double? = null
+ private var mZoom: Double? = null
+
+ private var mLatLng: LatLng? = null
+ private var mBounds: LatLngBounds? = null
+
+ private var mPaddingLeft: Int? = null
+ private var mPaddingRight: Int? = null
+ private var mPaddingBottom: Int? = null
+ private var mPaddingTop: Int? = null
+
+ private var mMode = CameraMode.EASE
+ private var mDuration = 2000
+ private var mCallback: Animator.AnimatorListener? = null
+ fun setBearing(bearing: Double) {
+ mBearing = bearing
+ }
+
+ fun setTilt(tilt: Double) {
+ mTilt = tilt
+ }
+
+ fun setZoom(zoom: Double) {
+ mZoom = zoom
+ }
+
+ fun setLatLng(latLng: LatLng?) {
+ mLatLng = latLng
+ }
+
+ fun setDuration(duration: Int) {
+ mDuration = duration
+ }
+
+ fun setCallback(callback: Animator.AnimatorListener?) {
+ mCallback = callback
+ }
+
+ fun setPadding(
+ paddingLeft: Int?,
+ paddingRight: Int?,
+ paddingTop: Int?,
+ paddingBottom: Int?
+ ) {
+ mPaddingLeft = paddingLeft
+ mPaddingRight = paddingRight
+ mPaddingTop = paddingTop
+ mPaddingBottom = paddingBottom
+ }
+
+ fun setBounds(
+ bounds: LatLngBounds?,
+ paddingLeft: Int?,
+ paddingRight: Int?,
+ paddingTop: Int?,
+ paddingBottom: Int?
+ ) {
+ mBounds = bounds
+ this.setPadding(paddingLeft, paddingRight, paddingTop, paddingBottom)
+ }
+
+ fun setMode(@CameraMode.Mode mode: Int) {
+ mMode = mode
+ }
+
+ private fun convert(value: IntArray): EdgeInsets {
+ val left = value[0].toDouble()
+ val top = value[1].toDouble()
+ val right = value[2].toDouble()
+ val bottom = value[3].toDouble()
+ return EdgeInsets(
+ top, left, bottom, right
+ )
+ }
+
+ fun toCameraUpdate(mapView: RCTMGLMapView): CameraUpdateItem {
+ val map = mapView.getMapboxMap()
+ val currentCamera = map.cameraState
+ val builder = CameraOptions.Builder()
+ builder.center(currentCamera.center)
+ builder.bearing(currentCamera.bearing)
+
+ val currentPadding = currentCamera.padding
+
+ builder.padding(currentCamera.padding)
+ builder.zoom(currentCamera.zoom)
+ if (mBearing != null) {
+ builder.bearing(mBearing)
+ }
+ if (mTilt != null) {
+ builder.pitch(mTilt)
+ }
+
+ val paddingLeft: Int = mPaddingLeft ?: currentPadding.left.toInt()
+ val paddingTop: Int = mPaddingTop ?: currentPadding.top.toInt()
+ val paddingRight: Int = mPaddingRight ?: currentPadding.right.toInt()
+ val paddingBottom: Int = mPaddingBottom ?: currentPadding.bottom.toInt()
+ val cameraPadding = intArrayOf(paddingLeft, paddingTop, paddingRight, paddingBottom)
+ val cameraPaddingClipped = clippedPadding(cameraPadding, mapView)
+ val cameraPaddingEdgeInsets = convert(cameraPaddingClipped)
+
+ if (mLatLng != null) {
+ builder.center(mLatLng!!.point)
+ builder.padding(cameraPaddingEdgeInsets)
+ } else if (mBounds != null) {
+ val tilt = if (mTilt != null) mTilt!! else currentCamera.pitch
+ val bearing = if (mBearing != null) mBearing!! else currentCamera.bearing
+
+ val boundsCamera = map.cameraForCoordinateBounds(
+ mBounds!!.toBounds(),
+ cameraPaddingEdgeInsets,
+ bearing,
+ tilt
+ )
+
+ builder.center(boundsCamera.center)
+ builder.anchor(boundsCamera.anchor)
+ builder.zoom(boundsCamera.zoom)
+ builder.padding(boundsCamera.padding)
+ }
+
+ if (mZoom != null) {
+ builder.zoom(mZoom)
+ }
+
+ return CameraUpdateItem(map, builder.build(), mDuration, mCallback, mMode)
+ }
+
+ companion object {
+ @JvmStatic
+ fun fromReadableMap(
+ context: Context,
+ readableMap: ReadableMap,
+ callback: Animator.AnimatorListener?
+ ): CameraStop {
+ val stop = CameraStop()
+
+ if (readableMap.hasKey("pitch")) {
+ stop.setTilt(readableMap.getDouble("pitch"))
+ }
+
+ if (readableMap.hasKey("heading")) {
+ stop.setBearing(readableMap.getDouble("heading"))
+ }
+
+ if (readableMap.hasKey("centerCoordinate")) {
+ val target = toPointGeometry(readableMap.getString("centerCoordinate"))
+ stop.setLatLng(toLatLng(target!!))
+ }
+
+ if (readableMap.hasKey("zoom")) {
+ stop.setZoom(readableMap.getDouble("zoom"))
+ }
+
+ if (readableMap.hasKey("duration")) {
+ stop.setDuration(readableMap.getInt("duration"))
+ }
+
+ val metrics = context.resources.displayMetrics
+ val paddingTop = getBoundsPaddingByKey(readableMap, metrics.density, "paddingTop")
+ val paddingRight = getBoundsPaddingByKey(readableMap, metrics.density, "paddingRight")
+ val paddingBottom = getBoundsPaddingByKey(readableMap, metrics.density, "paddingBottom")
+ val paddingLeft = getBoundsPaddingByKey(readableMap, metrics.density, "paddingLeft")
+
+ if (readableMap.hasKey("bounds")) {
+ val collection = FeatureCollection.fromJson(readableMap.getString("bounds")!!)
+ stop.setBounds(
+ toLatLngBounds(collection), paddingLeft, paddingRight,
+ paddingTop, paddingBottom
+ )
+ } else {
+ stop.setPadding(paddingLeft, paddingRight, paddingTop, paddingBottom)
+ }
+
+ if (readableMap.hasKey("mode")) {
+ when (readableMap.getInt("mode")) {
+ CameraMode.FLIGHT -> stop.setMode(CameraMode.FLIGHT)
+ CameraMode.LINEAR -> stop.setMode(CameraMode.LINEAR)
+ CameraMode.NONE -> stop.setMode(CameraMode.NONE)
+ else -> stop.setMode(CameraMode.EASE)
+ }
+ }
+
+ stop.setCallback(callback)
+
+ return stop
+ }
+
+ private fun clippedPadding(padding: IntArray, mapView: RCTMGLMapView): IntArray {
+ val mapHeight = mapView.height
+ val mapWidth = mapView.width
+ val left = padding[0]
+ val top = padding[1]
+ val right = padding[2]
+ val bottom = padding[3]
+ var resultLeft = left
+ var resultTop = top
+ var resultRight = right
+ var resultBottom = bottom
+ if (top + bottom >= mapHeight) {
+ val totalPadding = (top + bottom).toDouble()
+ val extra =
+ totalPadding - mapHeight + 1.0 // add 1 to compensate for floating point math
+ resultTop -= (top * extra / totalPadding).toInt()
+ resultBottom -= (bottom * extra / totalPadding).toInt()
+ }
+ if (left + right >= mapWidth) {
+ val totalPadding = (left + right).toDouble()
+ val extra =
+ totalPadding - mapWidth + 1.0 // add 1 to compensate for floating point math
+ resultLeft -= (left * extra / totalPadding).toInt()
+ resultRight -= (right * extra / totalPadding).toInt()
+ }
+ return intArrayOf(resultLeft, resultTop, resultRight, resultBottom)
+ }
+
+ private fun getBoundsPaddingByKey(map: ReadableMap, density: Float, key: String): Int? {
+ return if (map.hasKey(key)) {
+ (map.getInt(key) * density).toInt()
+ } else {
+ null
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/CameraUpdateItem.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/CameraUpdateItem.kt
new file mode 100644
index 000000000..039b45c7c
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/CameraUpdateItem.kt
@@ -0,0 +1,135 @@
+package com.mapbox.rctmgl.components.camera
+
+import android.animation.Animator
+import com.mapbox.maps.plugin.animation.MapAnimationOptions
+import com.mapbox.maps.MapboxMap
+import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin
+import com.mapbox.rctmgl.components.camera.CameraStop
+import com.mapbox.rctmgl.components.camera.RCTMGLCamera
+import com.mapbox.maps.CameraOptions
+import android.view.animation.LinearInterpolator
+import android.view.animation.AccelerateDecelerateInterpolator
+import com.mapbox.rctmgl.components.camera.CameraUpdateQueue.OnCompleteAllListener
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.camera.CameraUpdateItem
+import com.facebook.react.bridge.ReactApplicationContext
+import com.mapbox.rctmgl.components.AbstractEventEmitter
+import com.mapbox.rctmgl.components.camera.RCTMGLCameraManager
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.facebook.react.bridge.ReadableMap
+import com.mapbox.maps.plugin.animation.MapAnimationOptions.Companion.mapAnimationOptions
+import com.mapbox.maps.plugin.animation.easeTo
+import com.mapbox.maps.plugin.animation.flyTo
+import com.mapbox.rctmgl.components.camera.constants.CameraMode
+import java.lang.ref.WeakReference
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.RunnableFuture
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
+
+class CameraUpdateItem(
+ map: MapboxMap,
+ private val mCameraUpdate: CameraOptions,
+ val duration: Int,
+ private val mCallback: Animator.AnimatorListener?,
+ @param:CameraMode.Mode private val mCameraMode: Int
+) : RunnableFuture {
+ private var isCameraActionFinished = false
+ private var isCameraActionCancelled = false
+ private val mMap: WeakReference
+
+ internal enum class CallbackMode {
+ START, END, CANCEL, REPEAT
+ }
+
+ init {
+ mMap = WeakReference(map)
+ }
+
+ override fun run() {
+ val callback: Animator.AnimatorListener = object : Animator.AnimatorListener {
+ override fun onAnimationStart(animator: Animator) {
+ isCameraActionCancelled = false
+ isCameraActionFinished = false
+ mCallback?.onAnimationStart(animator)
+ }
+
+ override fun onAnimationEnd(animator: Animator) {
+ isCameraActionCancelled = false
+ isCameraActionFinished = true
+ mCallback?.onAnimationEnd(animator)
+ }
+
+ override fun onAnimationCancel(animator: Animator) {
+ isCameraActionCancelled = true
+ isCameraActionFinished = false
+ mCallback?.onAnimationCancel(animator)
+ }
+
+ override fun onAnimationRepeat(animator: Animator) {
+ isCameraActionCancelled = false
+ isCameraActionFinished = false
+ mCallback?.onAnimationRepeat(animator)
+ }
+ }
+ val map = mMap.get()
+ if (map == null) {
+ isCameraActionCancelled = true
+ return
+ }
+ val animationOptions = MapAnimationOptions.Builder().apply {
+ animatorListener(callback)
+ }
+
+ // animateCamera / easeCamera only allows positive duration
+ if (duration == 0 || mCameraMode == CameraMode.NONE) {
+ map.flyTo(mCameraUpdate, animationOptions.apply {
+ duration(0)
+ animatorListener(callback)
+ }.build())
+ }
+
+ // On iOS a duration of -1 means default or dynamic duration (based on flight-path length)
+ // On Android we can fallback to Mapbox's default duration as there is no such API
+ if (duration > 0) {
+ animationOptions.apply { duration(duration.toLong()) }
+ }
+ if (mCameraMode == CameraMode.FLIGHT) {
+ map.flyTo(mCameraUpdate, animationOptions.build())
+ } else if (mCameraMode == CameraMode.LINEAR) {
+ map.easeTo(
+ mCameraUpdate,
+ animationOptions.apply { interpolator(LinearInterpolator()) }.build()
+ )
+ } else if (mCameraMode == CameraMode.EASE) {
+ map.easeTo(
+ mCameraUpdate,
+ animationOptions.apply{ interpolator(AccelerateDecelerateInterpolator()) }.build()
+ )
+ }
+ null
+ }
+
+ override fun cancel(mayInterruptIfRunning: Boolean): Boolean {
+ return false
+ }
+
+ override fun isCancelled(): Boolean {
+ return isCameraActionCancelled
+ }
+
+ override fun isDone(): Boolean {
+ return isCameraActionFinished
+ }
+
+ @Throws(InterruptedException::class, ExecutionException::class)
+ override fun get(): Void? {
+ return null
+ }
+
+ @Throws(InterruptedException::class, ExecutionException::class, TimeoutException::class)
+ override fun get(timeout: Long, unit: TimeUnit): Void? {
+ return null
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/CameraUpdateQueue.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/CameraUpdateQueue.kt
new file mode 100644
index 000000000..efb1b9e5f
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/CameraUpdateQueue.kt
@@ -0,0 +1,66 @@
+package com.mapbox.rctmgl.components.camera
+
+import com.mapbox.rctmgl.components.camera.CameraStop.Companion.fromReadableMap
+import com.mapbox.maps.MapboxMap
+import com.mapbox.maps.CameraOptions
+import com.mapbox.maps.plugin.animation.CameraAnimationsPlugin
+import android.view.animation.LinearInterpolator
+import android.view.animation.AccelerateDecelerateInterpolator
+import com.mapbox.rctmgl.components.camera.CameraStop
+import com.mapbox.rctmgl.components.camera.CameraUpdateQueue.OnCompleteAllListener
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.camera.CameraUpdateItem
+import com.facebook.react.bridge.ReactApplicationContext
+import com.mapbox.rctmgl.components.AbstractEventEmitter
+import com.mapbox.rctmgl.components.camera.RCTMGLCamera
+import com.mapbox.rctmgl.components.camera.RCTMGLCameraManager
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.facebook.react.bridge.ReadableMap
+import java.util.*
+
+class CameraUpdateQueue {
+ private var mQueue: Queue
+ private var mCompleteListener: OnCompleteAllListener? = null
+
+ interface OnCompleteAllListener {
+ fun onCompleteAll()
+ }
+
+ init {
+ mQueue = LinkedList()
+ }
+
+ fun offer(item: CameraStop) {
+ mQueue.offer(item)
+ }
+
+ fun size(): Int {
+ return mQueue.size
+ }
+
+ val isEmpty: Boolean
+ get() = mQueue.isEmpty()
+
+ fun flush() {
+ while (mQueue.size > 0) {
+ mQueue.remove()
+ }
+ mQueue = LinkedList()
+ }
+
+ fun setOnCompleteAllListener(listener: OnCompleteAllListener?) {
+ mCompleteListener = listener
+ }
+
+ fun execute(map: RCTMGLMapView?) {
+ if (mQueue.isEmpty()) {
+ mCompleteListener?.let { it.onCompleteAll() }
+ return
+ }
+ val stop = mQueue.poll() ?: return
+ val item = stop.toCameraUpdate(map!!)
+ item.run()
+ execute(map)
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/RCTMGLCamera.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/RCTMGLCamera.kt
new file mode 100644
index 000000000..fd8c1fe0a
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/RCTMGLCamera.kt
@@ -0,0 +1,422 @@
+package com.mapbox.rctmgl.components.camera
+
+import android.animation.Animator
+import android.content.Context
+import android.location.Location
+import com.facebook.react.bridge.ReadableMap
+import com.mapbox.maps.plugin.gestures.gestures
+import com.mapbox.rctmgl.location.LocationManager.Companion.getInstance
+import com.mapbox.maps.plugin.animation.flyTo
+import com.mapbox.rctmgl.components.AbstractMapFeature
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.location.LocationComponentManager
+import com.mapbox.rctmgl.utils.LatLngBounds
+import com.mapbox.maps.plugin.locationcomponent.OnIndicatorBearingChangedListener
+import com.mapbox.maps.plugin.locationcomponent.OnIndicatorPositionChangedListener
+import com.facebook.react.bridge.WritableMap
+import com.facebook.react.bridge.WritableNativeMap
+import com.mapbox.maps.*
+import com.mapbox.maps.plugin.PuckBearingSource
+import com.mapbox.maps.plugin.locationcomponent.location
+import com.mapbox.maps.plugin.locationcomponent.location2
+import com.mapbox.maps.plugin.viewport.ViewportStatus
+import com.mapbox.maps.plugin.viewport.ViewportStatusObserver
+import com.mapbox.maps.plugin.viewport.data.FollowPuckViewportStateBearing
+import com.mapbox.maps.plugin.viewport.data.FollowPuckViewportStateOptions
+import com.mapbox.maps.plugin.viewport.data.ViewportStatusChangeReason
+import com.mapbox.maps.plugin.viewport.viewport
+import com.mapbox.rctmgl.components.RemovalReason
+import com.mapbox.rctmgl.components.camera.constants.CameraMode
+import com.mapbox.rctmgl.components.location.*
+import com.mapbox.rctmgl.events.MapUserTrackingModeEvent
+import com.mapbox.rctmgl.location.*
+import com.mapbox.rctmgl.utils.Logger
+
+
+class RCTMGLCamera(private val mContext: Context, private val mManager: RCTMGLCameraManager) :
+ AbstractMapFeature(
+ mContext
+ ) {
+ private var hasSentFirstRegion = false
+ private var mDefaultStop: CameraStop? = null
+ private var mCameraStop: CameraStop? = null
+ private val mCameraUpdateQueue = CameraUpdateQueue()
+
+ /*
+ // private LocationComponent mLocationComponent;
+ */
+ private var mLocationComponentManager: LocationComponentManager? = null
+ private var mUserTrackingMode = 0
+ private var mUserTrackingState = UserTrackingState.POSSIBLE
+ private val mLocationManager: LocationManager?
+ private val mUserLocation: UserLocation = UserLocation()
+ private val mCenterCoordinate: ScreenCoordinate? = null
+ private val mAnimated = false
+ private val mHeading = 0.0
+
+ private var mFollowUserLocation = false
+ private var mFollowUserMode: String? = null
+ private var mFollowZoomLevel : Double? = null
+ private var mFollowPitch : Double? = null
+ private var mFollowHeading : Double? = null
+ private var mFollowPadding : EdgeInsets? = null
+
+ private var mZoomLevel = -1.0
+ private var mMinZoomLevel : Double? = null
+ private var mMaxZoomLevel : Double? = null
+ private var mMaxBounds: LatLngBounds? = null
+
+
+ private val mCameraCallback: Animator.AnimatorListener = object : Animator.AnimatorListener {
+ override fun onAnimationStart(animator: Animator) {}
+ override fun onAnimationEnd(animator: Animator) {
+ if (!hasSentFirstRegion) {
+ mMapView?.sendRegionChangeEvent(false)
+ hasSentFirstRegion = true
+ }
+ }
+
+ override fun onAnimationCancel(animator: Animator) {
+ if (!hasSentFirstRegion) {
+ mMapView?.sendRegionChangeEvent(false)
+ hasSentFirstRegion = true
+ }
+ }
+
+ override fun onAnimationRepeat(animator: Animator) {}
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ setInitialCamera()
+ updateMaxBounds()
+ mCameraStop?.let { updateCamera(it) }
+ _observeViewportState(mapView)
+ _updateViewportState()
+ }
+
+ override fun removeFromMap(mapView: RCTMGLMapView, reason: RemovalReason) : Boolean {
+ if (reason == RemovalReason.STYLE_CHANGE) {
+ return false
+ } else {
+ return super.removeFromMap(mapView, reason);
+ }
+ }
+ fun setStop(stop: CameraStop) {
+ mCameraStop = stop
+ stop.setCallback(mCameraCallback)
+ if (mMapView != null) {
+ stop.let { updateCamera(it) }
+ }
+ }
+
+ fun setDefaultStop(stop: CameraStop?) {
+ mDefaultStop = stop
+ }
+
+ fun setFollowUserMode(mode: String?) {
+ mFollowUserMode = mode
+ _updateViewportState()
+ }
+
+ fun setFollowUserLocation(value: Boolean) {
+ mFollowUserLocation = value
+ _updateViewportState()
+ }
+
+ fun setFollowZoomLevel(zoomLevel: Double) {
+ mFollowZoomLevel = zoomLevel
+ _updateViewportState();
+ }
+
+ fun setFollowPitch(pitch: Double) {
+ mFollowPitch = pitch
+ _updateViewportState();
+ }
+
+ fun setFollowHeading(heading: Double) {
+ mFollowHeading = heading
+ _updateViewportState();
+ }
+
+ fun setFollowPadding(padding: ReadableMap) {
+ // scale padding by pixel ratio
+ val metrics = context.resources.displayMetrics
+ val edgeInsets = EdgeInsets(
+ if (padding.hasKey("paddingTop")) padding.getDouble("paddingTop") * metrics.density else 0.0,
+ if (padding.hasKey("paddingLeft")) padding.getDouble("paddingLeft") * metrics.density else 0.0,
+ if (padding.hasKey("paddingBottom")) padding.getDouble("paddingBottom") * metrics.density else 0.0,
+ if (padding.hasKey("paddingRight")) padding.getDouble("paddingRight") * metrics.density else 0.0,
+ )
+
+ mFollowPadding = edgeInsets
+ _updateViewportState();
+ }
+
+ fun setMaxBounds(bounds: LatLngBounds?) {
+ mMaxBounds = bounds
+ updateMaxBounds()
+ }
+
+
+ private fun updateMaxBounds() {
+ withMapView { mapView ->
+ val map = mapView.getMapboxMap()
+ val maxBounds = mMaxBounds
+ val builder = CameraBoundsOptions.Builder()
+
+ if (maxBounds != null) {
+ builder.bounds(maxBounds.toBounds())
+ }
+ mMinZoomLevel?.let { builder.minZoom(it) }
+ mMaxZoomLevel?.let { builder.maxZoom(it) }
+ map.setBounds(builder.build())
+ }
+ }
+
+ private fun setInitialCamera() {
+ mDefaultStop?.let {
+ val mapView = mMapView!!
+ val map = mapView.getMapboxMap()
+
+ it.setDuration(0)
+ it.setMode(CameraMode.NONE)
+ val item = it.toCameraUpdate(mapView)
+ item.run()
+ }
+ }
+
+ private fun updateCamera(cameraStop: CameraStop) {
+ mCameraUpdateQueue.offer(cameraStop)
+ mCameraUpdateQueue.execute(mMapView)
+ }
+
+ private fun updateUserLocation(isAnimated: Boolean) {
+
+ }
+
+ // NOTE: The direction of this is used for map rotation only, not location layer rotation
+ private val directionForUserLocationUpdate: Double
+ private get() {
+ // NOTE: The direction of this is used for map rotation only, not location layer rotation
+ val currentCamera = mMapView!!.getMapboxMap().cameraState
+ var direction = currentCamera.bearing
+ val userTrackingMode = mUserLocation.trackingMode
+ if (userTrackingMode == UserTrackingMode.FollowWithHeading || userTrackingMode == UserTrackingMode.FollowWithCourse) {
+ direction = mUserLocation.bearing
+ } else if (mHeading != 0.0) {
+ direction = mHeading
+ }
+ return direction
+ }
+
+ private fun hasSetCenterCoordinate(): Boolean {
+ val state = mapboxMap!!.cameraState
+ val center = state.center
+ return center.latitude() != 0.0 && center.longitude() != 0.0
+ }
+
+ init {
+ mLocationManager = getInstance(mContext)
+ }
+
+ private fun updateLocationLayer(style: Style) {
+ if (mLocationComponentManager == null) {
+ mLocationComponentManager = mMapView!!.locationComponentManager
+ }
+ mLocationComponentManager!!.update()
+ }
+
+ fun setMinZoomLevel(zoomLevel: Double?) {
+ mMinZoomLevel = zoomLevel
+ updateMaxBounds()
+ }
+
+ fun setMaxZoomLevel(zoomLevel: Double?) {
+ mMaxZoomLevel = zoomLevel
+ updateMaxBounds()
+ }
+
+ fun setZoomLevel(zoomLevel: Double) {
+ mZoomLevel = zoomLevel
+ updateCameraPositionIfNeeded(false)
+ }
+
+ private fun buildCamera(
+ previousPosition: CameraState,
+ shouldUpdateTarget: Boolean
+ ): CameraOptions {
+ return if (shouldUpdateTarget) {
+ previousPosition.toCameraOptions(mCenterCoordinate)
+ } else {
+ previousPosition.toCameraOptions(null)
+ }
+ }
+
+ private fun updateCameraPositionIfNeeded(shouldUpdateTarget: Boolean) {
+ if (mMapView != null) {
+ val prevPosition = mapboxMap!!.cameraState
+ val cameraUpdate = /*CameraUpdateFactory.newCameraPosition(*/
+ buildCamera(prevPosition, shouldUpdateTarget)
+ if (mAnimated) {
+ mapboxMap!!.flyTo(cameraUpdate, null)
+ } else {
+ mapboxMap!!.setCamera(cameraUpdate)
+ }
+ }
+ }
+
+ fun setUserTrackingMode(userTrackingMode: Int) {
+ val oldTrackingMode = mUserTrackingMode
+ mUserTrackingMode = userTrackingMode
+ mManager.handleEvent(MapUserTrackingModeEvent(this@RCTMGLCamera, userTrackingMode))
+ when (mUserTrackingMode) {
+ UserTrackingMode.NONE -> mUserTrackingState = UserTrackingState.POSSIBLE
+ UserTrackingMode.FOLLOW, UserTrackingMode.FollowWithCourse, UserTrackingMode.FollowWithHeading -> if (oldTrackingMode == UserTrackingMode.NONE) {
+ mUserTrackingState = UserTrackingState.POSSIBLE
+ }
+ }
+ if (mapboxMap != null) {
+ updateLocationLayer(mapboxMap!!.getStyle()!!)
+ }
+ }
+
+ fun _observeViewportState(mapView: MapView) {
+ mapView.viewport.addStatusObserver(object: ViewportStatusObserver {
+ override fun onViewportStatusChanged(
+ from: ViewportStatus,
+ to: ViewportStatus,
+ reason: ViewportStatusChangeReason
+ ) {
+ if (to == ViewportStatus.Idle) {
+ mManager.handleEvent(MapUserTrackingModeEvent(this@RCTMGLCamera, UserTrackingMode.NONE))
+ } else if (to is ViewportStatus.Transition) {
+
+ } else if (to is ViewportStatus.State){
+ //mManager.handleEvent(MapUserTrackingModeEvent(this@RCTMGLCamera, UserTrackingMode.FOLLOW))
+ }
+ }
+ })
+ }
+
+ fun _updateViewportState() {
+ mMapView?.let {
+ val map = it
+ val viewport = map.viewport;
+
+ if (mLocationComponentManager == null) {
+ mLocationComponentManager = it.locationComponentManager
+ }
+
+ if (mFollowUserLocation == false) {
+ viewport.idle()
+ mLocationComponentManager?.setFollowLocation(false)
+ return;
+ }
+
+ mLocationComponentManager?.setFollowLocation(true)
+ mLocationManager?.let {
+ val provider = map.location.getLocationProvider()
+ if (provider != null) {
+ it.provider = provider
+ }
+ }
+
+ val location = map.location2
+ val followOptions = FollowPuckViewportStateOptions.Builder()
+ val cameraState = map.getMapboxMap().cameraState
+ when (mFollowUserMode ?: "normal") {
+ "compass" -> {
+ location.puckBearingEnabled = true
+ location.puckBearingSource = PuckBearingSource.HEADING
+ followOptions.bearing(FollowPuckViewportStateBearing.SyncWithLocationPuck)
+ }
+ "course" -> {
+ location.puckBearingEnabled = true
+ location.puckBearingSource = PuckBearingSource.COURSE
+ followOptions.bearing(FollowPuckViewportStateBearing.SyncWithLocationPuck)
+ }
+ "normal" -> {
+ location.puckBearingEnabled = false
+ when(val it=mFollowHeading) {
+ null -> followOptions.bearing( FollowPuckViewportStateBearing.Constant(
+ cameraState.bearing
+ ))
+ else -> followOptions.bearing( FollowPuckViewportStateBearing.Constant(
+ cameraState.bearing
+ ))
+ }
+ }
+ else -> {
+ Logger.e("RCTMGLCamera", "unexpected follow mode: $mFollowUserMode")
+ }
+ }
+
+ when(val it=mFollowZoomLevel) {
+ null -> followOptions.zoom(cameraState.zoom)
+ else -> followOptions.zoom(it)
+ }
+
+ when(val it=mFollowPitch) {
+ null -> followOptions.pitch(cameraState.pitch)
+ else -> followOptions.pitch(it)
+ }
+
+ when(val it=mFollowPadding) {
+ null -> followOptions.padding(cameraState.padding)
+ else -> followOptions.padding(it)
+ }
+
+
+ val followState = viewport.makeFollowPuckViewportState(followOptions.build())
+ viewport.transitionTo(followState)
+ }
+ mapboxMap?.let {
+ it.getStyle()?.let {
+ updateLocationLayer(it)
+ }
+ }
+ }
+
+ private fun updatedFollowUserMode() {
+ if (mFollowUserLocation) {
+ setUserTrackingMode(UserTrackingMode.fromString(mFollowUserMode))
+ } else {
+ setUserTrackingMode(UserTrackingMode.NONE)
+ }
+ }
+
+ val mapboxMap: MapboxMap?
+ get() = if (mMapView == null) {
+ null
+ } else mMapView!!.getMapboxMap()
+
+ /**
+ * Create a payload of the location data per the web api geolocation spec
+ * https://dev.w3.org/geo/api/spec-source.html#position
+ *
+ * @return
+ */
+ private fun makeLocationChangePayload(location: Location): WritableMap {
+ val positionProperties: WritableMap = WritableNativeMap()
+ val coords: WritableMap = WritableNativeMap()
+ coords.putDouble("longitude", location.longitude)
+ coords.putDouble("latitude", location.latitude)
+ coords.putDouble("altitude", location.altitude)
+ coords.putDouble("accuracy", location.accuracy.toDouble())
+ // A better solution will be to pull the heading from the compass engine,
+ // unfortunately the api is not publicly available in the mapbox sdk
+ coords.putDouble("heading", location.bearing.toDouble())
+ coords.putDouble("course", location.bearing.toDouble())
+ coords.putDouble("speed", location.speed.toDouble())
+ positionProperties.putMap("coords", coords)
+ positionProperties.putDouble("timestamp", location.time.toDouble())
+ return positionProperties
+ }
+
+ companion object {
+ const val USER_LOCATION_CAMERA_MOVE_DURATION = 1000
+ const val minimumZoomLevelForUserTracking = 10.5
+ const val defaultZoomLevelForUserTracking = 14.0
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/RCTMGLCameraManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/RCTMGLCameraManager.kt
new file mode 100644
index 000000000..0c0338977
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/RCTMGLCameraManager.kt
@@ -0,0 +1,108 @@
+package com.mapbox.rctmgl.components.camera
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.bridge.ReadableMap
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.mapbox.geojson.FeatureCollection
+import com.mapbox.rctmgl.components.AbstractEventEmitter
+import com.mapbox.rctmgl.components.camera.CameraStop.Companion.fromReadableMap
+import com.mapbox.rctmgl.utils.GeoJSONUtils.toLatLngBounds
+
+
+class RCTMGLCameraManager(private val mContext: ReactApplicationContext) :
+ AbstractEventEmitter(
+ mContext
+ ) {
+ override fun customEvents(): Map? {
+ return HashMap()
+ }
+
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLCamera {
+ return RCTMGLCamera(reactContext, this)
+ }
+
+ @ReactProp(name = "stop")
+ fun setStop(camera: RCTMGLCamera, map: ReadableMap?) {
+ if (map != null) {
+ val stop = fromReadableMap(mContext, map, null)
+ camera.setStop(stop)
+ }
+ }
+
+ @ReactProp(name = "defaultStop")
+ fun setDefaultStop(camera: RCTMGLCamera, map: ReadableMap?) {
+ if (map != null) {
+ val stop = fromReadableMap(mContext, map, null)
+ camera.setDefaultStop(stop)
+ }
+ }
+
+ @ReactProp(name = "userTrackingMode")
+ fun setUserTrackingMode(camera: RCTMGLCamera, userTrackingMode: Int) {
+ camera.setUserTrackingMode(userTrackingMode)
+ throw AssertionError("Unused code")
+ }
+
+ @ReactProp(name = "zoomLevel")
+ fun setZoomLevel(camera: RCTMGLCamera, zoomLevel: Double) {
+ camera.setZoomLevel(zoomLevel)
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(camera: RCTMGLCamera, value: Double) {
+ camera.setMinZoomLevel(value)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(camera: RCTMGLCamera, value: Double) {
+ camera.setMaxZoomLevel(value)
+ }
+
+ @ReactProp(name = "followUserLocation")
+ fun setFollowUserLocation(camera: RCTMGLCamera, value: Boolean) {
+ camera.setFollowUserLocation(value)
+ }
+
+ @ReactProp(name = "followUserMode")
+ fun setFollowUserMode(camera: RCTMGLCamera, value: String?) {
+ camera.setFollowUserMode(value)
+ }
+
+ @ReactProp(name = "followZoomLevel")
+ fun setFollowZoomLevel(camera: RCTMGLCamera, value: Double) {
+ camera.setFollowZoomLevel(value)
+ }
+
+ @ReactProp(name = "followPitch")
+ fun setFollowPitch(camera: RCTMGLCamera, value: Double) {
+ camera.setFollowPitch(value)
+ }
+
+ @ReactProp(name = "followHeading")
+ fun setFollowHeading(camera: RCTMGLCamera, value: Double) {
+ camera.setFollowHeading(value)
+ }
+
+ @ReactProp(name = "followPadding")
+ fun setFollowPadding(camera: RCTMGLCamera, value: ReadableMap) {
+ camera.setFollowPadding(value)
+ }
+
+ @ReactProp(name = "maxBounds")
+ fun setMaxBounds(camera: RCTMGLCamera, value: String?) {
+ if (value != null) {
+ val collection = FeatureCollection.fromJson(value)
+ camera.setMaxBounds(toLatLngBounds(collection))
+ } else {
+ camera.setMaxBounds(null)
+ }
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLCamera"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/constants/CameraMode.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/constants/CameraMode.java
new file mode 100644
index 000000000..5dc5fcd2f
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/camera/constants/CameraMode.java
@@ -0,0 +1,18 @@
+package com.mapbox.rctmgl.components.camera.constants;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class CameraMode {
+
+ @IntDef({ FLIGHT, EASE, LINEAR, NONE })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Mode {}
+
+ public static final int FLIGHT = 1;
+ public static final int EASE = 2;
+ public static final int LINEAR = 3;
+ public static final int NONE = 4;
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImage.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImage.kt
new file mode 100644
index 000000000..a9acd93b9
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImage.kt
@@ -0,0 +1,74 @@
+package com.mapbox.rctmgl.components.images
+
+import android.graphics.Bitmap
+import android.view.View
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.facebook.react.views.view.ReactViewGroup
+import com.mapbox.maps.ImageContent
+import com.mapbox.maps.ImageStretches
+import com.mapbox.rctmgl.components.annotation.RCTMGLCallout
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.utils.BitmapUtils
+import com.mapbox.rctmgl.utils.Logger
+
+class RCTMGLImage(private val mContext: ReactApplicationContext, private val mManager: RCTMGLImageManager): ReactViewGroup(mContext), View.OnLayoutChangeListener {
+ var name: String? = null
+ var sdf: Boolean = false
+ var scale: Double = 1.0
+ var stretchX = listOf();
+ var stretchY = listOf();
+ var content: ImageContent? = null;
+
+ var mChildView: View? = null;
+
+ var mMapView: RCTMGLMapView? = null;
+
+ var nativeImageUpdater: NativeImageUpdater? = null;
+
+ var mBitmap : Bitmap? = null
+
+ override fun onLayoutChange(v: View, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int,
+ oldRight: Int, oldBottom: Int) {
+ if (left == 0 && top == 0 && right == 0 && bottom == 0) {
+ return
+ }
+ if (left != oldLeft || right != oldRight || top != oldTop || bottom != oldBottom) {
+ refreshBitmap(v, left, top, right, bottom)
+ }
+ }
+
+ private fun refreshBitmap(v: View, left: Int = v.left, top: Int = v.top, right: Int = v.right, bottom: Int = v.bottom) {
+ val name = this.name
+ if (name == null) {
+ Logger.e("RCTMGLImage", "Image component has no name")
+ return
+ }
+ val bitmap = BitmapUtils.viewToBitmap(v, left, top, right, bottom)
+ nativeImageUpdater?.let {
+ it.updateImage(name, bitmap, sdf, stretchX, stretchY, content, scale)
+ mBitmap = null;
+ }
+ }
+
+ fun refresh() {
+ mChildView?.let {
+ refreshBitmap(it)
+ }
+ }
+
+ override fun addView(childView: View, childPosition: Int) {
+ if (childPosition != 0) {
+ Logger.e("RCTMGLImage", "expected a single subview got childView:$childView position:$childPosition")
+ }
+ mMapView?.offscreenAnnotationViewContainer?.addView(childView)
+ mChildView = childView
+ childView.addOnLayoutChangeListener(this)
+ }
+
+ // region add/remove to Map
+ fun addToMap(mapView: RCTMGLMapView) {
+ mMapView = mapView
+ }
+ // endregion
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImageManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImageManager.kt
new file mode 100644
index 000000000..656480658
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImageManager.kt
@@ -0,0 +1,67 @@
+package com.mapbox.rctmgl.components.images
+
+import com.facebook.react.bridge.Dynamic
+import com.facebook.react.bridge.DynamicFromArray
+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.annotations.ReactProp
+import com.mapbox.rctmgl.components.AbstractEventEmitter
+import com.mapbox.rctmgl.events.constants.EventKeys
+
+class RCTMGLImageManager(private val mContext: ReactApplicationContext) : AbstractEventEmitter(
+mContext
+) {
+ override fun getName(): String {
+ return "RCTMGLImage"
+ }
+
+ override fun createViewInstance(p0: ThemedReactContext): RCTMGLImage {
+ return RCTMGLImage(mContext, this)
+ }
+
+ override fun customEvents(): MutableMap? {
+ return mutableMapOf();
+ }
+
+ // region React properties
+ @ReactProp(name="name")
+ fun setName(image: RCTMGLImage, value: String) {
+ image.name = value
+ }
+
+ @ReactProp(name="sdf")
+ fun setSdf(image: RCTMGLImage, value: Boolean) {
+ image.sdf = value
+ }
+
+ @ReactProp(name="stretchX")
+ fun setStretchX(image: RCTMGLImage, value: Dynamic) {
+ image.stretchX = RCTMGLImagesManager.convertStretch(value) ?: listOf()
+ }
+
+ @ReactProp(name="stretchY")
+ fun setStretchY(image: RCTMGLImage, value: Dynamic) {
+ image.stretchY = RCTMGLImagesManager.convertStretch(value) ?: listOf()
+ }
+
+ @ReactProp(name="content")
+ fun setContent(image: RCTMGLImage, value: Dynamic) {
+ image.content = RCTMGLImagesManager.convertContent(value)
+ }
+
+ @ReactProp(name="scale")
+ fun setScale(image: RCTMGLImage, value: Double) {
+ image.scale = value
+ }
+ // endregion
+
+ // region React methods
+ override fun receiveCommand(root: RCTMGLImage, commandId: String?, args: ReadableArray?) {
+ if (commandId == "refresh") {
+ root.refresh()
+ }
+ }
+ // endregion
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImages.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImages.kt
new file mode 100644
index 000000000..35e9fbaab
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImages.kt
@@ -0,0 +1,251 @@
+package com.mapbox.rctmgl.components.images
+
+import android.content.Context
+import android.graphics.Bitmap
+import com.mapbox.rctmgl.components.images.RCTMGLImagesManager
+import com.mapbox.rctmgl.components.AbstractMapFeature
+import com.mapbox.rctmgl.utils.ImageEntry
+import android.graphics.drawable.BitmapDrawable
+import androidx.core.content.res.ResourcesCompat
+import com.mapbox.bindgen.Expected
+import com.mapbox.bindgen.None
+import com.mapbox.maps.Image
+import com.mapbox.maps.ImageContent
+import com.mapbox.maps.ImageStretches
+import com.mapbox.maps.MapboxMap
+import com.mapbox.maps.Style
+import com.mapbox.rctmgl.R
+import com.mapbox.rctmgl.components.RemovalReason
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.images.RCTMGLImages
+import com.mapbox.rctmgl.events.ImageMissingEvent
+import com.mapbox.rctmgl.utils.BitmapUtils
+import com.mapbox.rctmgl.utils.DownloadMapImageTask
+import java.nio.ByteBuffer
+import java.util.AbstractMap
+import java.util.ArrayList
+import java.util.HashMap
+import java.util.HashSet
+
+fun Style.addBitmapImage(imageId: String, bitmap: Bitmap, sdf: Boolean = false, stretchX: List = listOf(), stretchY: List = listOf(), content: ImageContent? = null, scale: Double = 1.0) : Expected {
+ val byteBuffer = ByteBuffer.allocate(bitmap.byteCount)
+ bitmap.copyPixelsToBuffer(byteBuffer)
+ return this.addStyleImage(
+ imageId,
+ (1.0/((160.0/bitmap.density)) * scale).toFloat() ,
+ Image(bitmap.width, bitmap.height, byteBuffer.array()),
+ sdf,
+ stretchX,
+ stretchY,
+ content,
+ )
+}
+
+fun Style.addBitmapImage(nativeImage: NativeImage) : Expected {
+ return addBitmapImage(nativeImage.name, nativeImage.drawable.bitmap, nativeImage.sdf, nativeImage.stretchX, nativeImage.stretchY, nativeImage.content, nativeImage.scale)
+}
+
+data class NativeImage(val name: String, val drawable: BitmapDrawable, val scale: Double = 1.0, val sdf: Boolean = false, val stretchX: List = listOf(),
+ val stretchY: List = listOf(), val content: ImageContent? = null
+);
+
+interface NativeImageUpdater {
+ fun updateImage(imageId: String, bitmap: Bitmap, sdf: Boolean = false, stretchX: List = listOf(), stretchY: List = listOf(), content: ImageContent? = null, scale: Double = 1.0)
+}
+
+class RCTMGLImages(context: Context, private val mManager: RCTMGLImagesManager) : AbstractMapFeature(context), NativeImageUpdater {
+ var mCurrentImages: MutableSet
+ var mImageViews = mutableListOf();
+ private var mImages: MutableMap?
+ private var mNativeImages = mutableMapOf()
+ private var mSendMissingImageEvents = false
+ private var mMap: MapboxMap? = null
+
+ fun setImages(images: List>) {
+ val newImages: MutableMap = HashMap()
+ for ((key, value) in images) {
+ val oldValue = mImages?.put(key, value)
+ if (oldValue == null) {
+ newImages[key] = value
+ }
+ }
+ if (mMap != null && mMap?.getStyle() != null) {
+ addImagesToStyle(newImages, mMap!!)
+ }
+ }
+
+ fun setNativeImages(nativeImages: List) {
+ val newImages: MutableMap = HashMap()
+ for (nativeImage in nativeImages) {
+ val oldValue = mNativeImages.put(nativeImage.name, nativeImage)
+ if (oldValue == null) {
+ newImages[nativeImage.name] = nativeImage
+ }
+ }
+ mMap?.let {
+ if (it.getStyle() != null) {
+ addNativeImagesToStyle(newImages, it)
+ }
+ }
+ }
+
+ fun setHasOnImageMissing(value: Boolean) {
+ mSendMissingImageEvents = value
+ }
+
+ override fun removeFromMap(mapView: RCTMGLMapView, reason: RemovalReason): Boolean {
+ removeImages(mapView)
+ mMap = null
+ mNativeImages = mutableMapOf()
+ mImages = HashMap()
+ mCurrentImages = HashSet()
+ return super.removeFromMap(mapView, reason)
+ }
+
+ private fun removeImages(mapView: RCTMGLMapView) {
+ mapView.getStyle(object : Style.OnStyleLoaded {
+ override fun onStyleLoaded(style: Style) {
+ if (hasImages()) {
+ for ((key) in mImages!!) {
+ style.removeStyleImage(key)
+ }
+ }
+ if (hasNativeImages()) {
+ for ((key) in mNativeImages!!) {
+ style.removeStyleImage(key!!)
+ }
+ }
+ }
+ })
+ }
+
+ private fun hasImages(): Boolean {
+ return mImages != null && mImages!!.size > 0
+ }
+
+ private fun hasNativeImages(): Boolean {
+ return mNativeImages != null && mNativeImages!!.size > 0
+ }
+
+ fun addMissingImageToStyle(id: String, map: MapboxMap): Boolean {
+ val nativeImage = mNativeImages.get(id)
+ if (nativeImage != null) {
+ addNativeImages(listOf(nativeImage), map)
+ return true
+ }
+ if (mImages != null) {
+ val entry = mImages!![id]
+ if (entry != null) {
+ addRemoteImages(entry(id, entry), map)
+ return true
+ }
+ }
+ return false
+ }
+
+ fun addImagesToStyle(images: Map?, map: MapboxMap) {
+ if (images != null) {
+ addRemoteImages(ArrayList(images.entries), map)
+ }
+ }
+
+ fun addNativeImagesToStyle(images: Map, map: MapboxMap) {
+ addNativeImages(images.values.toList(), map)
+ }
+
+ fun sendImageMissingEvent(id: String, map: MapboxMap) {
+ if (mSendMissingImageEvents) {
+ mManager.handleEvent(ImageMissingEvent.makeImageMissingEvent(this, id))
+ }
+ }
+
+ private fun hasImage(imageId: String?, map: MapboxMap): Boolean {
+ val style = map.getStyle()
+ return style != null && imageId?.let { style.getStyleImage(it) } != null
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+
+ mImageViews.forEach {
+ it.addToMap(mapView)
+ }
+ // Wait for style before adding the source to the map
+ // only then we can pre-load required images / placeholders into the style
+ // before we add the ShapeSource to the map
+ mapView.getStyle(object : Style.OnStyleLoaded {
+ override fun onStyleLoaded(style: Style) {
+ val map = mapView.getMapboxMap()
+ mMap = map
+ addNativeImagesToStyle(mNativeImages, map)
+ addImagesToStyle(mImages, map)
+ // super.addToMap(mapView);
+
+ mImageViews.forEach {
+ it.refresh()
+ }
+ }
+ })
+ }
+
+ private fun addNativeImages(imageEntries: List, map: MapboxMap) {
+ val style = map.getStyle()
+ if (style == null) return
+ for (nativeImage in imageEntries) {
+ if (!hasImage(nativeImage.name, map)) {
+ val bitmap = nativeImage.drawable
+ style.addBitmapImage(nativeImage)
+ mCurrentImages.add(nativeImage.name)
+ }
+ }
+ }
+
+ private fun addRemoteImages(imageEntries: List>?, map: MapboxMap) {
+ val style = map.getStyle()
+ if (style == null || imageEntries == null) return
+ val missingImages: MutableList> = ArrayList()
+
+ // Add image placeholder for images that are not yet available in the style. This way
+ // we can load the images asynchronously and add the ShapeSource to the map without delay.
+ // The same is required when this ShapeSource is updated with new/added images and the
+ // data references them. In which case addMissingImageToStyle will take care of loading
+ // them in a similar way.
+ //
+ // See also: https://github.com/mapbox/mapbox-gl-native/pull/14253#issuecomment-478827792
+ for (imageEntry in imageEntries) {
+ if (!hasImage(imageEntry.key, map)) {
+ mImagePlaceholder?.let { style.addBitmapImage(imageEntry.key, it, false, listOf(), listOf(), null,1.0) }
+ missingImages.add(imageEntry)
+ mCurrentImages.add(imageEntry.key)
+ }
+ }
+ if (missingImages.size > 0) {
+ val task = DownloadMapImageTask(context, map, null)
+ val params = missingImages.toTypedArray()
+ task.execute(*params)
+ }
+ }
+
+ companion object {
+ private var mImagePlaceholder: Bitmap? = null
+ fun entry(k: K, v: V): List> {
+ return listOf(AbstractMap.SimpleEntry(k, v) as Map.Entry)
+ }
+ }
+
+ init {
+ mCurrentImages = HashSet()
+ mImages = HashMap()
+ mNativeImages = HashMap()
+ if (mImagePlaceholder == null) {
+ mImagePlaceholder = BitmapUtils.getBitmapFromDrawable(ResourcesCompat.getDrawable(context.resources, R.drawable.empty_drawable, null))
+ }
+ }
+
+ override fun updateImage(imageId: String, bitmap: Bitmap, sdf: Boolean, stretchX: List, stretchY: List, content: ImageContent?, scale: Double)
+ {
+ mMap?.getStyle()?.let {
+ it.addBitmapImage(imageId, bitmap, sdf, stretchX, stretchY, content, scale);
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImagesManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImagesManager.kt
new file mode 100644
index 000000000..dafff1603
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/images/RCTMGLImagesManager.kt
@@ -0,0 +1,216 @@
+package com.mapbox.rctmgl.components.images
+
+import android.graphics.drawable.BitmapDrawable
+import android.view.View
+import com.facebook.react.bridge.*
+import com.facebook.react.common.MapBuilder
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.mapbox.maps.ImageContent
+import com.mapbox.maps.ImageStretches
+import com.mapbox.rctmgl.components.AbstractEventEmitter
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.events.constants.EventKeys
+import com.mapbox.rctmgl.modules.RCTMGLLogging
+import com.mapbox.rctmgl.utils.ImageEntry
+import com.mapbox.rctmgl.utils.Logger
+import com.mapbox.rctmgl.utils.ResourceUtils
+import java.util.*
+
+class RCTMGLImagesManager(private val mContext: ReactApplicationContext) :
+ AbstractEventEmitter(
+ mContext
+ ) {
+ override fun getName(): String {
+ return "RCTMGLImages"
+ }
+
+ public override fun createViewInstance(context: ThemedReactContext): RCTMGLImages {
+ return RCTMGLImages(context, this)
+ }
+
+ @ReactProp(name = "images")
+ fun setImages(images: RCTMGLImages, map: ReadableMap) {
+ val imagesList: MutableList> = ArrayList()
+ val iterator = map.keySetIterator()
+ while (iterator.hasNextKey()) {
+ val imageName = iterator.nextKey()
+ var imageEntry: ImageEntry? = null
+ imageEntry = if (map.getType(imageName) == ReadableType.Map) {
+ val imageMap = map.getMap(imageName)
+ val uri = imageMap!!.getString("uri")
+ val hasScale =
+ imageMap.hasKey("scale") && imageMap.getType("scale") == ReadableType.Number
+ val scale = if (hasScale) imageMap.getDouble("scale") else ImageEntry.defaultScale
+ ImageEntry(uri, scale)
+ } else {
+ ImageEntry(map.getString(imageName))
+ }
+ imagesList.add(AbstractMap.SimpleEntry(imageName, imageEntry))
+ }
+ images.setImages(imagesList)
+ }
+
+ @ReactProp(name = "hasOnImageMissing")
+ fun setHasOnImageMissing(images: RCTMGLImages, value: Boolean?) {
+ images.setHasOnImageMissing(value!!)
+ }
+
+ fun toNativeImage(dynamic: Dynamic): NativeImage? {
+ when (dynamic.type) {
+ ReadableType.String -> {
+ val resourceName = dynamic.asString();
+ val drawable =
+ ResourceUtils.getDrawableByName(mContext, resourceName) as BitmapDrawable
+ if (drawable != null) {
+ return NativeImage(resourceName, drawable)
+ } else {
+ Logger.e("RCTMGLImages", "cound not get native drawable with name: $resourceName")
+ return null
+ }
+ }
+ ReadableType.Map -> {
+ val map = dynamic.asMap()
+ val resourceName = map.getString("name")
+ var sdf = false
+ var stretchX = listOf();
+ var stretchY = listOf();
+ var content : ImageContent? = null;
+ var scale : Double = 1.0;
+ if (map.hasKey("sdf")) {
+ sdf = map.getBoolean("sdf");
+ }
+ if (map.hasKey("stretchX")) {
+ stretchX = convertStretch(map.getDynamic("stretchX")) ?: listOf()
+ }
+ if (map.hasKey("stretchY")) {
+ stretchY = convertStretch(map.getDynamic("stretchY")) ?: listOf()
+ }
+ if (map.hasKey("content")) {
+ content = convertContent(map.getDynamic("content")) ?: null
+ }
+ if (map.hasKey("scale")) {
+ if (map.getType("scale") != ReadableType.Number) {
+ Logger.e("RCTMGLImages", "scale should be a number found: $scale in $dynamic")
+ return null
+ }
+ scale = map.getDouble("scale")
+ }
+ val drawable =
+ ResourceUtils.getDrawableByName(mContext, resourceName) as BitmapDrawable
+ if (drawable != null && resourceName != null) {
+ return NativeImage(resourceName, drawable, scale, sdf, stretchX, stretchY)
+ } else {
+ Logger.e("RCTMGLImages", "cound not get native drawable with name: $resourceName")
+ return null
+ }
+ }
+ else -> {
+ Logger.e("RCTMGLImages", "nativeImages element should be a string or a object, but was: $dynamic")
+ return null
+ }
+ }
+ }
+
+ @ReactProp(name = "nativeImages")
+ fun setNativeImages(images: RCTMGLImages, arr: ReadableArray) {
+ val nativeImages = mutableListOf();
+ for (i in 0 until arr.size()) {
+ val nativeImage = toNativeImage(arr.getDynamic(i))
+ if (nativeImage != null) {
+ nativeImages.add(nativeImage)
+ }
+ }
+ images.setNativeImages(nativeImages)
+ }
+
+ override fun customEvents(): Map? {
+ return MapBuilder.builder()
+ .put(EventKeys.IMAGES_MISSING, "onImageMissing")
+ .build()
+ }
+
+ // region RCTMGLImage children
+
+ override fun addView(parent: RCTMGLImages?, childView: View?, childPosition: Int) {
+ if (parent == null || childView == null) {
+ Logger.e("RCTMGLImages", "addView: parent or childView is null")
+ return
+ }
+
+ if (childView !is RCTMGLImage) {
+ Logger.e("RCTMGLImages", "child view should be RCTMGLImage")
+ return
+ }
+
+ parent.mImageViews.add(childPosition, childView)
+ childView.nativeImageUpdater = parent
+ }
+
+ override fun removeView(parent: RCTMGLImages?, view: View?) {
+ if (parent == null || view == null) {
+ Logger.e("RCTMGLImages", "removeView: parent or view is null")
+ return
+ }
+
+ parent.mImageViews.remove(view)
+ }
+
+ override fun removeAllViews(parent: RCTMGLImages?) {
+ if (parent == null) {
+ Logger.e("RCTMGLImages", "removeAllViews parent is null")
+ return
+ }
+
+ parent.mImageViews.clear()
+ }
+
+ // endregion
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLImages"
+
+ fun convertStretch(stretch: Dynamic) : List? {
+ if (stretch.type != ReadableType.Array) {
+ Logger.e("RCTMGLImages", "stretch should be an array, got $stretch")
+ return null
+ }
+ val array = stretch.asArray()
+ var result = mutableListOf();
+ for (i in 0 until array.size()) {
+ if (array.getType(i) != ReadableType.Array) {
+ Logger.e("RTMGLImages", "each element of strech should be an array but was: ${array.getDynamic(i)}")
+ } else {
+ val pair = array.getArray(i)
+ if (pair.size() != 2 || pair.getType(0) != ReadableType.Number || pair.getType(1) != ReadableType.Number) {
+ Logger.e("RCTMGLImages", "each element of stretch should be pair of 2 integers but was ${pair}")
+ }
+ result.add(ImageStretches(pair.getDouble(0).toFloat(), pair.getDouble(1).toFloat()))
+ }
+ }
+ return result;
+ }
+
+ fun convertContent(content: Dynamic) : ImageContent? {
+ if (content.type != ReadableType.Array) {
+ Logger.e("RCTMGLImages", "content should be an array, got $content")
+ return null
+ }
+ val array = content.asArray()
+ if (array.size() != 4) {
+ Logger.e("RCTMGLImages", "content should be an array of 4 numbers, got $content")
+ return null
+ }
+ val result = arrayOf(0.0, 0.0, 0.0, 0.0, 0.0)
+ for (i in 0 until array.size()) {
+ if (array.getType(i) != ReadableType.Number) {
+ Logger.e("RTMGLImages", "each element of content should be an number but was : ${array}")
+ return null
+ } else {
+ result[i] = array.getDouble(i)
+ }
+ }
+ return ImageContent(result[0].toFloat(), result[1].toFloat() ,result[2].toFloat(), result[3].toFloat())
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/CameraMode.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/CameraMode.java
new file mode 100644
index 000000000..a4650997f
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/CameraMode.java
@@ -0,0 +1,62 @@
+package com.mapbox.rctmgl.components.location;
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Contains the variety of camera modes which determine how the camera will track
+ * the user location.
+ */
+public final class CameraMode {
+
+ private CameraMode() {
+ }
+
+ /**
+ * Determine the camera tracking behavior in the {@link LocationComponent}.
+ */
+ @IntDef( {NONE, NONE_COMPASS, NONE_GPS, TRACKING, TRACKING_COMPASS, TRACKING_GPS, TRACKING_GPS_NORTH})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Mode {
+ }
+
+ /**
+ * No camera tracking.
+ */
+ public static final int NONE = 0x00000008;
+
+ /**
+ * Camera does not track location, but does track compass bearing.
+ */
+ public static final int NONE_COMPASS = 0x00000010;
+
+ /**
+ * Camera does not track location, but does track GPS {@link Location} bearing.
+ */
+ public static final int NONE_GPS = 0x00000016;
+
+ /**
+ * Camera tracks the user location.
+ */
+ public static final int TRACKING = 0x00000018;
+
+ /**
+ * Camera tracks the user location, with bearing
+ * provided by a compass.
+ */
+ public static final int TRACKING_COMPASS = 0x00000020;
+
+ /**
+ * Camera tracks the user location, with bearing
+ * provided by a normalized {@link Location#getBearing()}.
+ */
+ public static final int TRACKING_GPS = 0x00000022;
+
+ /**
+ * Camera tracks the user location, with bearing
+ * always set to north (0).
+ */
+ public static final int TRACKING_GPS_NORTH = 0x00000024;
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/LocationComponentManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/LocationComponentManager.kt
new file mode 100644
index 000000000..63850c47e
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/LocationComponentManager.kt
@@ -0,0 +1,169 @@
+package com.mapbox.rctmgl.components.location
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.VectorDrawable
+import androidx.appcompat.content.res.AppCompatResources
+import androidx.lifecycle.Lifecycle
+import com.mapbox.maps.plugin.locationcomponent.location
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.maps.plugin.LocationPuck2D
+import com.mapbox.maps.plugin.PuckBearingSource
+import com.mapbox.maps.plugin.lifecycle.lifecycle
+import com.mapbox.rctmgl.R
+import com.mapbox.rctmgl.location.LocationManager
+
+/**
+ * The LocationComponent on android implements display of user's current location.
+ * But viewport seems to be tied to it in the sense that if location is not enabled then it's viewport user tracking is not working.
+ * LocationComponentManager attempts to separate that, so that Camera can ask for location tracking independent of display of user current location.
+ * And NativeUserLocation can ask for display of user's current location - independent of Camera's user tracking.
+ */
+class LocationComponentManager(mapView: RCTMGLMapView, context: Context) {
+ var mMapView = mapView
+ var mContext = context
+ private var mState = State(showUserLocation=false, followUserLocation=false, tintColor= null, bearingImage = null, puckBearingSource =null)
+
+ private var mLocationManager: LocationManager = LocationManager.getInstance(context)
+
+ private var mNeedsFullUpdate = true
+
+ private var mLocationManagerStarted = false
+
+ data class State(
+ val showUserLocation: Boolean,
+ val followUserLocation: Boolean,
+ val tintColor: Int?, // tint of location puck
+ var bearingImage: Drawable?, // bearing image (background)
+ var puckBearingSource: PuckBearingSource? // bearing source
+ ) {
+ val enabled: Boolean
+ get() = showUserLocation || followUserLocation
+
+ val hidden: Boolean
+ get() = followUserLocation && !showUserLocation
+ }
+
+ fun update(newStateCallback: (currentState: State) -> State) {
+ val newState = newStateCallback(mState);
+ if (newState != mState) {
+ applyStateChanges(mState, newState)
+ mState = newState
+ }
+ }
+
+ private fun applyStateChanges(oldState: State, newState: State) {
+ mMapView.let {
+ val needsFullUpdate = mNeedsFullUpdate
+
+ applyStateChanges(it, oldState, newState, needsFullUpdate)
+
+ mNeedsFullUpdate = false
+ }
+ }
+
+ private fun applyStateChanges(map: RCTMGLMapView, oldState: State, newState: State, fullUpdate: Boolean) {
+ if (map.getLifecycleState() != Lifecycle.State.STARTED) {
+ // In case lifecycle was already stopped, so we're part of shutdown, do not call updateSettings as it'll just restart
+ // the loationComponent that will not be stopped. See https://github.com/mapbox/mapbox-maps-android/issues/2017
+ if (!newState.enabled) {
+ stopLocationManager()
+ }
+ return
+ }
+ map.location.updateSettings {
+ enabled = newState.enabled
+
+ if (fullUpdate || (newState.hidden != oldState.hidden) || (newState.tintColor != oldState.tintColor) || (newState.bearingImage != oldState.bearingImage)) {
+ if (newState.hidden) {
+ var emptyLocationPuck = LocationPuck2D()
+ val empty = AppCompatResources.getDrawable(mContext, R.drawable.empty)
+ emptyLocationPuck.bearingImage = empty
+ emptyLocationPuck.shadowImage = empty
+ emptyLocationPuck.topImage = empty
+ //emptyLocationPuck.opacity = 0.0
+ locationPuck = emptyLocationPuck
+ pulsingEnabled = false
+ } else {
+ val mapboxBlueColor = Color.parseColor("#4A90E2")
+ val tintColor = newState.tintColor
+ val defaultLocationPuck = LocationPuck2D()
+ var topImage = AppCompatResources.getDrawable(mContext, R.drawable.mapbox_user_icon)
+ if (tintColor != null) {
+ val drawable = topImage as VectorDrawable?
+ drawable!!.setTint(tintColor)
+ topImage = drawable
+ }
+ defaultLocationPuck.topImage = topImage
+ val defaultBearingImage = AppCompatResources.getDrawable(
+ mContext, R.drawable.mapbox_user_stroke_icon
+ );
+ defaultLocationPuck.bearingImage = newState.bearingImage ?: defaultBearingImage
+ val shadowImage = AppCompatResources.getDrawable(
+ mContext, R.drawable.mapbox_user_icon_shadow
+ )
+ defaultLocationPuck.shadowImage = shadowImage
+ locationPuck = defaultLocationPuck
+ pulsingEnabled = true
+ if (tintColor != null) {
+ pulsingColor = tintColor
+ } else {
+ pulsingColor = mapboxBlueColor
+ }
+ }
+ }
+
+ if (fullUpdate || newState.enabled != mState.enabled) {
+ if (newState.enabled) {
+ startLocationManager()
+ useMapLocationProvider(map)
+ } else {
+ stopLocationManager()
+ }
+ }
+ }
+ }
+
+ private fun startLocationManager() {
+ if (!mLocationManagerStarted) {
+ mLocationManager.startCounted()
+ mLocationManagerStarted = true
+ }
+ }
+
+ private fun stopLocationManager() {
+ if (mLocationManagerStarted) {
+ mLocationManager.stopCounted()
+ mLocationManagerStarted = false
+ }
+ }
+
+ private fun useMapLocationProvider(mapView: RCTMGLMapView) {
+ val provider = mapView.location.getLocationProvider()
+ if (provider != null) {
+ mLocationManager.provider = provider
+ }
+ }
+
+
+ fun showNativeUserLocation(showUserLocation: Boolean) {
+ update {
+ it.copy(showUserLocation = showUserLocation)
+ }
+ }
+
+ fun setFollowLocation(followUserLocation: Boolean) {
+ update {
+ it.copy(followUserLocation = followUserLocation)
+ }
+ }
+
+ fun update() {
+ update { it }
+ }
+
+ fun onDestroy() {
+ stopLocationManager();
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocation.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocation.kt
new file mode 100644
index 000000000..6bdff4e8b
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocation.kt
@@ -0,0 +1,81 @@
+package com.mapbox.rctmgl.components.location
+
+import android.annotation.SuppressLint
+import android.content.Context
+import androidx.appcompat.content.res.AppCompatResources
+import com.mapbox.rctmgl.components.mapview.OnMapReadyCallback
+import com.mapbox.maps.MapboxMap
+import com.mapbox.android.core.permissions.PermissionsManager
+import com.mapbox.maps.Style
+import com.mapbox.maps.plugin.PuckBearingSource
+import com.mapbox.rctmgl.R
+import com.mapbox.rctmgl.components.AbstractMapFeature
+import com.mapbox.rctmgl.components.RemovalReason
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+
+enum class RenderMode {
+ GPS, COMPASS, NORMAL
+}
+
+class RCTMGLNativeUserLocation(context: Context) : AbstractMapFeature(context), OnMapReadyCallback, Style.OnStyleLoaded {
+ private var mEnabled = true
+ private var mMap: MapboxMap? = null
+ private var mRenderMode : RenderMode = RenderMode.NORMAL;
+ private var mContext : Context = context
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ mEnabled = true
+ mapView.getMapboxMap()
+ mapView.getMapAsync(this)
+ mMapView?.locationComponentManager?.showNativeUserLocation(true)
+ applyChanges()
+ }
+
+ override fun removeFromMap(mapView: RCTMGLMapView, reason: RemovalReason): Boolean {
+ mEnabled = false
+ mMapView?.locationComponentManager?.showNativeUserLocation(false)
+ mMap?.getStyle(this)
+ return super.removeFromMap(mapView, reason)
+ }
+
+ @SuppressLint("MissingPermission")
+ override fun onMapReady(mapboxMap: MapboxMap) {
+ mMap = mapboxMap
+ mapboxMap.getStyle(this)
+ applyChanges()
+ }
+
+ fun setAndroidRenderMode(renderMode: RenderMode) {
+ mRenderMode = renderMode;
+ applyChanges();
+ }
+
+ @SuppressLint("MissingPermission")
+ override fun onStyleLoaded(style: Style) {
+ val context = context
+ if (!PermissionsManager.areLocationPermissionsGranted(context)) {
+ return
+ }
+
+ mMapView?.locationComponentManager?.update()
+ mMapView?.locationComponentManager?.showNativeUserLocation(mEnabled)
+ }
+
+ fun applyChanges() {
+ mMapView?.locationComponentManager?.let {
+ // emulate https://docs.mapbox.com/android/legacy/maps/guides/location-component/
+ when (mRenderMode) {
+ RenderMode.NORMAL ->
+ it.update { it.copy(bearingImage = null, puckBearingSource = null)}
+ RenderMode.GPS -> it.update {
+ it.copy(bearingImage = AppCompatResources.getDrawable(
+ mContext, R.drawable.mapbox_user_bearing_icon
+ ), puckBearingSource = PuckBearingSource.COURSE) }
+ RenderMode.COMPASS -> it.update{ it.copy(bearingImage= AppCompatResources.getDrawable(
+ mContext, R.drawable.mapbox_user_puck_icon
+ ), puckBearingSource = PuckBearingSource.HEADING) }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocationManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocationManager.kt
new file mode 100644
index 000000000..7e1e8fd3b
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/RCTMGLNativeUserLocationManager.kt
@@ -0,0 +1,32 @@
+package com.mapbox.rctmgl.components.location
+
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.ViewGroupManager
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.mapbox.rctmgl.utils.Logger
+import javax.annotation.Nonnull
+
+class RCTMGLNativeUserLocationManager : ViewGroupManager() {
+ @Nonnull
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ @ReactProp(name = "androidRenderMode")
+ fun setAndroidRenderMode(userLocation: RCTMGLNativeUserLocation, mode: String) {
+ when (mode) {
+ "compass" -> userLocation.setAndroidRenderMode(RenderMode.COMPASS);
+ "gps" -> userLocation.setAndroidRenderMode(RenderMode.GPS);
+ "normal" -> userLocation.setAndroidRenderMode(RenderMode.NORMAL);
+ }
+ }
+
+ @Nonnull
+ override fun createViewInstance(@Nonnull reactContext: ThemedReactContext): RCTMGLNativeUserLocation {
+ return RCTMGLNativeUserLocation(reactContext)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLNativeUserLocation"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/UserLocation.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/UserLocation.java
new file mode 100644
index 000000000..7c695a825
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/UserLocation.java
@@ -0,0 +1,59 @@
+package com.mapbox.rctmgl.components.location;
+
+import android.location.Location;
+
+import com.mapbox.rctmgl.utils.LatLng;
+
+public class UserLocation {
+ private Location currentLocation;
+ private Location previousLocation;
+
+ private int userTrackingMode = UserTrackingMode.NONE;
+
+ public UserLocation() {
+ this(null);
+ }
+
+ public UserLocation(Location currentLocation) {
+ this.currentLocation = currentLocation;
+ }
+
+ public Location getCurrentLocation() {
+ return currentLocation;
+ }
+
+ public double getBearing() {
+ if (currentLocation == null) {
+ return 0.0;
+ }
+ return currentLocation.getBearing();
+ }
+
+ public LatLng getCoordinate() {
+ if (currentLocation == null) {
+ return null;
+ }
+
+ return new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude());
+ }
+
+ public void setCurrentLocation(Location currentLocation) {
+ this.previousLocation = this.currentLocation;
+ this.currentLocation = currentLocation;
+ }
+
+ public void setTrackingMode(int userTrackingMode) {
+ this.userTrackingMode = userTrackingMode;
+ }
+
+ public int getTrackingMode() {
+ return userTrackingMode;
+ }
+
+ public float getDistance(Location location) {
+ if (currentLocation == null) {
+ return 0.0f;
+ }
+ return currentLocation.distanceTo(location);
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/UserTrackingMode.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/UserTrackingMode.kt
new file mode 100644
index 000000000..3c10d082a
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/location/UserTrackingMode.kt
@@ -0,0 +1,42 @@
+package com.mapbox.rctmgl.components.location
+
+object UserTrackingMode {
+ const val NONE = 0
+ const val FOLLOW = 1
+ const val FollowWithCourse = 2
+ const val FollowWithHeading = 3
+ @CameraMode.Mode
+ fun getCameraMode(mode: Int): Int {
+ when (mode) {
+ NONE -> return CameraMode.NONE
+ FOLLOW -> return CameraMode.TRACKING
+ FollowWithCourse -> return CameraMode.TRACKING_GPS
+ FollowWithHeading -> return CameraMode.TRACKING_COMPASS
+ }
+ return CameraMode.NONE
+ }
+
+ fun isUserGesture(reason: Int): Boolean {
+ return reason == 1 || reason == 2 // user gesture or animation
+ }
+
+ fun toString(value: Int): String? {
+ when (value) {
+ FOLLOW -> return "normal"
+ FollowWithCourse -> return "course"
+ FollowWithHeading -> return "compass"
+ }
+ return null
+ }
+
+ fun fromString(value: String?): Int {
+ var value = value
+ if (value == null) value = ""
+ return when (value) {
+ "course" -> FollowWithCourse
+ "normal" -> FOLLOW
+ "compass" -> FollowWithHeading
+ else -> FOLLOW
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/OnMapReadyCallback.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/OnMapReadyCallback.java
new file mode 100644
index 000000000..ed811a0df
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/OnMapReadyCallback.java
@@ -0,0 +1,9 @@
+package com.mapbox.rctmgl.components.mapview;
+
+import androidx.annotation.NonNull;
+
+import com.mapbox.maps.MapboxMap;
+
+public interface OnMapReadyCallback {
+ public void onMapReady(@NonNull MapboxMap mapboxMap);
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapView.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapView.java
new file mode 100644
index 000000000..f893eb9ea
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapView.java
@@ -0,0 +1,16 @@
+package com.mapbox.rctmgl.components.mapview;
+
+import android.content.Context;
+//import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
+/**
+ * Created by hernanmateo on 12/11/18.
+ */
+
+@SuppressWarnings({"MissingPermission"})
+public class RCTMGLAndroidTextureMapView extends RCTMGLMapView {
+ public static final String LOG_TAG = "RCTMGLAndroidTextureMapView";
+
+ public RCTMGLAndroidTextureMapView(Context context, RCTMGLAndroidTextureMapViewManager manager/*, MapboxMapOptions options*/) {
+ super(context, manager/*, options*/);
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.kt
new file mode 100644
index 000000000..69f621c3b
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLAndroidTextureMapViewManager.kt
@@ -0,0 +1,28 @@
+package com.mapbox.rctmgl.components.mapview
+
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.uimanager.ThemedReactContext
+
+//import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
+/**
+ * Created by hernanmateo on 12/11/18.
+ */
+class RCTMGLAndroidTextureMapViewManager(context: ReactApplicationContext?) : RCTMGLMapViewManager(
+ context!!
+) {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(themedReactContext: ThemedReactContext): RCTMGLAndroidTextureMapView {
+ //MapboxMapOptions options = new MapboxMapOptions();
+ //options.textureMode(true);
+ val context = activity ?: themedReactContext
+ return RCTMGLAndroidTextureMapView(context, this /*, options*/)
+ }
+
+ companion object {
+ const val LOG_TAG = "RCTMGLAndroidTextureMapViewManager"
+ const val REACT_CLASS = "RCTMGLAndroidTextureMapView"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt
new file mode 100644
index 000000000..9fb0471e6
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapView.kt
@@ -0,0 +1,1430 @@
+package com.mapbox.rctmgl.components.mapview
+
+import android.content.Context
+import android.graphics.BitmapFactory
+import android.graphics.PointF
+import android.graphics.RectF
+import android.util.Log
+import android.view.Gravity
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.LifecycleRegistry
+import androidx.lifecycle.ViewTreeLifecycleOwner
+import com.facebook.react.bridge.*
+import com.mapbox.android.gestures.MoveGestureDetector
+import com.mapbox.android.gestures.RotateGestureDetector
+import com.mapbox.android.gestures.StandardScaleGestureDetector
+import com.mapbox.geojson.Feature
+import com.mapbox.geojson.FeatureCollection
+import com.mapbox.geojson.Point
+import com.mapbox.maps.*
+import com.mapbox.maps.extension.localization.localizeLabels
+import com.mapbox.maps.extension.observable.eventdata.MapLoadingErrorEventData
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.layers.Layer
+import com.mapbox.maps.extension.style.layers.generated.*
+import com.mapbox.maps.extension.style.layers.getLayer
+import com.mapbox.maps.extension.style.layers.properties.generated.ProjectionName
+import com.mapbox.maps.extension.style.layers.properties.generated.Visibility
+import com.mapbox.maps.extension.style.projection.generated.Projection
+import com.mapbox.maps.extension.style.projection.generated.setProjection
+import com.mapbox.maps.plugin.annotation.Annotation
+import com.mapbox.maps.plugin.annotation.AnnotationConfig
+import com.mapbox.maps.plugin.annotation.annotations
+import com.mapbox.maps.plugin.annotation.generated.*
+import com.mapbox.maps.plugin.attribution.attribution
+import com.mapbox.maps.plugin.attribution.generated.AttributionSettings
+import com.mapbox.maps.plugin.compass.compass
+import com.mapbox.maps.plugin.compass.generated.CompassSettings
+import com.mapbox.maps.plugin.delegates.listeners.*
+import com.mapbox.maps.plugin.gestures.*
+import com.mapbox.maps.plugin.logo.generated.LogoSettings
+import com.mapbox.maps.plugin.logo.logo
+import com.mapbox.maps.plugin.scalebar.generated.ScaleBarSettings
+import com.mapbox.maps.plugin.scalebar.scalebar
+import com.mapbox.rctmgl.R
+import com.mapbox.rctmgl.components.AbstractMapFeature
+import com.mapbox.rctmgl.components.RemovalReason
+import com.mapbox.rctmgl.components.annotation.RCTMGLMarkerView
+import com.mapbox.rctmgl.components.annotation.RCTMGLMarkerViewManager
+import com.mapbox.rctmgl.components.annotation.RCTMGLPointAnnotation
+import com.mapbox.rctmgl.components.camera.RCTMGLCamera
+import com.mapbox.rctmgl.components.images.RCTMGLImages
+import com.mapbox.rctmgl.components.location.LocationComponentManager
+import com.mapbox.rctmgl.components.location.RCTMGLNativeUserLocation
+import com.mapbox.rctmgl.components.mapview.helpers.CameraChangeReason
+import com.mapbox.rctmgl.components.mapview.helpers.CameraChangeTracker
+import com.mapbox.rctmgl.components.styles.layers.RCTLayer
+import com.mapbox.rctmgl.components.styles.light.RCTMGLLight
+import com.mapbox.rctmgl.components.styles.sources.RCTSource
+import com.mapbox.rctmgl.components.styles.terrain.RCTMGLTerrain
+import com.mapbox.rctmgl.events.AndroidCallbackEvent
+import com.mapbox.rctmgl.events.IEvent
+import com.mapbox.rctmgl.events.MapChangeEvent
+import com.mapbox.rctmgl.events.MapClickEvent
+import com.mapbox.rctmgl.events.constants.EventTypes
+import com.mapbox.rctmgl.utils.*
+import com.mapbox.rctmgl.utils.extensions.toReadableArray
+import org.json.JSONException
+import org.json.JSONObject
+import java.util.*
+
+
+data class OrnamentSettings(
+ var enabled : Boolean? = false,
+ var margins: ReadableMap? =null,
+ var position: Int = -1
+)
+
+enum class MapGestureType {
+ Move,Scale,Rotate
+}
+
+/***
+ * Mapbox's MapView observers lifecycle events see MapboxLifecyclePluginImpl - (ON_START, ON_STOP, ON_DESTROY)
+ * We need to emulate those.
+ */
+interface RCTMGLLifeCycleOwner : LifecycleOwner {
+ fun handleLifecycleEvent(event: Lifecycle.Event)
+}
+
+class RCTMGLLifeCycle {
+ private var lifecycleOwner : RCTMGLLifeCycleOwner? = null
+
+ fun onAttachedToWindow(view: View) {
+ if (lifecycleOwner == null) {
+ lifecycleOwner = object : RCTMGLLifeCycleOwner {
+ private lateinit var lifecycleRegistry: LifecycleRegistry
+ init {
+ lifecycleRegistry = LifecycleRegistry(this)
+ lifecycleRegistry.currentState = Lifecycle.State.CREATED
+ }
+
+ override fun handleLifecycleEvent(event: Lifecycle.Event) {
+ try {
+ lifecycleRegistry.handleLifecycleEvent(event)
+ } catch (e: RuntimeException) {
+ Log.e("RCTMGLMapView", "handleLifecycleEvent, handleLifecycleEvent error: $e")
+ }
+ }
+
+ override fun getLifecycle(): Lifecycle {
+ return lifecycleRegistry
+ }
+ }
+ ViewTreeLifecycleOwner.set(view, lifecycleOwner);
+ }
+ lifecycleOwner?.handleLifecycleEvent(Lifecycle.Event.ON_START)
+ }
+
+ fun onDetachedFromWindow() {
+ if (lifecycleOwner?.lifecycle?.currentState == Lifecycle.State.DESTROYED) {
+ return
+ }
+ lifecycleOwner?.handleLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_STOP)
+ }
+
+ fun onDestroy() {
+ if (lifecycleOwner?.lifecycle?.currentState == Lifecycle.State.STARTED || lifecycleOwner?.lifecycle?.currentState == Lifecycle.State.RESUMED) {
+ lifecycleOwner?.handleLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_STOP)
+ }
+ if (lifecycleOwner?.lifecycle?.currentState != Lifecycle.State.DESTROYED) {
+ lifecycleOwner?.handleLifecycleEvent(androidx.lifecycle.Lifecycle.Event.ON_DESTROY)
+ }
+ }
+
+ fun getState() : Lifecycle.State {
+ return lifecycleOwner?.lifecycle?.currentState ?: Lifecycle.State.INITIALIZED;
+ }
+}
+
+data class FeatureEntry(val feature: AbstractMapFeature?, val view: View?, var addedToMap: Boolean = false) {
+
+}
+
+open class RCTMGLMapView(private val mContext: Context, var mManager: RCTMGLMapViewManager /*, MapboxMapOptions options*/) : MapView(mContext), OnMapClickListener, OnMapLongClickListener {
+ /**
+ * `PointAnnotations` are rendered to a canvas, but the React Native `Image` component is
+ * implemented on top of Fresco (https://frescolib.org), which does not load images for
+ * views not attached to the window. This provides an offscreen view where views can
+ * be rendered to the canvas before being added as annotations.
+ */
+ public var offscreenAnnotationViewContainer: ViewGroup? = null
+
+ private val mSources: MutableMap>
+ private val mImages: MutableList
+ private var mPointAnnotationManager: PointAnnotationManager? = null
+ private var mActiveMarkerID: Long = -1
+ private var mProjection: ProjectionName = ProjectionName.MERCATOR
+ private var mLocaleString: String? = null
+ private var mLocaleLayerIds: List? = null
+ private var mStyleURL: String? = null
+ val isDestroyed = false
+ private var mCamera: RCTMGLCamera? = null
+ private val mFeatures = mutableListOf()
+ private var mQueuedFeatures: MutableList? = ArrayList()
+ private val mPointAnnotations: MutableMap
+ private val mCameraChangeTracker = CameraChangeTracker()
+ private val mMap: MapboxMap?
+
+ var savedStyle: Style? = null
+ private set
+
+ private var styleLoaded = false
+
+ private var mHandledMapChangedEvents: HashSet? = null
+ private var mAnnotationClicked = false
+ private var mAnnotationDragged = false
+ private var mLocationComponentManager: LocationComponentManager? = null
+ var tintColor: Int? = null
+ private set
+
+ val mapView: MapView
+ get() = this
+
+ val pointAnnotationManager: PointAnnotationManager?
+ get() {
+ if (mPointAnnotationManager == null) {
+ val _this = this
+ val gesturesPlugin: GesturesPlugin = this.gestures
+ gesturesPlugin.removeOnMapClickListener(_this)
+ gesturesPlugin.removeOnMapLongClickListener(_this)
+
+ mPointAnnotationManager = annotations.createPointAnnotationManager(AnnotationConfig(layerId = "rctmgl-mapview-annotations"))
+ mPointAnnotationManager?.addClickListener(OnPointAnnotationClickListener { pointAnnotation ->
+ onMarkerClick(pointAnnotation)
+ false
+ }
+ )
+ mPointAnnotationManager?.addDragListener(object : OnPointAnnotationDragListener {
+ override fun onAnnotationDragStarted(_annotation: Annotation<*>) {
+ mAnnotationDragged = true;
+ var reactAnnotation: RCTMGLPointAnnotation? = null
+ for (key in mPointAnnotations.keys) {
+ val annotation = mPointAnnotations[key]
+ val curMarkerID = annotation?.mapboxID
+ if (_annotation.id == curMarkerID) {
+ reactAnnotation = annotation
+ }
+ }
+ reactAnnotation?.let { it.onDragStart() }
+ }
+
+ override fun onAnnotationDrag(_annotation: Annotation<*>) {
+ var reactAnnotation: RCTMGLPointAnnotation? = null
+ for (key in mPointAnnotations.keys) {
+ val annotation = mPointAnnotations[key]
+ val curMarkerID = annotation?.mapboxID
+ if (_annotation.id == curMarkerID) {
+ reactAnnotation = annotation
+ }
+ }
+ reactAnnotation?.let { it.onDrag() }
+ }
+
+ override fun onAnnotationDragFinished(_annotation: Annotation<*>) {
+ mAnnotationDragged = false;
+ var reactAnnotation: RCTMGLPointAnnotation? = null
+ for (key in mPointAnnotations.keys) {
+ val annotation = mPointAnnotations[key]
+ val curMarkerID = annotation?.mapboxID
+ if (_annotation.id == curMarkerID) {
+ reactAnnotation = annotation
+ }
+ }
+ reactAnnotation?.let { it.onDragEnd() }
+ }
+ })
+ gesturesPlugin.addOnMapClickListener(_this)
+ gesturesPlugin.addOnMapLongClickListener(_this)
+
+ }
+ return mPointAnnotationManager
+ }
+
+ private fun styleLoaded(style: Style) {
+ savedStyle = style
+ styleLoaded = true
+ setUpImage(style)
+ addFeaturesToMap()
+ applyLocalizeLabels()
+ style.setProjection(Projection(mProjection))
+ }
+
+ private fun onMapReady(map: MapboxMap) {
+ map.getStyle(object : Style.OnStyleLoaded {
+ override fun onStyleLoaded(style: Style) {
+ styleLoaded(style)
+ }
+ })
+ val _this = this
+
+ map.addOnCameraChangeListener(OnCameraChangeListener { cameraChangedEventData ->
+ handleMapChangedEvent(EventTypes.REGION_IS_CHANGING)
+ handleMapChangedEvent(EventTypes.CAMERA_CHANGED)
+ })
+
+ map.addOnMapIdleListener(OnMapIdleListener { mapIdleEventData ->
+ sendRegionDidChangeEvent()
+ handleMapChangedEvent(EventTypes.MAP_IDLE);
+ })
+
+ val gesturesPlugin: GesturesPlugin = this.gestures
+ gesturesPlugin.addOnMapLongClickListener(_this)
+ gesturesPlugin.addOnMapClickListener(_this)
+
+ gesturesPlugin.addOnScaleListener(object: OnScaleListener{
+ override fun onScale(detector: StandardScaleGestureDetector) {
+ mapGesture(MapGestureType.Scale, detector)
+ }
+ override fun onScaleBegin(detector: StandardScaleGestureDetector) {
+ mapGestureBegin(MapGestureType.Scale, detector)
+ }
+ override fun onScaleEnd(detector: StandardScaleGestureDetector) {
+ mapGestureEnd(MapGestureType.Scale, detector)
+ }
+ })
+
+ gesturesPlugin.addOnRotateListener(object: OnRotateListener{
+ override fun onRotate(detector: RotateGestureDetector) {
+ mapGesture(MapGestureType.Rotate, detector)
+ }
+ override fun onRotateBegin(detector: RotateGestureDetector) {
+ mapGestureBegin(MapGestureType.Rotate, detector)
+ }
+ override fun onRotateEnd(detector: RotateGestureDetector) {
+ mapGestureEnd(MapGestureType.Rotate, detector)
+ }
+ })
+
+ gesturesPlugin.addOnMoveListener(object : OnMoveListener {
+ override fun onMoveBegin(moveGestureDetector: MoveGestureDetector) {
+ mapGestureBegin(MapGestureType.Move, moveGestureDetector)
+ }
+
+ override fun onMove(moveGestureDetector: MoveGestureDetector): Boolean {
+ return mapGesture(MapGestureType.Move, moveGestureDetector)
+ }
+
+ override fun onMoveEnd(moveGestureDetector: MoveGestureDetector) {
+ mapGestureEnd(MapGestureType.Move, moveGestureDetector)
+ }
+ })
+
+ map.subscribe({ event -> Logger.e(LOG_TAG, String.format("Map load failed: %s", event.data.toString())) }, Arrays.asList(MapEvents.MAP_LOADING_ERROR))
+ }
+
+ fun mapGestureBegin(type:MapGestureType, gesture: T) {
+ mCameraChangeTracker.setReason(CameraChangeReason.USER_GESTURE)
+ handleMapChangedEvent(EventTypes.REGION_WILL_CHANGE)
+ }
+ fun mapGesture(type: MapGestureType, gesture: T): Boolean {
+ mCameraChangeTracker.setReason(CameraChangeReason.USER_GESTURE)
+ handleMapChangedEvent(EventTypes.REGION_IS_CHANGING)
+ return false
+ }
+ fun mapGestureEnd(type: MapGestureType, gesture: T) {}
+
+ fun init() {
+ // Required for rendering properly in Android Oreo
+ viewTreeObserver.dispatchOnGlobalLayout()
+ }
+
+ fun getStyle(onStyleLoaded: Style.OnStyleLoaded) {
+ if (mMap == null) {
+ return
+ }
+ mMap.getStyle(onStyleLoaded)
+ }
+
+ // region Features
+ fun addFeature(childView: View?, childPosition: Int) {
+ var feature: AbstractMapFeature? = null
+ if (childView is RCTSource<*>) {
+ val source = childView
+ mSources[source.iD.toString()] = source
+ feature = childView as AbstractMapFeature?
+ } else if (childView is RCTMGLImages) {
+ mImages.add(childView)
+ feature = childView
+ } else if (childView is RCTMGLLight) {
+ feature = childView
+ } else if (childView is RCTMGLTerrain) {
+ feature = childView as AbstractMapFeature?
+ } else if (childView is RCTMGLNativeUserLocation) {
+ feature = childView
+ } else if (childView is RCTMGLPointAnnotation) {
+ val annotation = childView
+ mPointAnnotations[annotation.iD.toString()] = annotation
+ feature = childView
+ } else if (childView is RCTMGLMarkerView) {
+ feature = childView
+ } else if (childView is RCTMGLCamera) {
+ mCamera = childView
+ feature = childView
+ } else if (childView is RCTLayer<*>) {
+ feature = childView as AbstractMapFeature?
+ } else if (childView is ViewGroup) {
+ val children = childView
+ Logger.w(LOG_TAG, "Adding non map components as a child of a map is deprecated!")
+ for (i in 0 until children.childCount) {
+ addView(children.getChildAt(i), childPosition)
+ }
+ }
+
+ val addToMap = styleLoaded
+
+
+ var entry = FeatureEntry(feature, childView, false)
+ if (addToMap) {
+ feature?.addToMap(this)
+ entry.addedToMap = true
+ }
+ mFeatures.add(childPosition, entry);
+ }
+
+ fun removeFeatureAt(childPosition: Int) {
+ val entry = mFeatures[childPosition]
+ val feature = entry.feature
+ if (feature is RCTSource<*>) {
+ mSources.remove(feature.iD)
+ } else if (feature is RCTMGLPointAnnotation) {
+ val annotation = feature
+ if (annotation.mapboxID == mActiveMarkerID) {
+ mActiveMarkerID = -1
+ }
+ mPointAnnotations.remove(annotation.iD)
+ } else if (feature is RCTMGLImages) {
+ mImages.remove(feature)
+ }
+ if (entry.addedToMap) {
+ if (feature?.removeFromMap(this, RemovalReason.VIEW_REMOVAL) == true) {
+ entry.addedToMap = false
+ }
+ }
+ mFeatures.removeAt(childPosition)
+ }
+
+ val featureCount: Int
+ get() = mFeatures.size
+
+ fun getFeatureAt(i: Int): View? {
+ return mFeatures[i].view
+ }
+
+ fun removeAllFeatureFromMap(reason: RemovalReason) {
+ mFeatures.forEach {
+ if (it.feature?.removeFromMap(this, reason) == true) {
+ it.addedToMap = false
+ }
+ }
+ }
+ // endregion
+
+ fun sendRegionChangeEvent(isAnimated: Boolean) {
+ val didChangeEvent = MapChangeEvent(this, EventTypes.REGION_DID_CHANGE,
+ makeRegionPayload(isAnimated))
+ mManager.handleEvent(didChangeEvent)
+ mCameraChangeTracker.setReason(CameraChangeReason.NONE)
+ }
+
+ private fun removeAllFeaturesFromMap(reason: RemovalReason) {
+ mFeatures.forEach { it ->
+ if (it.feature?.removeFromMap(this, reason) == true) {
+ it.addedToMap = false
+ }
+ }
+ }
+
+ private fun addFeaturesToMap() {
+ mFeatures.forEach {
+ if (!it.addedToMap) {
+ it.feature?.addToMap(this)
+ it.addedToMap = true
+ }
+ }
+ }
+
+
+ private val allTouchableSources: List>
+ private get() {
+ val sources: MutableList> = ArrayList()
+ for (key in mSources.keys) {
+ val source = mSources[key]
+ if (source != null && source.hasPressListener()) {
+ sources.add(source)
+ }
+ }
+ return sources
+ }
+
+ private fun getTouchableSourceWithHighestZIndex(sources: List>?): RCTSource<*>? {
+ if (sources == null || sources.size == 0) {
+ return null
+ }
+ if (sources.size == 1) {
+ return sources[0]
+ }
+ val layerToSourceMap: MutableMap> = HashMap()
+ for (source in sources) {
+ val layerIDs: Array? = source.layerIDs.toTypedArray()
+ if (layerIDs != null) {
+ for (layerID in layerIDs) {
+ layerToSourceMap[layerID] = source
+ }
+ }
+ }
+ val mapboxLayers = mMap?.getStyle()?.styleLayers
+ if (mapboxLayers != null) {
+ for (i in mapboxLayers.indices.reversed()) {
+ val mapboxLayer = mapboxLayers[i]
+ val layerID = mapboxLayer.id
+ if (layerToSourceMap.containsKey(layerID)) {
+ return layerToSourceMap[layerID]
+ }
+ }
+ }
+ return null
+ }
+
+ fun isJSONValid(test: String?): Boolean {
+ if (test == null) {
+ return false
+ }
+ try {
+ JSONObject(test)
+ } catch (ex: JSONException) {
+ return false
+ }
+ return true
+ }
+
+ fun setReactProjection(projection: ProjectionName) {
+ if (projection != null) {
+ mProjection = projection
+ }
+
+ if (mMap != null) {
+ mMap.getStyle()?.setProjection(Projection(projection))
+ }
+ }
+
+ fun applyLocalizeLabels() {
+ val localeStr = mLocaleString
+ if (localeStr != null) {
+ val locale = if (localeStr == "current") Locale.getDefault() else Locale(localeStr)
+ savedStyle?.localizeLabels(locale, mLocaleLayerIds)
+ }
+ }
+ fun setReactLocalizeLabels(localeStr: String?, layerIds: List?) {
+ if (localeStr != null) {
+ mLocaleString = localeStr
+ mLocaleLayerIds = layerIds
+ }
+ applyLocalizeLabels()
+ }
+
+ fun setReactStyleURL(styleURL: String) {
+ mStyleURL = styleURL
+ if (mMap != null) {
+ removeAllFeatureFromMap(RemovalReason.STYLE_CHANGE)
+ if (isJSONValid(mStyleURL)) {
+ styleLoaded = false
+ mMap.loadStyleJson(styleURL, object : Style.OnStyleLoaded {
+ override fun onStyleLoaded(style: Style) {
+ styleLoaded(style)
+ }
+ })
+ } else {
+ styleLoaded = false
+ mMap.loadStyleUri(styleURL, object : Style.OnStyleLoaded {
+ override fun onStyleLoaded(style: Style) {
+ styleLoaded(style)
+ }
+ },
+ object : OnMapLoadErrorListener {
+ override fun onMapLoadError(mapLoadingErrorEventData: MapLoadingErrorEventData) {
+ Logger.w("MapLoadError", mapLoadingErrorEventData.message)
+ }
+ }
+ )
+ }
+ }
+ }
+
+ interface HandleTap {
+ fun run(hitTouchableSources: List?>?, hits: Map?>)
+ }
+
+ fun handleTapInSources(
+ sources: LinkedList>, screenPoint: ScreenCoordinate,
+ hits: HashMap?>,
+ hitTouchableSources: ArrayList?>,
+ handleTap: HandleTap
+ ) {
+ if (sources.isEmpty()) {
+ handleTap.run(hitTouchableSources, hits)
+ return
+ }
+ val source = sources.removeFirst()
+ val hitbox = source.touchHitbox
+ if (hitbox != null) {
+ val halfWidth = (hitbox["width"]!!.toFloat() / 2.0f).toDouble()
+ val halfHeight = (hitbox["height"]!!.toFloat() / 2.0f).toDouble()
+ val screenBox = ScreenBox(
+ ScreenCoordinate(screenPoint.x - halfWidth,
+ screenPoint.y - halfHeight
+ ),
+ ScreenCoordinate(screenPoint.x + halfWidth,
+ screenPoint.y + halfHeight)
+ )
+ getMapboxMap().queryRenderedFeatures(RenderedQueryGeometry(screenBox),
+ RenderedQueryOptions(
+ source.layerIDs,
+ null
+ )
+ ) { features ->
+ if (features.isValue) {
+ if (features.value!!.size > 0) {
+ val featuresList = ArrayList()
+ for (i in features.value!!) {
+ featuresList.add(i.feature)
+ }
+ hits[source.iD] = featuresList
+ hitTouchableSources.add(source)
+ }
+ } else {
+ Logger.e("handleTapInSources", features.error ?: "n/a")
+ }
+ handleTapInSources(sources, screenPoint, hits, hitTouchableSources, handleTap)
+ }
+ }
+ }
+
+ override fun onMapClick(point: Point): Boolean {
+ val _this = this
+ /*if (mPointAnnotationManager != nil) {
+ getAnnotations()
+ }*/if (mAnnotationClicked) {
+ mAnnotationClicked = false
+ return true
+ }
+ val screenPoint = mMap?.pixelForCoordinate(point)
+ val touchableSources = allTouchableSources
+ val hits = HashMap?>()
+ if (screenPoint != null) {
+ handleTapInSources(LinkedList(touchableSources), screenPoint, hits, ArrayList(), object : HandleTap {
+ override fun run(hitTouchableSources: List?>?, hits: Map?>) {
+ if (hits.size > 0) {
+ val source = getTouchableSourceWithHighestZIndex(hitTouchableSources as List>?)
+ if (source != null && source.hasPressListener() && source.iD != null && source.iD in hits) {
+ source.onPress(RCTSource.OnPressEvent(
+ hits[source.iD] as List,
+ GeoJSONUtils.toLatLng(point),
+ PointF(screenPoint.x.toFloat(), screenPoint.y.toFloat())
+ ))
+ return
+ }
+ }
+ val event = MapClickEvent(_this, LatLng(point), screenPoint)
+ mManager.handleEvent(event)
+ }
+
+ })
+ }
+ return false
+ }
+
+ override fun onMapLongClick(point: Point): Boolean {
+ val _this = this
+ if (mAnnotationDragged) {
+ mAnnotationDragged = false
+ return true
+ }
+ val screenPoint = mMap?.pixelForCoordinate(point)
+ if (screenPoint != null) {
+ val event = MapClickEvent(_this, LatLng(point), screenPoint, EventTypes.MAP_LONG_CLICK)
+ mManager.handleEvent(event)
+ }
+
+ return false
+ }
+
+ fun onMarkerClick(symbol: PointAnnotation) {
+ mAnnotationClicked = true
+ val selectedMarkerID = symbol.id
+ var activeAnnotation: RCTMGLPointAnnotation? = null
+ var nextActiveAnnotation: RCTMGLPointAnnotation? = null
+ for (key in mPointAnnotations.keys) {
+ val annotation = mPointAnnotations[key]
+ val curMarkerID = annotation?.mapboxID
+ if (mActiveMarkerID == curMarkerID) {
+ activeAnnotation = annotation
+ }
+ if (selectedMarkerID == curMarkerID && mActiveMarkerID != curMarkerID) {
+ nextActiveAnnotation = annotation
+ }
+ }
+ activeAnnotation?.let { deselectAnnotation(it) }
+ nextActiveAnnotation?.let { selectAnnotation(it) }
+ }
+
+ fun selectAnnotation(annotation: RCTMGLPointAnnotation) {
+ mActiveMarkerID = annotation.mapboxID
+ annotation.onSelect(true)
+ }
+
+ fun deselectAnnotation(annotation: RCTMGLPointAnnotation) {
+ mActiveMarkerID = -1
+ annotation.onDeselect()
+ }
+
+ interface FoundLayerCallback {
+ fun found(layer: Layer?)
+ }
+
+ private val layerWaiters: MutableMap> = HashMap()
+ fun layerAdded(layer: Layer) {
+ val layerId = layer.layerId
+ val callbacks: List? = layerWaiters[layerId]
+ if (callbacks != null) {
+ for (callback in callbacks) {
+ callback.found(layer)
+ }
+ }
+ layerWaiters.remove(layerId)
+ }
+
+ fun waitForLayer(layerID: String?, callback: FoundLayerCallback) {
+ if(layerID == null){
+ callback.found(null)
+ return
+ }
+ if (savedStyle != null) {
+ val layer = savedStyle?.getLayer(layerID)
+ if (layer != null) {
+ callback.found(layer)
+ return
+ }
+ }
+ var waiters = layerWaiters[layerID]
+ if (waiters == null) {
+ waiters = ArrayList()
+ layerWaiters[layerID] = waiters
+ }
+ waiters.add(callback)
+ }
+
+ // region Events
+
+ fun sendRegionDidChangeEvent() {
+ handleMapChangedEvent(EventTypes.REGION_DID_CHANGE)
+ mCameraChangeTracker.setReason(CameraChangeReason.NONE)
+ }
+
+ private fun handleMapChangedEvent(eventType: String) {
+ if (!canHandleEvent(eventType)) return
+
+ val event: IEvent
+ event = when (eventType) {
+ EventTypes.REGION_WILL_CHANGE, EventTypes.REGION_DID_CHANGE, EventTypes.REGION_IS_CHANGING -> MapChangeEvent(this, eventType, makeRegionPayload(null))
+ EventTypes.CAMERA_CHANGED, EventTypes.MAP_IDLE -> MapChangeEvent(this, eventType, makeCameraPayload())
+ else -> MapChangeEvent(this, eventType)
+ }
+ mManager.handleEvent(event)
+ }
+
+ fun setHandledMapChangedEvents(events: Array) {
+ mHandledMapChangedEvents = HashSet(events.asList())
+ }
+
+ private fun canHandleEvent(event: String): Boolean {
+ val changedEvents = mHandledMapChangedEvents
+ return changedEvents == null || changedEvents.contains(event)
+ }
+
+ private fun makeCameraPayload(): WritableMap {
+ val position = mMap?.cameraState ?: return WritableNativeMap()
+ val properties = WritableNativeMap()
+ properties.putDouble("zoom", position.zoom)
+ properties.putDouble("heading", position.bearing)
+ properties.putDouble("pitch", position.pitch)
+ properties.putArray("center", position.center.toReadableArray())
+ try {
+ val bounds = mMap.coordinateBoundsForCamera(position.toCameraOptions())
+
+ val boundsMap = WritableNativeMap()
+ boundsMap.putArray("ne", bounds.northeast.toReadableArray())
+ boundsMap.putArray("sw", bounds.southwest.toReadableArray())
+
+ properties.putMap("bounds", boundsMap)
+ } catch (ex: Exception) {
+ Logger.e(LOG_TAG, "An error occurred while attempting to make the region", ex)
+ }
+ val gestures = WritableNativeMap()
+ gestures.putBoolean("isGestureActive", mCameraChangeTracker.isUserInteraction)
+ // gestures.putBoolean("isAnimatingFromGesture", if (null == isAnimated) mCameraChangeTracker.isAnimated else isAnimated)
+
+ val state: WritableMap = WritableNativeMap()
+ state.putMap("properties", properties)
+ state.putMap("gestures", gestures)
+
+ return state
+ }
+
+ private fun makeRegionPayload(isAnimated: Boolean?): WritableMap {
+ val position = mMap?.cameraState ?: return WritableNativeMap()
+ val latLng = LatLng(position.center.latitude(), position.center.longitude())
+ val properties: WritableMap = WritableNativeMap()
+ properties.putDouble("zoomLevel", position.zoom)
+ properties.putDouble("heading", position.bearing)
+ properties.putDouble("pitch", position.pitch)
+ properties.putBoolean("animated",
+ if (null == isAnimated) mCameraChangeTracker.isAnimated else isAnimated)
+ properties.putBoolean("isUserInteraction", mCameraChangeTracker.isUserInteraction)
+ try {
+ val bounds = mMap.coordinateBoundsForCamera(position.toCameraOptions())
+ properties.putArray("visibleBounds", bounds.toReadableArray())
+ } catch (ex: Exception) {
+ Logger.e(LOG_TAG, "An error occurred while attempting to make the region", ex)
+ }
+ return GeoJSONUtils.toPointFeature(latLng, properties)
+ }
+
+ // endregion
+
+ /**
+ * Adds the marker image to the map for use as a SymbolLayer icon
+ */
+ private fun setUpImage(loadedStyle: Style) {
+ loadedStyle.addImage("MARKER_IMAGE_ID", BitmapFactory.decodeResource(
+ this.resources, R.drawable.red_marker)
+ )
+ }
+
+ val locationComponentManager: LocationComponentManager
+ get() {
+ if (mLocationComponentManager == null) {
+ mLocationComponentManager = LocationComponentManager(this, mContext)
+ }
+ return mLocationComponentManager!!
+ }
+
+ fun getMapAsync(mapReady: OnMapReadyCallback) {
+ mapReady.onMapReady(getMapboxMap())
+ }
+
+ //fun setTintColor(color: Int) {
+ // tintColor = color
+ // if (mLocationComponentManager != null) {
+ // mLocationComponentManager.tintColorChanged()
+ // }
+ //}
+
+ // region Callbacks
+
+ fun getCenter(callbackID: String?) {
+ var center = mMap!!.cameraState!!.center
+
+ sendResponse(callbackID, {
+ val array: WritableArray = WritableNativeArray()
+ array.pushDouble(center.longitude())
+ array.pushDouble(center.latitude())
+ it.putArray("center", array)
+ })
+ }
+
+ fun getZoom(callbackID: String?) {
+ var zoom = mMap!!.cameraState!!.zoom
+
+ sendResponse(callbackID, {
+ it.putDouble("zoom", zoom)
+ })
+ }
+
+ private fun getDisplayDensity(): Float {
+ return mContext.resources.displayMetrics.density
+ }
+
+ fun getCoordinateFromView(callbackID: String?, pixel: ScreenCoordinate) {
+ val density: Float = getDisplayDensity()
+ val screenCoordinate = ScreenCoordinate(pixel.x * density, pixel.y * density)
+
+ val coordinate = mMap!!.coordinateForPixel(screenCoordinate)
+
+ sendResponse(callbackID, {
+ it.putArray("coordinateFromView", coordinate.toReadableArray())
+ })
+ }
+
+ fun getPointInView(callbackID: String?, coordinate: Point) {
+ val point = mMap!!.pixelForCoordinate(coordinate)
+
+ sendResponse(callbackID, {
+ val array: WritableArray = WritableNativeArray()
+ array.pushDouble(point.x)
+ array.pushDouble(point.y)
+ it.putArray("pointInView", array)
+ })
+ }
+
+ fun queryRenderedFeaturesAtPoint(callbackID: String?, point: PointF, filter: Expression?, layerIDs: List?) {
+ if (mMap == null) {
+ Logger.e("queryRenderedFeaturesAtPoint", "mapbox map is null")
+ return
+ }
+ val screenCoordinate = ScreenCoordinate(point.x.toDouble(), point.y.toDouble())
+ val queryGeometry = RenderedQueryGeometry(screenCoordinate)
+ val layers = layerIDs?.takeUnless { it.isEmpty() } ?: null;
+ val queryOptions = RenderedQueryOptions(layers, filter)
+ mMap.queryRenderedFeatures(queryGeometry, queryOptions) { features ->
+ if (features.isValue) {
+ val featuresList = ArrayList()
+ for (i in features.value!!) {
+ featuresList.add(i.feature)
+ }
+ sendResponse(callbackID) {
+ it.putString("data", FeatureCollection.fromFeatures(featuresList).toJson())
+ }
+ } else {
+ Logger.e("queryRenderedFeaturesAtPoint", features.error ?: "n/a")
+ }
+ }
+ }
+
+ fun queryRenderedFeaturesInRect(callbackID: String?, rect: RectF, filter: Expression?, layerIDs: List?) {
+ val size = mMap!!.getMapOptions().size
+ val screenBox = if (rect.isEmpty()) ScreenBox(ScreenCoordinate(0.0, 0.0), ScreenCoordinate(size?.width!!.toDouble(), size?.height!!.toDouble())) else ScreenBox(
+ ScreenCoordinate(rect.right.toDouble(), rect.bottom.toDouble() ),
+ ScreenCoordinate(rect.left.toDouble(), rect.top.toDouble()),
+ )
+ mMap?.queryRenderedFeatures(
+ RenderedQueryGeometry(screenBox),
+ RenderedQueryOptions(layerIDs, filter)
+ ) { features ->
+ if (features.isValue) {
+ val featuresList = ArrayList()
+ for (i in features.value!!) {
+ featuresList.add(i.feature)
+ }
+
+ val payload: WritableMap = WritableNativeMap()
+ payload.putString("data", FeatureCollection.fromFeatures(featuresList).toJson())
+
+ var event = AndroidCallbackEvent(this, callbackID, payload)
+ mManager.handleEvent(event)
+ } else {
+ Logger.e("queryRenderedFeaturesInRect", features.error ?: "n/a")
+ }
+ }
+ }
+
+ fun sendResponse(callbackID: String?, buildPayload: (map: WritableMap) -> Unit) {
+ val payload: WritableMap = WritableNativeMap()
+ buildPayload(payload)
+ var event = AndroidCallbackEvent(this, callbackID, payload)
+ mManager.handleEvent(event)
+ }
+
+ fun getVisibleBounds(callbackID: String?) {
+ val bounds = mMap!!.coordinateBoundsForCamera(mMap!!.cameraState.toCameraOptions())
+
+ sendResponse(callbackID, {
+ it.putArray("visibleBounds", bounds.toReadableArray())
+ })
+ }
+
+ fun takeSnap(callbackID: String?, writeToDisk: Boolean) {
+ this.snapshot { snapshot ->
+ if (snapshot == null) {
+ Logger.e("takeSnap", "snapshot failed")
+
+ sendResponse(callbackID, {
+ it.putNull("data")
+ it.putString("error", "no snapshot")
+ })
+ } else {
+ val uri: String = if (writeToDisk) BitmapUtils.createTempFile(
+ mContext,
+ snapshot
+ ) else BitmapUtils.createBase64(snapshot)
+
+ sendResponse(callbackID, {
+ it.putString("uri", uri)
+ })
+ }
+ }
+ }
+
+ fun queryTerrainElevation(callbackID: String?, longitude: Double, latitude: Double) {
+ val result = mMap?.getElevation(Point.fromLngLat(longitude, latitude))
+
+ sendResponse(callbackID, {
+ if (result != null) {
+ it.putDouble("data", result)
+ } else {
+ Logger.e("queryTerrainElevation", "no elevation data")
+
+ it.putNull("data")
+ it.putString("error", "no elevation")
+ }
+ })
+ }
+
+ fun match(layer: Layer, sourceId:String, sourceLayerId: String?) : Boolean {
+ fun match(actSourceId: String, actSourceLayerId: String?) : Boolean {
+ return (actSourceId == sourceId && ((sourceLayerId == null) || (sourceLayerId == actSourceLayerId)))
+ }
+ return when (layer) {
+ is BackgroundLayer -> false
+ is LocationIndicatorLayer -> false
+ is SkyLayer -> false
+ is CircleLayer -> match(layer.sourceId, layer.sourceLayer)
+ is FillExtrusionLayer -> match(layer.sourceId, layer.sourceLayer)
+ is FillLayer -> match(layer.sourceId, layer.sourceLayer)
+ is HeatmapLayer -> match(layer.sourceId, layer.sourceLayer)
+ is HillshadeLayer -> match(layer.sourceId, layer.sourceLayer)
+ is LineLayer -> match(layer.sourceId, layer.sourceLayer)
+ is RasterLayer -> match(layer.sourceId, layer.sourceLayer)
+ is SymbolLayer -> match(layer.sourceId, layer.sourceLayer)
+ else -> {
+ logE("MapView", "Layer type: $layer.type unknown.")
+ false
+ }
+ }
+ }
+
+ fun setSourceVisibility(
+ visible: Boolean,
+ sourceId: String,
+ sourceLayerId: String?
+ ) {
+ if (mMap == null) {
+ Logger.e("MapView", "setSourceVisibility, map is null")
+ return
+ }
+ val style = mMap!!.getStyle();
+ style!!.styleLayers.forEach {
+ val layer = style.getLayer(it.id)
+ if ((layer != null) && match(layer, sourceId, sourceLayerId)) {
+ layer.visibility(
+ if (visible) Visibility.VISIBLE else Visibility.NONE
+ )
+ }
+ }
+ }
+
+ // endregion
+
+ companion object {
+ const val LOG_TAG = "RCTMGLMapView"
+ }
+
+ init {
+ offscreenAnnotationViewContainer = FrameLayout(getContext())
+ val p = FrameLayout.LayoutParams(0, 0)
+ p.setMargins(-10000, -10000, -10000, -10000)
+ offscreenAnnotationViewContainer?.setLayoutParams(p)
+ addView(offscreenAnnotationViewContainer)
+
+ mMap = getMapboxMap()
+ mSources = HashMap()
+ mImages = ArrayList()
+ mPointAnnotations = HashMap()
+
+ onMapReady(mMap)
+
+ val _this = this
+ mMap.addOnMapLoadedListener(OnMapLoadedListener { (begin, end) -> _this.handleMapChangedEvent(EventTypes.DID_FINISH_LOADING_MAP) })
+ mMap.addOnStyleImageMissingListener(OnStyleImageMissingListener { (begin, end, id) ->
+ for (images in mImages) {
+ if (images.addMissingImageToStyle(id, mMap)) {
+ return@OnStyleImageMissingListener
+ }
+ }
+ for (images in mImages) {
+ images.sendImageMissingEvent(id, mMap)
+ }
+ })
+
+ RCTMGLMarkerViewManager.markerViewContainerSizeFixer(this, this.viewAnnotationManager)
+ }
+
+ // region Ornaments
+
+ private fun toGravity(kind: String, viewPosition: Int): Int {
+ return when (viewPosition) {
+ 0 -> (Gravity.TOP or Gravity.START)
+ 1 -> (Gravity.TOP or Gravity.END)
+ 2 -> (Gravity.BOTTOM or Gravity.START)
+ 3 -> (Gravity.BOTTOM or Gravity.END)
+ else -> {
+ Logger.e(
+ "MapView",
+ "Unexpected viewPosition for $kind: $viewPosition should be between 0 and 3"
+ )
+ 0
+ }
+ }
+ }
+
+ private fun updateOrnament(kind: String, from: OrnamentSettings, to: GenericOrnamentSettings) {
+ from.enabled?.let { to.enabled = it }
+ if (from.position >= 0) {
+ to.position = toGravity(kind, from.position)
+ }
+
+ from.margins?.let {
+ val pixelDensity = resources.displayMetrics.density
+ val x: Int? = it.getDouble("x")?.let { (it * pixelDensity).toInt() }
+ val y: Int? = it.getDouble("y")?.let { (it * pixelDensity).toInt() }
+
+ val horizontalGravity = to.position and Gravity.HORIZONTAL_GRAVITY_MASK
+ val verticalGravity = to.position and Gravity.VERTICAL_GRAVITY_MASK
+
+ when (horizontalGravity) {
+ Gravity.LEFT -> { to.setHMargins(x?.toFloat(), 0f) }
+ Gravity.RIGHT -> { to.setHMargins(0f, x?.toFloat()) }
+ Gravity.CENTER_HORIZONTAL ->{ to.setHMargins(x?.toFloat(), x?.toFloat()) }
+ else -> Logger.e(
+ "MapView",
+ "${kind}ViewMargins: unexpected absolute pos: $horizontalGravity"
+ )
+ }
+ when (verticalGravity) {
+ Gravity.TOP -> { to.setVMargins(y?.toFloat(), 0f) }
+ Gravity.BOTTOM -> { to.setVMargins(0f, y?.toFloat()) }
+ Gravity.CENTER_VERTICAL -> { to.setVMargins(y?.toFloat(), y?.toFloat()) }
+ else -> Logger.e(
+ "MapView",
+ "${kind}ViewMargins: unexpected vertical pos: $verticalGravity"
+ )
+ }
+ }
+ }
+
+ var mCompassSettings = OrnamentSettings(enabled = false)
+ var mCompassFadeWhenNorth = false
+
+ fun setReactCompassEnabled(compassEnabled: Boolean) {
+ mCompassSettings.enabled = compassEnabled
+ updateCompass()
+ }
+
+ fun setReactCompassFadeWhenNorth(compassFadeWhenNorth: Boolean) {
+ mCompassFadeWhenNorth = compassFadeWhenNorth
+ updateCompass()
+ }
+
+ fun setReactCompassViewMargins(compassViewMargins: ReadableMap) {
+ mCompassSettings.margins = compassViewMargins
+ updateCompass()
+ }
+
+ fun setReactCompassViewPosition(compassViewPosition: Int) {
+ mCompassSettings.position = compassViewPosition
+ updateCompass()
+ }
+
+ fun setReactCompassPosition(compassPosition: ReadableMap) {
+ mCompassSettings.setPosAndMargins(compassPosition)
+ updateCompass()
+ }
+
+ private fun updateCompass() {
+ compass.updateSettings {
+ fadeWhenFacingNorth = mCompassFadeWhenNorth
+ updateOrnament("compass", mCompassSettings, this.toGenericOrnamentSettings())
+ }
+ workaroundToRelayoutChildOfMapView()
+ }
+
+ var mScaleBarSettings = OrnamentSettings(enabled = false)
+
+ fun setReactScaleBarEnabled(scaleBarEnabled: Boolean) {
+ mScaleBarSettings.enabled = scaleBarEnabled
+ updateScaleBar()
+ }
+
+ fun setReactScaleBarViewMargins(scaleBarMargins: ReadableMap) {
+ mScaleBarSettings.margins = scaleBarMargins
+ updateScaleBar()
+ }
+
+ fun setReactScaleBarViewPosition(scaleBarPosition: Int) {
+ mScaleBarSettings.position = scaleBarPosition
+ updateScaleBar()
+ }
+
+ fun setReactScaleBarPosition(scaleBarPosition: ReadableMap) {
+ mScaleBarSettings.setPosAndMargins(scaleBarPosition)
+ updateScaleBar()
+ }
+
+ private fun updateScaleBar() {
+ mapView.scalebar.updateSettings {
+ updateOrnament("scaleBar", mScaleBarSettings, this.toGenericOrnamentSettings())
+ }
+ workaroundToRelayoutChildOfMapView()
+ }
+
+ fun workaroundToRelayoutChildOfMapView() {
+ if (mapView.width == 0 && mapView.height == 0) {
+ return
+ }
+
+ mapView.requestLayout();
+ mapView.forceLayout();
+
+ mapView.measure(
+ MeasureSpec.makeMeasureSpec(mapView.measuredWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(mapView.measuredHeight, MeasureSpec.EXACTLY)
+ );
+ mapView.layout(mapView.left, mapView.top, mapView.right, mapView.bottom)
+ }
+
+ // endregion
+
+ private fun getGravityAndMargin (position:ReadableMap): Pair {
+ var gravity = Gravity.NO_GRAVITY
+ if (position.hasKey("left")) {
+ gravity = gravity or Gravity.START
+ }
+ if (position.hasKey("right")) {
+ gravity = gravity or Gravity.END
+ }
+ if (position.hasKey("top")) {
+ gravity = gravity or Gravity.TOP
+ }
+ if (position.hasKey("bottom")) {
+ gravity = gravity or Gravity.BOTTOM
+ }
+ val density = getDisplayDensity()
+ val margin = intArrayOf(
+ if (position.hasKey("left")) density.toInt() * position.getInt("left") else 0,
+ if (position.hasKey("top")) density.toInt() * position.getInt("top") else 0,
+ if (position.hasKey("right")) density.toInt() * position.getInt("right") else 0,
+ if (position.hasKey("bottom")) density.toInt() * position.getInt("bottom") else 0,
+ )
+ return Pair(gravity, margin)
+ }
+
+ // region Attribution
+ var mAttributionSettings = OrnamentSettings(enabled = AttributionSettings().enabled)
+
+ fun setReactAttributionEnabled(attributionEnabled: Boolean?) {
+ mAttributionSettings.enabled = attributionEnabled
+ updateAttribution()
+ }
+
+ fun setReactAttributionViewMargins(margins: ReadableMap) {
+ mAttributionSettings.margins = margins
+ updateAttribution()
+ }
+
+ fun setReactAttributionViewPosition(position: Int) {
+ mAttributionSettings.position = position
+ updateAttribution()
+ }
+
+ fun setReactAttributionPosition(position: ReadableMap?) {
+ mAttributionSettings.setPosAndMargins(position)
+ updateAttribution()
+ }
+
+ private fun updateAttribution() {
+ attribution.updateSettings {
+ updateOrnament("attribution", mAttributionSettings, this.toGenericOrnamentSettings())
+ }
+ workaroundToRelayoutChildOfMapView()
+ }
+ //endregion
+
+ // region Logo
+ private var mLogoEnabled: Boolean? = null;
+ private var mLogoGravity: Int? = null
+ private var mLogoMargin: IntArray? = null
+
+ var mLogoSettings = OrnamentSettings(enabled = null)
+
+ fun setReactLogoEnabled(enabled: Boolean?) {
+ mLogoSettings.enabled = enabled
+ updateLogo()
+ }
+
+ fun setReactLogoMargins(margins: ReadableMap) {
+ mLogoSettings.margins = margins
+ updateLogo()
+ }
+
+ fun setReactLogoViewPosition(position: Int) {
+ mLogoSettings.position = position
+ updateLogo()
+ }
+
+ fun setReactLogoPosition(position: ReadableMap?) {
+ mLogoSettings.setPosAndMargins(position)
+ updateLogo()
+ }
+
+ private fun updateLogo() {
+ logo.updateSettings {
+ updateOrnament("logo", mLogoSettings, this.toGenericOrnamentSettings())
+ }
+ workaroundToRelayoutChildOfMapView()
+ }
+ // endregion
+
+ // region lifecycle
+ private val lifecycle : RCTMGLLifeCycle by lazy { RCTMGLLifeCycle() }
+
+ fun getLifecycleState() : Lifecycle.State {
+ return this.lifecycle.getState()
+ }
+
+ override fun onDetachedFromWindow() {
+ lifecycle.onDetachedFromWindow()
+ super.onDetachedFromWindow();
+ }
+
+ override fun onDestroy() {
+ removeAllFeaturesFromMap(RemovalReason.ON_DESTROY)
+ viewAnnotationManager.removeAllViewAnnotations()
+ mLocationComponentManager?.onDestroy();
+
+ lifecycle.onDestroy()
+ super.onDestroy()
+ }
+
+ fun onDropViewInstance() {
+ removeAllFeaturesFromMap(RemovalReason.ON_DESTROY)
+ viewAnnotationManager.removeAllViewAnnotations()
+ lifecycle.onDestroy()
+ }
+
+ override fun onAttachedToWindow() {
+ lifecycle.onAttachedToWindow(this)
+ super.onAttachedToWindow()
+ }
+
+
+ // endregion
+}
+
+fun OrnamentSettings.setPosAndMargins(posAndMargins: ReadableMap?) {
+ if (posAndMargins == null) { return }
+
+ val bottom_mask = 2;
+ val right_mask = 1;
+
+ var margins = WritableNativeMap()
+ var position = 0;
+ if (posAndMargins
+ .hasKey("bottom")) {
+ margins.putInt("y", posAndMargins.getInt("bottom"))
+ position = position or bottom_mask
+ } else {
+ if (posAndMargins.hasKey("top")) {
+ margins.putInt("y", posAndMargins.getInt("top"))
+ }
+ }
+
+ if (posAndMargins.hasKey("left")) {
+ margins.putInt("x", posAndMargins.getInt("left"))
+ } else {
+ if (posAndMargins.hasKey("right")) {
+ position = position or right_mask
+ margins.putInt("x", posAndMargins.getInt("right"))
+ }
+ }
+ this.position = position
+ this.margins = margins
+}
+
+interface GenericOrnamentSettings {
+ fun setHMargins(left: Float?, right: Float?)
+ fun setVMargins(top: Float?, bottom: Float?)
+ var enabled: Boolean
+ var position: Int
+}
+
+fun ScaleBarSettings.toGenericOrnamentSettings() = object : GenericOrnamentSettings {
+ private val settings = this@toGenericOrnamentSettings
+ override fun setHMargins(left: Float?, right: Float?) {
+ left?.let { settings.marginLeft = it }
+ right?.let { settings.marginRight = it }
+ }
+ override fun setVMargins(top: Float?, bottom: Float?) {
+ top?.let { settings.marginTop = it }
+ bottom?.let { settings.marginBottom = it }
+ }
+ override var enabled: Boolean
+ get() = settings.enabled
+ set(value) { settings.enabled = value }
+ override var position: Int
+ get() = settings.position
+ set(value) { settings.position = value }
+}
+
+fun CompassSettings.toGenericOrnamentSettings() = object : GenericOrnamentSettings {
+ private var settings = this@toGenericOrnamentSettings
+ override fun setHMargins(left: Float?, right: Float?) {
+ left?.let { settings.marginLeft = it }
+ right?.let { settings.marginRight = it }
+ }
+ override fun setVMargins(top: Float?, bottom: Float?) {
+ top?.let { settings.marginTop = it }
+ bottom?.let { settings.marginBottom = it }
+ }
+ override var enabled: Boolean
+ get() = settings.enabled
+ set(value) { settings.enabled = value }
+ override var position: Int
+ get() = settings.position
+ set(value) {
+ settings.position = value
+ }
+}
+
+fun LogoSettings.toGenericOrnamentSettings() = object : GenericOrnamentSettings {
+ private var settings = this@toGenericOrnamentSettings
+ override fun setHMargins(left: Float?, right: Float?) {
+ left?.let { settings.marginLeft = it }
+ right?.let { settings.marginRight = it }
+ }
+ override fun setVMargins(top: Float?, bottom: Float?) {
+ top?.let { settings.marginTop = it }
+ bottom?.let { settings.marginBottom = it }
+ }
+ override var enabled: Boolean
+ get() = settings.enabled
+ set(value) { settings.enabled = value }
+ override var position: Int
+ get() = settings.position
+ set(value) {
+ settings.position = value
+ }
+}
+
+fun AttributionSettings.toGenericOrnamentSettings() = object : GenericOrnamentSettings {
+ private var settings = this@toGenericOrnamentSettings;
+ override fun setHMargins(left: Float?, right: Float?) {
+ left?.let { settings.marginLeft = it }
+ right?.let { settings.marginRight = it }
+ }
+ override fun setVMargins(top: Float?, bottom: Float?) {
+ top?.let { settings.marginTop = it }
+ bottom?.let { settings.marginBottom = it }
+ }
+ override var enabled: Boolean
+ get() = settings.enabled
+ set(value) { settings.enabled = value }
+ override var position: Int
+ get() = settings.position
+ set(value) {
+ settings.position = value
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt
new file mode 100644
index 000000000..f406ec63f
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/RCTMGLMapViewManager.kt
@@ -0,0 +1,389 @@
+package com.mapbox.rctmgl.components.mapview
+
+import android.util.Log
+import android.view.View
+import com.facebook.react.bridge.*
+
+import com.mapbox.rctmgl.components.AbstractEventEmitter
+import com.facebook.react.uimanager.LayoutShadowNode
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.mapbox.rctmgl.events.constants.EventKeys
+import com.mapbox.maps.MapboxMap
+import com.facebook.react.common.MapBuilder
+import com.mapbox.maps.extension.style.layers.properties.generated.ProjectionName
+import com.mapbox.maps.plugin.compass.compass
+import com.mapbox.maps.plugin.gestures.gestures
+import com.mapbox.maps.plugin.logo.logo
+import com.mapbox.rctmgl.utils.ConvertUtils
+import com.mapbox.rctmgl.utils.ExpressionParser
+import com.mapbox.rctmgl.utils.GeoJSONUtils
+import com.mapbox.rctmgl.utils.extensions.toCoordinate
+import com.mapbox.rctmgl.utils.extensions.toScreenCoordinate
+import java.lang.Exception
+import java.util.HashMap
+
+fun ReadableArray.forEachString(action: (String) -> Unit) {
+ for (i in 0 until size()) {
+ action(getString(i))
+ }
+}
+
+fun ReadableArray.asArrayString(): Array {
+ val result = Array(size()) {
+ getString(it)
+ }
+ return result
+}
+
+open class RCTMGLMapViewManager(context: ReactApplicationContext) :
+ AbstractEventEmitter(context) {
+ private val mViews: MutableMap
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createShadowNodeInstance(): LayoutShadowNode {
+ return MapShadowNode(this)
+ }
+
+ override fun getShadowNodeClass(): Class {
+ return MapShadowNode::class.java
+ }
+
+ override fun onAfterUpdateTransaction(mapView: RCTMGLMapView) {
+ super.onAfterUpdateTransaction(mapView)
+ if (mapView.getMapboxMap() == null) {
+ mViews[mapView.id] = mapView
+ mapView.init()
+ }
+ }
+
+ override fun addView(mapView: RCTMGLMapView?, childView: View?, childPosition: Int) {
+ mapView!!.addFeature(childView, childPosition)
+ }
+
+ override fun getChildCount(mapView: RCTMGLMapView?): Int {
+ return mapView!!.featureCount
+ }
+
+ override fun getChildAt(mapView: RCTMGLMapView?, index: Int): View? {
+ return mapView!!.getFeatureAt(index)
+ }
+
+ override fun removeViewAt(mapView: RCTMGLMapView?, index: Int) {
+ mapView!!.removeFeatureAt(index)
+ }
+
+ override fun createViewInstance(themedReactContext: ThemedReactContext): RCTMGLMapView {
+ val context = activity ?: themedReactContext
+ return RCTMGLMapView(context, this /*, null*/)
+ }
+
+ override fun onDropViewInstance(mapView: RCTMGLMapView) {
+ val reactTag = mapView.id
+ if (mViews.containsKey(reactTag)) {
+ mViews.remove(reactTag)
+ }
+ mapView.onDropViewInstance()
+ super.onDropViewInstance(mapView)
+ }
+
+ fun getByReactTag(reactTag: Int): RCTMGLMapView? {
+ return mViews[reactTag]
+ }
+
+ // region React Props
+ @ReactProp(name = "projection")
+ fun setProjection(mapView: RCTMGLMapView, projection: String?) {
+ mapView.setReactProjection( if (projection == "globe") ProjectionName.GLOBE else ProjectionName.MERCATOR )
+ }
+
+ @ReactProp(name = "localizeLabels")
+ fun setLocalizeLabels(mapView: RCTMGLMapView, localeMap: ReadableMap?) {
+ val locale = localeMap?.getString("locale")
+ val layerIds = localeMap?.getArray("layerIds")?.toArrayList()?.mapNotNull {it?.toString()}
+ mapView.setReactLocalizeLabels(locale, layerIds)
+ }
+
+ @ReactProp(name = "styleURL")
+ fun setStyleURL(mapView: RCTMGLMapView, styleURL: String?) {
+ mapView.setReactStyleURL(styleURL!!)
+ }
+
+ @ReactProp(name = "preferredFramesPerSecond")
+ fun setPreferredFramesPerSecond(mapView: RCTMGLMapView?, preferredFramesPerSecond: Int) {
+ //mapView.setReactPreferredFramesPerSecond(preferredFramesPerSecond);
+ }
+
+ @ReactProp(name = "zoomEnabled")
+ fun setZoomEnabled(mapView: RCTMGLMapView, zoomEnabled: Boolean) {
+ mapView.gestures.pinchToZoomEnabled = zoomEnabled
+ mapView.gestures.doubleTouchToZoomOutEnabled = zoomEnabled
+ mapView.gestures.doubleTapToZoomInEnabled = zoomEnabled
+ }
+
+ @ReactProp(name = "scrollEnabled")
+ fun setScrollEnabled(mapView: RCTMGLMapView, scrollEnabled: Boolean) {
+ mapView.gestures.scrollEnabled = scrollEnabled
+ }
+
+ @ReactProp(name = "pitchEnabled")
+ fun setPitchEnabled(mapView: RCTMGLMapView, pitchEnabled: Boolean) {
+ mapView.gestures.pitchEnabled = pitchEnabled
+ }
+
+ @ReactProp(name = "rotateEnabled")
+ fun setRotateEnabled(mapView: RCTMGLMapView, rotateEnabled: Boolean) {
+ mapView.gestures.rotateEnabled = rotateEnabled
+ }
+
+ @ReactProp(name = "attributionEnabled")
+ fun setAttributionEnabled(mapView: RCTMGLMapView?, attributionEnabled: Boolean?) {
+ mapView!!.setReactAttributionEnabled(attributionEnabled);
+ }
+
+ @ReactProp(name = "attributionPosition")
+ fun setAttributionPosition(mapView: RCTMGLMapView?, attributionPosition: ReadableMap?) {
+ mapView!!.setReactAttributionPosition(attributionPosition);
+ }
+
+ @ReactProp(name = "attributionViewMargins")
+ fun setAttributionViewMargins(mapView: RCTMGLMapView?, scaleBarMargins: ReadableMap?) {
+ mapView!!.setReactAttributionViewMargins(scaleBarMargins!!);
+ }
+
+ @ReactProp(name = "attributionViewPosition")
+ fun setAttributionViewPosition(mapView: RCTMGLMapView?, scaleBarPosition: Int) {
+ mapView!!.setReactAttributionViewPosition(scaleBarPosition!!)
+ }
+
+ @ReactProp(name = "logoEnabled")
+ fun setLogoEnabled(mapView: RCTMGLMapView?, logoEnabled: Boolean?) {
+ mapView!!.setReactLogoEnabled(logoEnabled);
+ }
+
+ @ReactProp(name = "logoPosition")
+ fun setLogoPosition(mapView: RCTMGLMapView?, logoPosition: ReadableMap?) {
+ mapView!!.setReactLogoPosition(logoPosition);
+ }
+
+ @ReactProp(name = "scaleBarEnabled")
+ fun setScaleBarEnabled(mapView: RCTMGLMapView?, scaleBarEnabled: Boolean) {
+ mapView!!.setReactScaleBarEnabled(scaleBarEnabled);
+ }
+
+ @ReactProp(name = "scaleBarViewMargins")
+ fun setScaleBarViewMargins(mapView: RCTMGLMapView?, scaleBarMargins: ReadableMap?) {
+ mapView!!.setReactScaleBarViewMargins(scaleBarMargins!!);
+ }
+
+ @ReactProp(name = "scaleBarViewPosition")
+ fun setScaleBarViewPosition(mapView: RCTMGLMapView?, scaleBarPosition: Int) {
+ mapView!!.setReactScaleBarViewPosition(scaleBarPosition!!)
+ }
+
+ @ReactProp(name = "scaleBarPosition")
+ fun scaleBarViewPosition(mapView: RCTMGLMapView?, scaleBarPosition: ReadableMap) {
+ mapView!!.setReactScaleBarPosition(scaleBarPosition)
+ }
+
+ @ReactProp(name = "compassEnabled")
+ fun setCompassEnabled(mapView: RCTMGLMapView?, compassEnabled: Boolean) {
+ mapView!!.setReactCompassEnabled(compassEnabled);
+ }
+
+ @ReactProp(name = "compassFadeWhenNorth")
+ fun setCompassFadeWhenNorth(mapView: RCTMGLMapView?, compassFadeWhenNorth: Boolean) {
+ mapView!!.setReactCompassFadeWhenNorth(compassFadeWhenNorth!!);
+ }
+
+ @ReactProp(name = "compassViewMargins")
+ fun setCompassViewMargins(mapView: RCTMGLMapView?, compassViewMargins: ReadableMap?) {
+ mapView!!.setReactCompassViewMargins(compassViewMargins!!);
+ }
+
+ @ReactProp(name = "compassViewPosition")
+ fun setCompassViewPosition(mapView: RCTMGLMapView?, compassViewPosition: Int) {
+ mapView!!.setReactCompassViewPosition(compassViewPosition!!)
+ }
+
+ @ReactProp(name = "compassPosition")
+ fun setCompassPosition(mapView: RCTMGLMapView?, compassMargins: ReadableMap) {
+ mapView!!.setReactCompassPosition(compassMargins)
+ }
+
+ @ReactProp(name = "contentInset")
+ fun setContentInset(mapView: RCTMGLMapView?, array: ReadableArray?) {
+ //mapView.setReactContentInset(array);
+ }
+
+ @ReactProp(name = "tintColor", customType = "Color")
+ fun setTintColor(mapView: RCTMGLMapView?, tintColor: Int?) {
+ //mapView.setTintColor(tintColor);
+ }
+
+ //endregion
+ //region Custom Events
+ override fun customEvents(): Map? {
+ return MapBuilder.builder()
+ .put(EventKeys.MAP_CLICK, "onPress")
+ .put(EventKeys.MAP_LONG_CLICK, "onLongPress")
+ .put(EventKeys.MAP_ONCHANGE, "onMapChange")
+ .put(EventKeys.MAP_ON_LOCATION_CHANGE, "onLocationChange")
+ .put(EventKeys.MAP_USER_TRACKING_MODE_CHANGE, "onUserTrackingModeChange")
+ .put(EventKeys.MAP_ANDROID_CALLBACK, "onAndroidCallback")
+ .build()
+ }
+
+ override fun getCommandsMap(): Map? {
+ return MapBuilder.builder()
+ .put("queryRenderedFeaturesAtPoint", METHOD_QUERY_FEATURES_POINT)
+ .put("queryRenderedFeaturesInRect", METHOD_QUERY_FEATURES_RECT)
+ .put("getVisibleBounds", METHOD_VISIBLE_BOUNDS)
+ .put("getPointInView", METHOD_GET_POINT_IN_VIEW)
+ .put("getCoordinateFromView", METHOD_GET_COORDINATE_FROM_VIEW)
+ .put("takeSnap", METHOD_TAKE_SNAP)
+ .put("getZoom", METHOD_GET_ZOOM)
+ .put("getCenter", METHOD_GET_CENTER)
+ .put("setHandledMapChangedEvents", METHOD_SET_HANDLED_MAP_EVENTS)
+ .put("showAttribution", METHOD_SHOW_ATTRIBUTION)
+ .put("setSourceVisibility", METHOD_SET_SOURCE_VISIBILITY)
+ .put("queryTerrainElevation", METHOD_QUERY_TERRAIN_ELEVATION)
+ .build()
+ }
+
+ override fun receiveCommand(mapView: RCTMGLMapView, commandID: Int, args: ReadableArray?) {
+ // allows method calls to work with componentDidMount
+ val mapboxMap = mapView.getMapboxMap()
+ ?: // mapView.enqueuePreRenderMapMethod(commandID, args);
+ return
+ when (commandID) {
+ METHOD_QUERY_TERRAIN_ELEVATION -> {
+ val coords = args!!.getArray(1)
+ mapView.queryTerrainElevation(
+ args.getString(0),
+ coords.getDouble(0),
+ coords.getDouble(1)
+ )
+ }
+ METHOD_GET_ZOOM -> {
+ mapView.getZoom(args!!.getString(0));
+ }
+ METHOD_GET_CENTER -> {
+ mapView.getCenter(args!!.getString(0));
+ }
+ METHOD_GET_POINT_IN_VIEW -> {
+ mapView.getPointInView(args!!.getString(0), args.getArray(1).toCoordinate())
+ }
+ METHOD_GET_COORDINATE_FROM_VIEW -> {
+ mapView.getCoordinateFromView(args!!.getString(0), args.getArray(1).toScreenCoordinate());
+ }
+ METHOD_SET_SOURCE_VISIBILITY -> {
+ mapView!!.setSourceVisibility(
+ args!!.getBoolean(1),
+ args!!.getString(2),
+ args!!.getString(3)
+ );
+ }
+ METHOD_QUERY_FEATURES_POINT -> {
+ mapView.queryRenderedFeaturesAtPoint(
+ args!!.getString(0),
+ ConvertUtils.toPointF(args!!.getArray(1)),
+ ExpressionParser.from(args!!.getArray(2)),
+ ConvertUtils.toStringList(args!!.getArray(3))
+ );
+ }
+ METHOD_QUERY_FEATURES_RECT -> {
+ val layerIds = ConvertUtils.toStringList(args!!.getArray(3))
+ mapView.queryRenderedFeaturesInRect(
+ args!!.getString(0),
+ ConvertUtils.toRectF(args.getArray(1)),
+ ExpressionParser.from(args!!.getArray(2)),
+ if (layerIds.size == 0) null else layerIds
+ );
+ }
+ METHOD_VISIBLE_BOUNDS -> {
+ mapView.getVisibleBounds(args!!.getString(0));
+ }
+ METHOD_TAKE_SNAP -> {
+ mapView.takeSnap(args!!.getString(0), args!!.getBoolean(1))
+ }
+ METHOD_SET_HANDLED_MAP_EVENTS -> {
+ args?.let {
+ mapView.setHandledMapChangedEvents(it.getArray(1).asArrayString());
+ }
+ }
+ }
+ /*
+ switch (commandID) {
+ case METHOD_TAKE_SNAP:
+ mapView.takeSnap(args.getString(0), args.getBoolean(1));
+ break;
+ case METHOD_SET_HANDLED_MAP_EVENTS:
+ if(args != null) {
+ ArrayList eventsArray = new ArrayList<>();
+ for (int i = 1; i < args.size(); i++) {
+ eventsArray.add(args.getString(i));
+ }
+ mapView.setHandledMapChangedEvents(eventsArray);
+ }
+ break;
+ case METHOD_SHOW_ATTRIBUTION:
+ mapView.showAttribution();
+ break;
+
+
+ }*/
+ }
+ //endregion
+
+ private class MapShadowNode(private val mViewManager: RCTMGLMapViewManager) :
+ LayoutShadowNode() {
+ override fun dispose() {
+ super.dispose()
+ diposeNativeMapView()
+ }
+
+ /**
+ * We need this mapview to dispose (calls into nativeMap.destroy) before ReactNative starts tearing down the views in
+ * onDropViewInstance.
+ */
+ private fun diposeNativeMapView() {
+ val mapView = mViewManager.getByReactTag(reactTag)
+ if (mapView != null) {
+ UiThreadUtil.runOnUiThread {
+ try {
+// mapView.dispose();
+ } catch (ex: Exception) {
+ Log.e(LOG_TAG, " disposeNativeMapView() exception destroying map view", ex)
+ }
+ }
+ }
+ }
+ }
+
+ companion object {
+ const val LOG_TAG = "RCTMGLMapViewManager"
+ const val REACT_CLASS = "RCTMGLMapView"
+
+ //endregion
+ //region React Methods
+ const val METHOD_QUERY_FEATURES_POINT = 2
+ const val METHOD_QUERY_FEATURES_RECT = 3
+ const val METHOD_VISIBLE_BOUNDS = 4
+ const val METHOD_GET_POINT_IN_VIEW = 5
+ const val METHOD_GET_COORDINATE_FROM_VIEW = 6
+ const val METHOD_TAKE_SNAP = 7
+ const val METHOD_GET_ZOOM = 8
+ const val METHOD_GET_CENTER = 9
+ const val METHOD_SET_HANDLED_MAP_EVENTS = 10
+ const val METHOD_SHOW_ATTRIBUTION = 11
+ const val METHOD_SET_SOURCE_VISIBILITY = 12
+ const val METHOD_QUERY_TERRAIN_ELEVATION = 13
+ }
+
+ init {
+ mViews = HashMap()
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/helpers/CameraChangeTracker.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/helpers/CameraChangeTracker.kt
new file mode 100644
index 000000000..b70e66b6c
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/mapview/helpers/CameraChangeTracker.kt
@@ -0,0 +1,23 @@
+package com.mapbox.rctmgl.components.mapview.helpers
+
+enum class CameraChangeReason {
+ NONE,
+ USER_GESTURE,
+ DEVELOPER_ANIMATION,
+ SDK_ANIMATION
+}
+
+class CameraChangeTracker {
+ private var reason : CameraChangeReason = CameraChangeReason.NONE
+ var isAnimating = false
+ fun setReason(reason: CameraChangeReason) {
+ this.reason = reason
+ }
+
+ val isUserInteraction: Boolean
+ get() = reason == CameraChangeReason.USER_GESTURE || reason == CameraChangeReason.DEVELOPER_ANIMATION
+ val isAnimated: Boolean
+ get() = reason == CameraChangeReason.DEVELOPER_ANIMATION || reason == CameraChangeReason.SDK_ANIMATION
+ val isEmpty: Boolean
+ get() = reason == CameraChangeReason.NONE
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyle.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyle.kt
new file mode 100644
index 000000000..d4632e799
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyle.kt
@@ -0,0 +1,68 @@
+package com.mapbox.rctmgl.components.styles
+
+import android.content.Context
+import com.facebook.react.bridge.ReadableMap
+import com.mapbox.maps.MapboxMap
+import com.mapbox.rctmgl.utils.ImageEntry
+import com.mapbox.rctmgl.utils.DownloadMapImageTask
+import com.mapbox.rctmgl.utils.Logger
+import java.util.AbstractMap
+import java.util.ArrayList
+
+class RCTMGLStyle(private val mContext: Context, reactStyle: ReadableMap?, map: MapboxMap) {
+ private val mReactStyle: ReadableMap?
+ private val mMap: MapboxMap
+ val allStyleKeys: List
+ get() {
+ if (mReactStyle == null) {
+ return ArrayList()
+ }
+ val it = mReactStyle.keySetIterator()
+ val keys: MutableList = ArrayList()
+ while (it.hasNextKey()) {
+ val key = it.nextKey()
+ if (key != "__MAPBOX_STYLESHEET__") {
+ keys.add(key)
+ }
+ }
+ return keys
+ }
+
+ fun getStyleValueForKey(styleKey: String?): RCTMGLStyleValue? {
+ val styleValueConfig = mReactStyle!!.getMap(styleKey!!)
+ ?: // TODO: throw exeception here
+ return null
+ return RCTMGLStyleValue(styleValueConfig)
+ }
+
+ fun imageEntry(styleValue: RCTMGLStyleValue): ImageEntry {
+ return ImageEntry(styleValue.imageURI, styleValue.imageScale)
+ }
+
+ @JvmOverloads
+ fun addImage(styleValue: RCTMGLStyleValue, styleKey: String, callback: DownloadMapImageTask.OnAllImagesLoaded? = null) {
+ if (!styleValue.shouldAddImage()) {
+ callback?.onAllImagesLoaded()
+ return
+ }
+ Logger.w(LOG_TAG,"Deprecated: Image in style is deprecated, use images component instead. key: $styleKey [image-in-style-deprecated]")
+ val uriStr = styleValue.imageURI
+ val images = arrayOf>(
+ AbstractMap.SimpleEntry(
+ uriStr,
+ imageEntry(styleValue)
+ )
+ )
+ val task = DownloadMapImageTask(mContext, mMap, callback)
+ task.execute(*images)
+ }
+
+ init {
+ mReactStyle = reactStyle
+ mMap = map
+ }
+
+ companion object {
+ const val LOG_TAG = "RCTMGLStyle"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java
new file mode 100644
index 000000000..2a8ee3307
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyleFactory.java
@@ -0,0 +1,2586 @@
+// DO NOT MODIFY
+// THIS FILE IS AUTOGENERATED
+
+package com.mapbox.rctmgl.components.styles;
+
+import com.mapbox.maps.extension.style.expressions.generated.Expression;
+import com.mapbox.maps.extension.style.layers.generated.BackgroundLayer;
+import com.mapbox.maps.extension.style.layers.generated.CircleLayer;
+import com.mapbox.maps.extension.style.layers.generated.FillExtrusionLayer;
+import com.mapbox.maps.extension.style.layers.generated.FillLayer;
+import com.mapbox.maps.extension.style.layers.generated.LineLayer;
+import com.mapbox.maps.extension.style.layers.generated.SkyLayer;
+// import com.mapbox.maps.extension.style.layers.generated.PropertyFactory;
+// import com.mapbox.maps.extension.style.layers.generated.PropertyValue;
+import com.mapbox.maps.extension.style.layers.generated.RasterLayer;
+import com.mapbox.maps.extension.style.layers.generated.SymbolLayer;
+import com.mapbox.maps.extension.style.layers.generated.HeatmapLayer;
+import com.mapbox.maps.extension.style.layers.generated.HillshadeLayer;
+import com.mapbox.maps.extension.style.atmosphere.generated.Atmosphere;
+import com.mapbox.maps.extension.style.terrain.generated.Terrain;
+// import com.mapbox.maps.extension.style.layers.properties.generated.Visibility;
+import com.mapbox.maps.extension.style.layers.properties.generated.*;
+import com.mapbox.maps.extension.style.types.StyleTransition;
+import com.mapbox.maps.extension.style.light.generated.Light;
+import com.mapbox.maps.extension.style.light.LightPosition;
+import com.mapbox.rctmgl.utils.DownloadMapImageTask;
+import com.mapbox.rctmgl.utils.Logger;
+
+import java.util.List;
+
+public class RCTMGLStyleFactory {
+ public static final String VALUE_KEY = "value";
+ public static final String SHOULD_ADD_IMAGE_KEY = "shouldAddImage";
+
+ public static void setFillLayerStyle(final FillLayer layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "fillSortKey":
+ RCTMGLStyleFactory.setFillSortKey(layer, styleValue);
+ break;
+ case "visibility":
+ RCTMGLStyleFactory.setVisibility(layer, styleValue);
+ break;
+ case "fillAntialias":
+ RCTMGLStyleFactory.setFillAntialias(layer, styleValue);
+ break;
+ case "fillOpacity":
+ RCTMGLStyleFactory.setFillOpacity(layer, styleValue);
+ break;
+ case "fillOpacityTransition":
+ RCTMGLStyleFactory.setFillOpacityTransition(layer, styleValue);
+ break;
+ case "fillColor":
+ RCTMGLStyleFactory.setFillColor(layer, styleValue);
+ break;
+ case "fillColorTransition":
+ RCTMGLStyleFactory.setFillColorTransition(layer, styleValue);
+ break;
+ case "fillOutlineColor":
+ RCTMGLStyleFactory.setFillOutlineColor(layer, styleValue);
+ break;
+ case "fillOutlineColorTransition":
+ RCTMGLStyleFactory.setFillOutlineColorTransition(layer, styleValue);
+ break;
+ case "fillTranslate":
+ RCTMGLStyleFactory.setFillTranslate(layer, styleValue);
+ break;
+ case "fillTranslateTransition":
+ RCTMGLStyleFactory.setFillTranslateTransition(layer, styleValue);
+ break;
+ case "fillTranslateAnchor":
+ RCTMGLStyleFactory.setFillTranslateAnchor(layer, styleValue);
+ break;
+ case "fillPattern":
+ style.addImage(styleValue, styleKey, new DownloadMapImageTask.OnAllImagesLoaded() {
+ @Override
+ public void onAllImagesLoaded() {
+ try {
+ RCTMGLStyleFactory.setFillPattern(layer, styleValue);
+ } catch (RuntimeException exception) {
+ Logger.INSTANCE.e("RCTMGLFill",String.format("Exception failed during setFillPattern: %s", exception.getMessage()));
+ }
+ }
+ });
+ break;
+ }
+ }
+ }
+ public static void setLineLayerStyle(final LineLayer layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "lineCap":
+ RCTMGLStyleFactory.setLineCap(layer, styleValue);
+ break;
+ case "lineJoin":
+ RCTMGLStyleFactory.setLineJoin(layer, styleValue);
+ break;
+ case "lineMiterLimit":
+ RCTMGLStyleFactory.setLineMiterLimit(layer, styleValue);
+ break;
+ case "lineRoundLimit":
+ RCTMGLStyleFactory.setLineRoundLimit(layer, styleValue);
+ break;
+ case "lineSortKey":
+ RCTMGLStyleFactory.setLineSortKey(layer, styleValue);
+ break;
+ case "visibility":
+ RCTMGLStyleFactory.setVisibility(layer, styleValue);
+ break;
+ case "lineOpacity":
+ RCTMGLStyleFactory.setLineOpacity(layer, styleValue);
+ break;
+ case "lineOpacityTransition":
+ RCTMGLStyleFactory.setLineOpacityTransition(layer, styleValue);
+ break;
+ case "lineColor":
+ RCTMGLStyleFactory.setLineColor(layer, styleValue);
+ break;
+ case "lineColorTransition":
+ RCTMGLStyleFactory.setLineColorTransition(layer, styleValue);
+ break;
+ case "lineTranslate":
+ RCTMGLStyleFactory.setLineTranslate(layer, styleValue);
+ break;
+ case "lineTranslateTransition":
+ RCTMGLStyleFactory.setLineTranslateTransition(layer, styleValue);
+ break;
+ case "lineTranslateAnchor":
+ RCTMGLStyleFactory.setLineTranslateAnchor(layer, styleValue);
+ break;
+ case "lineWidth":
+ RCTMGLStyleFactory.setLineWidth(layer, styleValue);
+ break;
+ case "lineWidthTransition":
+ RCTMGLStyleFactory.setLineWidthTransition(layer, styleValue);
+ break;
+ case "lineGapWidth":
+ RCTMGLStyleFactory.setLineGapWidth(layer, styleValue);
+ break;
+ case "lineGapWidthTransition":
+ RCTMGLStyleFactory.setLineGapWidthTransition(layer, styleValue);
+ break;
+ case "lineOffset":
+ RCTMGLStyleFactory.setLineOffset(layer, styleValue);
+ break;
+ case "lineOffsetTransition":
+ RCTMGLStyleFactory.setLineOffsetTransition(layer, styleValue);
+ break;
+ case "lineBlur":
+ RCTMGLStyleFactory.setLineBlur(layer, styleValue);
+ break;
+ case "lineBlurTransition":
+ RCTMGLStyleFactory.setLineBlurTransition(layer, styleValue);
+ break;
+ case "lineDasharray":
+ RCTMGLStyleFactory.setLineDasharray(layer, styleValue);
+ break;
+ case "linePattern":
+ style.addImage(styleValue, styleKey, new DownloadMapImageTask.OnAllImagesLoaded() {
+ @Override
+ public void onAllImagesLoaded() {
+ try {
+ RCTMGLStyleFactory.setLinePattern(layer, styleValue);
+ } catch (RuntimeException exception) {
+ Logger.INSTANCE.e("RCTMGLLine",String.format("Exception failed during setLinePattern: %s", exception.getMessage()));
+ }
+ }
+ });
+ break;
+ case "lineGradient":
+ RCTMGLStyleFactory.setLineGradient(layer, styleValue);
+ break;
+ case "lineTrimOffset":
+ RCTMGLStyleFactory.setLineTrimOffset(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setSymbolLayerStyle(final SymbolLayer layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "symbolPlacement":
+ RCTMGLStyleFactory.setSymbolPlacement(layer, styleValue);
+ break;
+ case "symbolSpacing":
+ RCTMGLStyleFactory.setSymbolSpacing(layer, styleValue);
+ break;
+ case "symbolAvoidEdges":
+ RCTMGLStyleFactory.setSymbolAvoidEdges(layer, styleValue);
+ break;
+ case "symbolSortKey":
+ RCTMGLStyleFactory.setSymbolSortKey(layer, styleValue);
+ break;
+ case "symbolZOrder":
+ RCTMGLStyleFactory.setSymbolZOrder(layer, styleValue);
+ break;
+ case "iconAllowOverlap":
+ RCTMGLStyleFactory.setIconAllowOverlap(layer, styleValue);
+ break;
+ case "iconIgnorePlacement":
+ RCTMGLStyleFactory.setIconIgnorePlacement(layer, styleValue);
+ break;
+ case "iconOptional":
+ RCTMGLStyleFactory.setIconOptional(layer, styleValue);
+ break;
+ case "iconRotationAlignment":
+ RCTMGLStyleFactory.setIconRotationAlignment(layer, styleValue);
+ break;
+ case "iconSize":
+ RCTMGLStyleFactory.setIconSize(layer, styleValue);
+ break;
+ case "iconTextFit":
+ RCTMGLStyleFactory.setIconTextFit(layer, styleValue);
+ break;
+ case "iconTextFitPadding":
+ RCTMGLStyleFactory.setIconTextFitPadding(layer, styleValue);
+ break;
+ case "iconImage":
+ style.addImage(styleValue, styleKey, new DownloadMapImageTask.OnAllImagesLoaded() {
+ @Override
+ public void onAllImagesLoaded() {
+ try {
+ RCTMGLStyleFactory.setIconImage(layer, styleValue);
+ } catch (RuntimeException exception) {
+ Logger.INSTANCE.e("RCTMGLSymbol",String.format("Exception failed during setIconImage: %s", exception.getMessage()));
+ }
+ }
+ });
+ break;
+ case "iconRotate":
+ RCTMGLStyleFactory.setIconRotate(layer, styleValue);
+ break;
+ case "iconPadding":
+ RCTMGLStyleFactory.setIconPadding(layer, styleValue);
+ break;
+ case "iconKeepUpright":
+ RCTMGLStyleFactory.setIconKeepUpright(layer, styleValue);
+ break;
+ case "iconOffset":
+ RCTMGLStyleFactory.setIconOffset(layer, styleValue);
+ break;
+ case "iconAnchor":
+ RCTMGLStyleFactory.setIconAnchor(layer, styleValue);
+ break;
+ case "iconPitchAlignment":
+ RCTMGLStyleFactory.setIconPitchAlignment(layer, styleValue);
+ break;
+ case "textPitchAlignment":
+ RCTMGLStyleFactory.setTextPitchAlignment(layer, styleValue);
+ break;
+ case "textRotationAlignment":
+ RCTMGLStyleFactory.setTextRotationAlignment(layer, styleValue);
+ break;
+ case "textField":
+ RCTMGLStyleFactory.setTextField(layer, styleValue);
+ break;
+ case "textFont":
+ RCTMGLStyleFactory.setTextFont(layer, styleValue);
+ break;
+ case "textSize":
+ RCTMGLStyleFactory.setTextSize(layer, styleValue);
+ break;
+ case "textMaxWidth":
+ RCTMGLStyleFactory.setTextMaxWidth(layer, styleValue);
+ break;
+ case "textLineHeight":
+ RCTMGLStyleFactory.setTextLineHeight(layer, styleValue);
+ break;
+ case "textLetterSpacing":
+ RCTMGLStyleFactory.setTextLetterSpacing(layer, styleValue);
+ break;
+ case "textJustify":
+ RCTMGLStyleFactory.setTextJustify(layer, styleValue);
+ break;
+ case "textRadialOffset":
+ RCTMGLStyleFactory.setTextRadialOffset(layer, styleValue);
+ break;
+ case "textVariableAnchor":
+ RCTMGLStyleFactory.setTextVariableAnchor(layer, styleValue);
+ break;
+ case "textAnchor":
+ RCTMGLStyleFactory.setTextAnchor(layer, styleValue);
+ break;
+ case "textMaxAngle":
+ RCTMGLStyleFactory.setTextMaxAngle(layer, styleValue);
+ break;
+ case "textWritingMode":
+ RCTMGLStyleFactory.setTextWritingMode(layer, styleValue);
+ break;
+ case "textRotate":
+ RCTMGLStyleFactory.setTextRotate(layer, styleValue);
+ break;
+ case "textPadding":
+ RCTMGLStyleFactory.setTextPadding(layer, styleValue);
+ break;
+ case "textKeepUpright":
+ RCTMGLStyleFactory.setTextKeepUpright(layer, styleValue);
+ break;
+ case "textTransform":
+ RCTMGLStyleFactory.setTextTransform(layer, styleValue);
+ break;
+ case "textOffset":
+ RCTMGLStyleFactory.setTextOffset(layer, styleValue);
+ break;
+ case "textAllowOverlap":
+ RCTMGLStyleFactory.setTextAllowOverlap(layer, styleValue);
+ break;
+ case "textIgnorePlacement":
+ RCTMGLStyleFactory.setTextIgnorePlacement(layer, styleValue);
+ break;
+ case "textOptional":
+ RCTMGLStyleFactory.setTextOptional(layer, styleValue);
+ break;
+ case "visibility":
+ RCTMGLStyleFactory.setVisibility(layer, styleValue);
+ break;
+ case "iconOpacity":
+ RCTMGLStyleFactory.setIconOpacity(layer, styleValue);
+ break;
+ case "iconOpacityTransition":
+ RCTMGLStyleFactory.setIconOpacityTransition(layer, styleValue);
+ break;
+ case "iconColor":
+ RCTMGLStyleFactory.setIconColor(layer, styleValue);
+ break;
+ case "iconColorTransition":
+ RCTMGLStyleFactory.setIconColorTransition(layer, styleValue);
+ break;
+ case "iconHaloColor":
+ RCTMGLStyleFactory.setIconHaloColor(layer, styleValue);
+ break;
+ case "iconHaloColorTransition":
+ RCTMGLStyleFactory.setIconHaloColorTransition(layer, styleValue);
+ break;
+ case "iconHaloWidth":
+ RCTMGLStyleFactory.setIconHaloWidth(layer, styleValue);
+ break;
+ case "iconHaloWidthTransition":
+ RCTMGLStyleFactory.setIconHaloWidthTransition(layer, styleValue);
+ break;
+ case "iconHaloBlur":
+ RCTMGLStyleFactory.setIconHaloBlur(layer, styleValue);
+ break;
+ case "iconHaloBlurTransition":
+ RCTMGLStyleFactory.setIconHaloBlurTransition(layer, styleValue);
+ break;
+ case "iconTranslate":
+ RCTMGLStyleFactory.setIconTranslate(layer, styleValue);
+ break;
+ case "iconTranslateTransition":
+ RCTMGLStyleFactory.setIconTranslateTransition(layer, styleValue);
+ break;
+ case "iconTranslateAnchor":
+ RCTMGLStyleFactory.setIconTranslateAnchor(layer, styleValue);
+ break;
+ case "textOpacity":
+ RCTMGLStyleFactory.setTextOpacity(layer, styleValue);
+ break;
+ case "textOpacityTransition":
+ RCTMGLStyleFactory.setTextOpacityTransition(layer, styleValue);
+ break;
+ case "textColor":
+ RCTMGLStyleFactory.setTextColor(layer, styleValue);
+ break;
+ case "textColorTransition":
+ RCTMGLStyleFactory.setTextColorTransition(layer, styleValue);
+ break;
+ case "textHaloColor":
+ RCTMGLStyleFactory.setTextHaloColor(layer, styleValue);
+ break;
+ case "textHaloColorTransition":
+ RCTMGLStyleFactory.setTextHaloColorTransition(layer, styleValue);
+ break;
+ case "textHaloWidth":
+ RCTMGLStyleFactory.setTextHaloWidth(layer, styleValue);
+ break;
+ case "textHaloWidthTransition":
+ RCTMGLStyleFactory.setTextHaloWidthTransition(layer, styleValue);
+ break;
+ case "textHaloBlur":
+ RCTMGLStyleFactory.setTextHaloBlur(layer, styleValue);
+ break;
+ case "textHaloBlurTransition":
+ RCTMGLStyleFactory.setTextHaloBlurTransition(layer, styleValue);
+ break;
+ case "textTranslate":
+ RCTMGLStyleFactory.setTextTranslate(layer, styleValue);
+ break;
+ case "textTranslateTransition":
+ RCTMGLStyleFactory.setTextTranslateTransition(layer, styleValue);
+ break;
+ case "textTranslateAnchor":
+ RCTMGLStyleFactory.setTextTranslateAnchor(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setCircleLayerStyle(final CircleLayer layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "circleSortKey":
+ RCTMGLStyleFactory.setCircleSortKey(layer, styleValue);
+ break;
+ case "visibility":
+ RCTMGLStyleFactory.setVisibility(layer, styleValue);
+ break;
+ case "circleRadius":
+ RCTMGLStyleFactory.setCircleRadius(layer, styleValue);
+ break;
+ case "circleRadiusTransition":
+ RCTMGLStyleFactory.setCircleRadiusTransition(layer, styleValue);
+ break;
+ case "circleColor":
+ RCTMGLStyleFactory.setCircleColor(layer, styleValue);
+ break;
+ case "circleColorTransition":
+ RCTMGLStyleFactory.setCircleColorTransition(layer, styleValue);
+ break;
+ case "circleBlur":
+ RCTMGLStyleFactory.setCircleBlur(layer, styleValue);
+ break;
+ case "circleBlurTransition":
+ RCTMGLStyleFactory.setCircleBlurTransition(layer, styleValue);
+ break;
+ case "circleOpacity":
+ RCTMGLStyleFactory.setCircleOpacity(layer, styleValue);
+ break;
+ case "circleOpacityTransition":
+ RCTMGLStyleFactory.setCircleOpacityTransition(layer, styleValue);
+ break;
+ case "circleTranslate":
+ RCTMGLStyleFactory.setCircleTranslate(layer, styleValue);
+ break;
+ case "circleTranslateTransition":
+ RCTMGLStyleFactory.setCircleTranslateTransition(layer, styleValue);
+ break;
+ case "circleTranslateAnchor":
+ RCTMGLStyleFactory.setCircleTranslateAnchor(layer, styleValue);
+ break;
+ case "circlePitchScale":
+ RCTMGLStyleFactory.setCirclePitchScale(layer, styleValue);
+ break;
+ case "circlePitchAlignment":
+ RCTMGLStyleFactory.setCirclePitchAlignment(layer, styleValue);
+ break;
+ case "circleStrokeWidth":
+ RCTMGLStyleFactory.setCircleStrokeWidth(layer, styleValue);
+ break;
+ case "circleStrokeWidthTransition":
+ RCTMGLStyleFactory.setCircleStrokeWidthTransition(layer, styleValue);
+ break;
+ case "circleStrokeColor":
+ RCTMGLStyleFactory.setCircleStrokeColor(layer, styleValue);
+ break;
+ case "circleStrokeColorTransition":
+ RCTMGLStyleFactory.setCircleStrokeColorTransition(layer, styleValue);
+ break;
+ case "circleStrokeOpacity":
+ RCTMGLStyleFactory.setCircleStrokeOpacity(layer, styleValue);
+ break;
+ case "circleStrokeOpacityTransition":
+ RCTMGLStyleFactory.setCircleStrokeOpacityTransition(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setHeatmapLayerStyle(final HeatmapLayer layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "visibility":
+ RCTMGLStyleFactory.setVisibility(layer, styleValue);
+ break;
+ case "heatmapRadius":
+ RCTMGLStyleFactory.setHeatmapRadius(layer, styleValue);
+ break;
+ case "heatmapRadiusTransition":
+ RCTMGLStyleFactory.setHeatmapRadiusTransition(layer, styleValue);
+ break;
+ case "heatmapWeight":
+ RCTMGLStyleFactory.setHeatmapWeight(layer, styleValue);
+ break;
+ case "heatmapIntensity":
+ RCTMGLStyleFactory.setHeatmapIntensity(layer, styleValue);
+ break;
+ case "heatmapIntensityTransition":
+ RCTMGLStyleFactory.setHeatmapIntensityTransition(layer, styleValue);
+ break;
+ case "heatmapColor":
+ RCTMGLStyleFactory.setHeatmapColor(layer, styleValue);
+ break;
+ case "heatmapOpacity":
+ RCTMGLStyleFactory.setHeatmapOpacity(layer, styleValue);
+ break;
+ case "heatmapOpacityTransition":
+ RCTMGLStyleFactory.setHeatmapOpacityTransition(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setFillExtrusionLayerStyle(final FillExtrusionLayer layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "visibility":
+ RCTMGLStyleFactory.setVisibility(layer, styleValue);
+ break;
+ case "fillExtrusionOpacity":
+ RCTMGLStyleFactory.setFillExtrusionOpacity(layer, styleValue);
+ break;
+ case "fillExtrusionOpacityTransition":
+ RCTMGLStyleFactory.setFillExtrusionOpacityTransition(layer, styleValue);
+ break;
+ case "fillExtrusionColor":
+ RCTMGLStyleFactory.setFillExtrusionColor(layer, styleValue);
+ break;
+ case "fillExtrusionColorTransition":
+ RCTMGLStyleFactory.setFillExtrusionColorTransition(layer, styleValue);
+ break;
+ case "fillExtrusionTranslate":
+ RCTMGLStyleFactory.setFillExtrusionTranslate(layer, styleValue);
+ break;
+ case "fillExtrusionTranslateTransition":
+ RCTMGLStyleFactory.setFillExtrusionTranslateTransition(layer, styleValue);
+ break;
+ case "fillExtrusionTranslateAnchor":
+ RCTMGLStyleFactory.setFillExtrusionTranslateAnchor(layer, styleValue);
+ break;
+ case "fillExtrusionPattern":
+ style.addImage(styleValue, styleKey, new DownloadMapImageTask.OnAllImagesLoaded() {
+ @Override
+ public void onAllImagesLoaded() {
+ try {
+ RCTMGLStyleFactory.setFillExtrusionPattern(layer, styleValue);
+ } catch (RuntimeException exception) {
+ Logger.INSTANCE.e("RCTMGLFillExtrusion",String.format("Exception failed during setFillExtrusionPattern: %s", exception.getMessage()));
+ }
+ }
+ });
+ break;
+ case "fillExtrusionHeight":
+ RCTMGLStyleFactory.setFillExtrusionHeight(layer, styleValue);
+ break;
+ case "fillExtrusionHeightTransition":
+ RCTMGLStyleFactory.setFillExtrusionHeightTransition(layer, styleValue);
+ break;
+ case "fillExtrusionBase":
+ RCTMGLStyleFactory.setFillExtrusionBase(layer, styleValue);
+ break;
+ case "fillExtrusionBaseTransition":
+ RCTMGLStyleFactory.setFillExtrusionBaseTransition(layer, styleValue);
+ break;
+ case "fillExtrusionVerticalGradient":
+ RCTMGLStyleFactory.setFillExtrusionVerticalGradient(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setRasterLayerStyle(final RasterLayer layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "visibility":
+ RCTMGLStyleFactory.setVisibility(layer, styleValue);
+ break;
+ case "rasterOpacity":
+ RCTMGLStyleFactory.setRasterOpacity(layer, styleValue);
+ break;
+ case "rasterOpacityTransition":
+ RCTMGLStyleFactory.setRasterOpacityTransition(layer, styleValue);
+ break;
+ case "rasterHueRotate":
+ RCTMGLStyleFactory.setRasterHueRotate(layer, styleValue);
+ break;
+ case "rasterHueRotateTransition":
+ RCTMGLStyleFactory.setRasterHueRotateTransition(layer, styleValue);
+ break;
+ case "rasterBrightnessMin":
+ RCTMGLStyleFactory.setRasterBrightnessMin(layer, styleValue);
+ break;
+ case "rasterBrightnessMinTransition":
+ RCTMGLStyleFactory.setRasterBrightnessMinTransition(layer, styleValue);
+ break;
+ case "rasterBrightnessMax":
+ RCTMGLStyleFactory.setRasterBrightnessMax(layer, styleValue);
+ break;
+ case "rasterBrightnessMaxTransition":
+ RCTMGLStyleFactory.setRasterBrightnessMaxTransition(layer, styleValue);
+ break;
+ case "rasterSaturation":
+ RCTMGLStyleFactory.setRasterSaturation(layer, styleValue);
+ break;
+ case "rasterSaturationTransition":
+ RCTMGLStyleFactory.setRasterSaturationTransition(layer, styleValue);
+ break;
+ case "rasterContrast":
+ RCTMGLStyleFactory.setRasterContrast(layer, styleValue);
+ break;
+ case "rasterContrastTransition":
+ RCTMGLStyleFactory.setRasterContrastTransition(layer, styleValue);
+ break;
+ case "rasterResampling":
+ RCTMGLStyleFactory.setRasterResampling(layer, styleValue);
+ break;
+ case "rasterFadeDuration":
+ RCTMGLStyleFactory.setRasterFadeDuration(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setHillshadeLayerStyle(final HillshadeLayer layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "visibility":
+ RCTMGLStyleFactory.setVisibility(layer, styleValue);
+ break;
+ case "hillshadeIlluminationDirection":
+ RCTMGLStyleFactory.setHillshadeIlluminationDirection(layer, styleValue);
+ break;
+ case "hillshadeIlluminationAnchor":
+ RCTMGLStyleFactory.setHillshadeIlluminationAnchor(layer, styleValue);
+ break;
+ case "hillshadeExaggeration":
+ RCTMGLStyleFactory.setHillshadeExaggeration(layer, styleValue);
+ break;
+ case "hillshadeExaggerationTransition":
+ RCTMGLStyleFactory.setHillshadeExaggerationTransition(layer, styleValue);
+ break;
+ case "hillshadeShadowColor":
+ RCTMGLStyleFactory.setHillshadeShadowColor(layer, styleValue);
+ break;
+ case "hillshadeShadowColorTransition":
+ RCTMGLStyleFactory.setHillshadeShadowColorTransition(layer, styleValue);
+ break;
+ case "hillshadeHighlightColor":
+ RCTMGLStyleFactory.setHillshadeHighlightColor(layer, styleValue);
+ break;
+ case "hillshadeHighlightColorTransition":
+ RCTMGLStyleFactory.setHillshadeHighlightColorTransition(layer, styleValue);
+ break;
+ case "hillshadeAccentColor":
+ RCTMGLStyleFactory.setHillshadeAccentColor(layer, styleValue);
+ break;
+ case "hillshadeAccentColorTransition":
+ RCTMGLStyleFactory.setHillshadeAccentColorTransition(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setBackgroundLayerStyle(final BackgroundLayer layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "visibility":
+ RCTMGLStyleFactory.setVisibility(layer, styleValue);
+ break;
+ case "backgroundColor":
+ RCTMGLStyleFactory.setBackgroundColor(layer, styleValue);
+ break;
+ case "backgroundColorTransition":
+ RCTMGLStyleFactory.setBackgroundColorTransition(layer, styleValue);
+ break;
+ case "backgroundPattern":
+ style.addImage(styleValue, styleKey, new DownloadMapImageTask.OnAllImagesLoaded() {
+ @Override
+ public void onAllImagesLoaded() {
+ try {
+ RCTMGLStyleFactory.setBackgroundPattern(layer, styleValue);
+ } catch (RuntimeException exception) {
+ Logger.INSTANCE.e("RCTMGLBackground",String.format("Exception failed during setBackgroundPattern: %s", exception.getMessage()));
+ }
+ }
+ });
+ break;
+ case "backgroundOpacity":
+ RCTMGLStyleFactory.setBackgroundOpacity(layer, styleValue);
+ break;
+ case "backgroundOpacityTransition":
+ RCTMGLStyleFactory.setBackgroundOpacityTransition(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setSkyLayerStyle(final SkyLayer layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "visibility":
+ RCTMGLStyleFactory.setVisibility(layer, styleValue);
+ break;
+ case "skyType":
+ RCTMGLStyleFactory.setSkyType(layer, styleValue);
+ break;
+ case "skyAtmosphereSun":
+ RCTMGLStyleFactory.setSkyAtmosphereSun(layer, styleValue);
+ break;
+ case "skyAtmosphereSunIntensity":
+ RCTMGLStyleFactory.setSkyAtmosphereSunIntensity(layer, styleValue);
+ break;
+ case "skyGradientCenter":
+ RCTMGLStyleFactory.setSkyGradientCenter(layer, styleValue);
+ break;
+ case "skyGradientRadius":
+ RCTMGLStyleFactory.setSkyGradientRadius(layer, styleValue);
+ break;
+ case "skyGradient":
+ RCTMGLStyleFactory.setSkyGradient(layer, styleValue);
+ break;
+ case "skyAtmosphereHaloColor":
+ RCTMGLStyleFactory.setSkyAtmosphereHaloColor(layer, styleValue);
+ break;
+ case "skyAtmosphereColor":
+ RCTMGLStyleFactory.setSkyAtmosphereColor(layer, styleValue);
+ break;
+ case "skyOpacity":
+ RCTMGLStyleFactory.setSkyOpacity(layer, styleValue);
+ break;
+ case "skyOpacityTransition":
+ RCTMGLStyleFactory.setSkyOpacityTransition(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setLightLayerStyle(final Light layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "anchor":
+ RCTMGLStyleFactory.setAnchor(layer, styleValue);
+ break;
+ case "position":
+ RCTMGLStyleFactory.setPosition(layer, styleValue);
+ break;
+ case "positionTransition":
+ RCTMGLStyleFactory.setPositionTransition(layer, styleValue);
+ break;
+ case "color":
+ RCTMGLStyleFactory.setColor(layer, styleValue);
+ break;
+ case "colorTransition":
+ RCTMGLStyleFactory.setColorTransition(layer, styleValue);
+ break;
+ case "intensity":
+ RCTMGLStyleFactory.setIntensity(layer, styleValue);
+ break;
+ case "intensityTransition":
+ RCTMGLStyleFactory.setIntensityTransition(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setAtmosphereLayerStyle(final Atmosphere layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "range":
+ RCTMGLStyleFactory.setRange(layer, styleValue);
+ break;
+ case "rangeTransition":
+ RCTMGLStyleFactory.setRangeTransition(layer, styleValue);
+ break;
+ case "color":
+ RCTMGLStyleFactory.setColor(layer, styleValue);
+ break;
+ case "colorTransition":
+ RCTMGLStyleFactory.setColorTransition(layer, styleValue);
+ break;
+ case "highColor":
+ RCTMGLStyleFactory.setHighColor(layer, styleValue);
+ break;
+ case "highColorTransition":
+ RCTMGLStyleFactory.setHighColorTransition(layer, styleValue);
+ break;
+ case "spaceColor":
+ RCTMGLStyleFactory.setSpaceColor(layer, styleValue);
+ break;
+ case "spaceColorTransition":
+ RCTMGLStyleFactory.setSpaceColorTransition(layer, styleValue);
+ break;
+ case "horizonBlend":
+ RCTMGLStyleFactory.setHorizonBlend(layer, styleValue);
+ break;
+ case "horizonBlendTransition":
+ RCTMGLStyleFactory.setHorizonBlendTransition(layer, styleValue);
+ break;
+ case "starIntensity":
+ RCTMGLStyleFactory.setStarIntensity(layer, styleValue);
+ break;
+ case "starIntensityTransition":
+ RCTMGLStyleFactory.setStarIntensityTransition(layer, styleValue);
+ break;
+ }
+ }
+ }
+ public static void setTerrainLayerStyle(final Terrain layer, RCTMGLStyle style) {
+ List styleKeys = style.getAllStyleKeys();
+
+ if (styleKeys.size() == 0) {
+ return;
+ }
+
+ for (String styleKey : styleKeys) {
+ final RCTMGLStyleValue styleValue = style.getStyleValueForKey(styleKey);
+
+ switch (styleKey) {
+ case "exaggeration":
+ RCTMGLStyleFactory.setExaggeration(layer, styleValue);
+ break;
+ }
+ }
+ }
+
+ public static void setFillSortKey(FillLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillSortKey(styleValue.getExpression());
+ } else {
+ layer.fillSortKey(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setVisibility(FillLayer layer, RCTMGLStyleValue styleValue) {
+ layer.visibility(Visibility.valueOf(styleValue.getEnumName()));
+ }
+
+ public static void setFillAntialias(FillLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillAntialias(styleValue.getExpression());
+ } else {
+ layer.fillAntialias(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setFillOpacity(FillLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillOpacity(styleValue.getExpression());
+ } else {
+ layer.fillOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setFillOpacityTransition(FillLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.fillOpacityTransition(transition);
+ }
+ }
+
+ public static void setFillColor(FillLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillColor(styleValue.getExpression());
+ } else {
+ layer.fillColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setFillColorTransition(FillLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.fillColorTransition(transition);
+ }
+ }
+
+ public static void setFillOutlineColor(FillLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillOutlineColor(styleValue.getExpression());
+ } else {
+ layer.fillOutlineColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setFillOutlineColorTransition(FillLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.fillOutlineColorTransition(transition);
+ }
+ }
+
+ public static void setFillTranslate(FillLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillTranslate(styleValue.getExpression());
+ } else {
+ layer.fillTranslate(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+
+ public static void setFillTranslateTransition(FillLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.fillTranslateTransition(transition);
+ }
+ }
+
+ public static void setFillTranslateAnchor(FillLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillTranslateAnchor(styleValue.getExpression());
+ } else {
+ layer.fillTranslateAnchor(FillTranslateAnchor.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setFillPattern(FillLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ if (styleValue.isImageStringValue()) {
+ layer.fillPattern(styleValue.getImageStringValue());
+ } else {
+ layer.fillPattern(styleValue.getExpression());
+ }
+ } else {
+ layer.fillPattern(styleValue.getImageURI());
+ }
+ }
+
+ public static void setLineCap(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineCap(styleValue.getExpression());
+ } else {
+ layer.lineCap(LineCap.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setLineJoin(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineJoin(styleValue.getExpression());
+ } else {
+ layer.lineJoin(LineJoin.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setLineMiterLimit(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineMiterLimit(styleValue.getExpression());
+ } else {
+ layer.lineMiterLimit(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setLineRoundLimit(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineRoundLimit(styleValue.getExpression());
+ } else {
+ layer.lineRoundLimit(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setLineSortKey(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineSortKey(styleValue.getExpression());
+ } else {
+ layer.lineSortKey(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setVisibility(LineLayer layer, RCTMGLStyleValue styleValue) {
+ layer.visibility(Visibility.valueOf(styleValue.getEnumName()));
+ }
+
+ public static void setLineOpacity(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineOpacity(styleValue.getExpression());
+ } else {
+ layer.lineOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setLineOpacityTransition(LineLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.lineOpacityTransition(transition);
+ }
+ }
+
+ public static void setLineColor(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineColor(styleValue.getExpression());
+ } else {
+ layer.lineColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setLineColorTransition(LineLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.lineColorTransition(transition);
+ }
+ }
+
+ public static void setLineTranslate(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineTranslate(styleValue.getExpression());
+ } else {
+ layer.lineTranslate(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+
+ public static void setLineTranslateTransition(LineLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.lineTranslateTransition(transition);
+ }
+ }
+
+ public static void setLineTranslateAnchor(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineTranslateAnchor(styleValue.getExpression());
+ } else {
+ layer.lineTranslateAnchor(LineTranslateAnchor.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setLineWidth(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineWidth(styleValue.getExpression());
+ } else {
+ layer.lineWidth(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setLineWidthTransition(LineLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.lineWidthTransition(transition);
+ }
+ }
+
+ public static void setLineGapWidth(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineGapWidth(styleValue.getExpression());
+ } else {
+ layer.lineGapWidth(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setLineGapWidthTransition(LineLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.lineGapWidthTransition(transition);
+ }
+ }
+
+ public static void setLineOffset(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineOffset(styleValue.getExpression());
+ } else {
+ layer.lineOffset(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setLineOffsetTransition(LineLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.lineOffsetTransition(transition);
+ }
+ }
+
+ public static void setLineBlur(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineBlur(styleValue.getExpression());
+ } else {
+ layer.lineBlur(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setLineBlurTransition(LineLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.lineBlurTransition(transition);
+ }
+ }
+
+ public static void setLineDasharray(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineDasharray(styleValue.getExpression());
+ } else {
+ layer.lineDasharray(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+ public static void setLinePattern(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ if (styleValue.isImageStringValue()) {
+ layer.linePattern(styleValue.getImageStringValue());
+ } else {
+ layer.linePattern(styleValue.getExpression());
+ }
+ } else {
+ layer.linePattern(styleValue.getImageURI());
+ }
+ }
+
+ public static void setLineGradient(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineGradient(styleValue.getExpression());
+ } else {
+ layer.lineGradient(styleValue.getIntExpression(VALUE_KEY));
+ }
+ }
+
+ public static void setLineTrimOffset(LineLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.lineTrimOffset(styleValue.getExpression());
+ } else {
+ layer.lineTrimOffset(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+ public static void setSymbolPlacement(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.symbolPlacement(styleValue.getExpression());
+ } else {
+ layer.symbolPlacement(SymbolPlacement.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setSymbolSpacing(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.symbolSpacing(styleValue.getExpression());
+ } else {
+ layer.symbolSpacing(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setSymbolAvoidEdges(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.symbolAvoidEdges(styleValue.getExpression());
+ } else {
+ layer.symbolAvoidEdges(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setSymbolSortKey(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.symbolSortKey(styleValue.getExpression());
+ } else {
+ layer.symbolSortKey(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setSymbolZOrder(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.symbolZOrder(styleValue.getExpression());
+ } else {
+ layer.symbolZOrder(SymbolZOrder.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setIconAllowOverlap(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconAllowOverlap(styleValue.getExpression());
+ } else {
+ layer.iconAllowOverlap(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setIconIgnorePlacement(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconIgnorePlacement(styleValue.getExpression());
+ } else {
+ layer.iconIgnorePlacement(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setIconOptional(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconOptional(styleValue.getExpression());
+ } else {
+ layer.iconOptional(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setIconRotationAlignment(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconRotationAlignment(styleValue.getExpression());
+ } else {
+ layer.iconRotationAlignment(IconRotationAlignment.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setIconSize(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconSize(styleValue.getExpression());
+ } else {
+ layer.iconSize(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setIconTextFit(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconTextFit(styleValue.getExpression());
+ } else {
+ layer.iconTextFit(IconTextFit.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setIconTextFitPadding(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconTextFitPadding(styleValue.getExpression());
+ } else {
+ layer.iconTextFitPadding(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+ public static void setIconImage(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ if (styleValue.isImageStringValue()) {
+ layer.iconImage(styleValue.getImageStringValue());
+ } else {
+ layer.iconImage(styleValue.getExpression());
+ }
+ } else {
+ layer.iconImage(styleValue.getImageURI());
+ }
+ }
+
+ public static void setIconRotate(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconRotate(styleValue.getExpression());
+ } else {
+ layer.iconRotate(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setIconPadding(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconPadding(styleValue.getExpression());
+ } else {
+ layer.iconPadding(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setIconKeepUpright(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconKeepUpright(styleValue.getExpression());
+ } else {
+ layer.iconKeepUpright(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setIconOffset(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconOffset(styleValue.getExpression());
+ } else {
+ layer.iconOffset(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+ public static void setIconAnchor(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconAnchor(styleValue.getExpression());
+ } else {
+ layer.iconAnchor(IconAnchor.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setIconPitchAlignment(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconPitchAlignment(styleValue.getExpression());
+ } else {
+ layer.iconPitchAlignment(IconPitchAlignment.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setTextPitchAlignment(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textPitchAlignment(styleValue.getExpression());
+ } else {
+ layer.textPitchAlignment(TextPitchAlignment.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setTextRotationAlignment(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textRotationAlignment(styleValue.getExpression());
+ } else {
+ layer.textRotationAlignment(TextRotationAlignment.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setTextField(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textField(styleValue.getExpression());
+ } else {
+ layer.textField(styleValue.getString(VALUE_KEY));
+ }
+ }
+
+ public static void setTextFont(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textFont(styleValue.getExpression());
+ } else {
+ layer.textFont(styleValue.getStringArray(VALUE_KEY));
+ }
+ }
+
+ public static void setTextSize(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textSize(styleValue.getExpression());
+ } else {
+ layer.textSize(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setTextMaxWidth(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textMaxWidth(styleValue.getExpression());
+ } else {
+ layer.textMaxWidth(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setTextLineHeight(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textLineHeight(styleValue.getExpression());
+ } else {
+ layer.textLineHeight(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setTextLetterSpacing(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textLetterSpacing(styleValue.getExpression());
+ } else {
+ layer.textLetterSpacing(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setTextJustify(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textJustify(styleValue.getExpression());
+ } else {
+ layer.textJustify(TextJustify.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setTextRadialOffset(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textRadialOffset(styleValue.getExpression());
+ } else {
+ layer.textRadialOffset(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setTextVariableAnchor(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textVariableAnchor(styleValue.getExpression());
+ } else {
+ layer.textVariableAnchor(styleValue.getStringArray(VALUE_KEY));
+ }
+ }
+
+ public static void setTextAnchor(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textAnchor(styleValue.getExpression());
+ } else {
+ layer.textAnchor(TextAnchor.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setTextMaxAngle(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textMaxAngle(styleValue.getExpression());
+ } else {
+ layer.textMaxAngle(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setTextWritingMode(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textWritingMode(styleValue.getExpression());
+ } else {
+ layer.textWritingMode(styleValue.getStringArray(VALUE_KEY));
+ }
+ }
+
+ public static void setTextRotate(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textRotate(styleValue.getExpression());
+ } else {
+ layer.textRotate(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setTextPadding(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textPadding(styleValue.getExpression());
+ } else {
+ layer.textPadding(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setTextKeepUpright(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textKeepUpright(styleValue.getExpression());
+ } else {
+ layer.textKeepUpright(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setTextTransform(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textTransform(styleValue.getExpression());
+ } else {
+ layer.textTransform(TextTransform.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setTextOffset(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textOffset(styleValue.getExpression());
+ } else {
+ layer.textOffset(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+ public static void setTextAllowOverlap(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textAllowOverlap(styleValue.getExpression());
+ } else {
+ layer.textAllowOverlap(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setTextIgnorePlacement(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textIgnorePlacement(styleValue.getExpression());
+ } else {
+ layer.textIgnorePlacement(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setTextOptional(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textOptional(styleValue.getExpression());
+ } else {
+ layer.textOptional(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setVisibility(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ layer.visibility(Visibility.valueOf(styleValue.getEnumName()));
+ }
+
+ public static void setIconOpacity(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconOpacity(styleValue.getExpression());
+ } else {
+ layer.iconOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setIconOpacityTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.iconOpacityTransition(transition);
+ }
+ }
+
+ public static void setIconColor(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconColor(styleValue.getExpression());
+ } else {
+ layer.iconColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setIconColorTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.iconColorTransition(transition);
+ }
+ }
+
+ public static void setIconHaloColor(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconHaloColor(styleValue.getExpression());
+ } else {
+ layer.iconHaloColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setIconHaloColorTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.iconHaloColorTransition(transition);
+ }
+ }
+
+ public static void setIconHaloWidth(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconHaloWidth(styleValue.getExpression());
+ } else {
+ layer.iconHaloWidth(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setIconHaloWidthTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.iconHaloWidthTransition(transition);
+ }
+ }
+
+ public static void setIconHaloBlur(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconHaloBlur(styleValue.getExpression());
+ } else {
+ layer.iconHaloBlur(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setIconHaloBlurTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.iconHaloBlurTransition(transition);
+ }
+ }
+
+ public static void setIconTranslate(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconTranslate(styleValue.getExpression());
+ } else {
+ layer.iconTranslate(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+
+ public static void setIconTranslateTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.iconTranslateTransition(transition);
+ }
+ }
+
+ public static void setIconTranslateAnchor(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.iconTranslateAnchor(styleValue.getExpression());
+ } else {
+ layer.iconTranslateAnchor(IconTranslateAnchor.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setTextOpacity(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textOpacity(styleValue.getExpression());
+ } else {
+ layer.textOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setTextOpacityTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.textOpacityTransition(transition);
+ }
+ }
+
+ public static void setTextColor(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textColor(styleValue.getExpression());
+ } else {
+ layer.textColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setTextColorTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.textColorTransition(transition);
+ }
+ }
+
+ public static void setTextHaloColor(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textHaloColor(styleValue.getExpression());
+ } else {
+ layer.textHaloColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setTextHaloColorTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.textHaloColorTransition(transition);
+ }
+ }
+
+ public static void setTextHaloWidth(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textHaloWidth(styleValue.getExpression());
+ } else {
+ layer.textHaloWidth(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setTextHaloWidthTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.textHaloWidthTransition(transition);
+ }
+ }
+
+ public static void setTextHaloBlur(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textHaloBlur(styleValue.getExpression());
+ } else {
+ layer.textHaloBlur(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setTextHaloBlurTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.textHaloBlurTransition(transition);
+ }
+ }
+
+ public static void setTextTranslate(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textTranslate(styleValue.getExpression());
+ } else {
+ layer.textTranslate(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+
+ public static void setTextTranslateTransition(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.textTranslateTransition(transition);
+ }
+ }
+
+ public static void setTextTranslateAnchor(SymbolLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.textTranslateAnchor(styleValue.getExpression());
+ } else {
+ layer.textTranslateAnchor(TextTranslateAnchor.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setCircleSortKey(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circleSortKey(styleValue.getExpression());
+ } else {
+ layer.circleSortKey(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setVisibility(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ layer.visibility(Visibility.valueOf(styleValue.getEnumName()));
+ }
+
+ public static void setCircleRadius(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circleRadius(styleValue.getExpression());
+ } else {
+ layer.circleRadius(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setCircleRadiusTransition(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.circleRadiusTransition(transition);
+ }
+ }
+
+ public static void setCircleColor(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circleColor(styleValue.getExpression());
+ } else {
+ layer.circleColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setCircleColorTransition(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.circleColorTransition(transition);
+ }
+ }
+
+ public static void setCircleBlur(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circleBlur(styleValue.getExpression());
+ } else {
+ layer.circleBlur(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setCircleBlurTransition(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.circleBlurTransition(transition);
+ }
+ }
+
+ public static void setCircleOpacity(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circleOpacity(styleValue.getExpression());
+ } else {
+ layer.circleOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setCircleOpacityTransition(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.circleOpacityTransition(transition);
+ }
+ }
+
+ public static void setCircleTranslate(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circleTranslate(styleValue.getExpression());
+ } else {
+ layer.circleTranslate(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+
+ public static void setCircleTranslateTransition(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.circleTranslateTransition(transition);
+ }
+ }
+
+ public static void setCircleTranslateAnchor(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circleTranslateAnchor(styleValue.getExpression());
+ } else {
+ layer.circleTranslateAnchor(CircleTranslateAnchor.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setCirclePitchScale(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circlePitchScale(styleValue.getExpression());
+ } else {
+ layer.circlePitchScale(CirclePitchScale.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setCirclePitchAlignment(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circlePitchAlignment(styleValue.getExpression());
+ } else {
+ layer.circlePitchAlignment(CirclePitchAlignment.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setCircleStrokeWidth(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circleStrokeWidth(styleValue.getExpression());
+ } else {
+ layer.circleStrokeWidth(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setCircleStrokeWidthTransition(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.circleStrokeWidthTransition(transition);
+ }
+ }
+
+ public static void setCircleStrokeColor(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circleStrokeColor(styleValue.getExpression());
+ } else {
+ layer.circleStrokeColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setCircleStrokeColorTransition(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.circleStrokeColorTransition(transition);
+ }
+ }
+
+ public static void setCircleStrokeOpacity(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.circleStrokeOpacity(styleValue.getExpression());
+ } else {
+ layer.circleStrokeOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setCircleStrokeOpacityTransition(CircleLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.circleStrokeOpacityTransition(transition);
+ }
+ }
+
+ public static void setVisibility(HeatmapLayer layer, RCTMGLStyleValue styleValue) {
+ layer.visibility(Visibility.valueOf(styleValue.getEnumName()));
+ }
+
+ public static void setHeatmapRadius(HeatmapLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.heatmapRadius(styleValue.getExpression());
+ } else {
+ layer.heatmapRadius(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setHeatmapRadiusTransition(HeatmapLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.heatmapRadiusTransition(transition);
+ }
+ }
+
+ public static void setHeatmapWeight(HeatmapLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.heatmapWeight(styleValue.getExpression());
+ } else {
+ layer.heatmapWeight(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setHeatmapIntensity(HeatmapLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.heatmapIntensity(styleValue.getExpression());
+ } else {
+ layer.heatmapIntensity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setHeatmapIntensityTransition(HeatmapLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.heatmapIntensityTransition(transition);
+ }
+ }
+
+ public static void setHeatmapColor(HeatmapLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.heatmapColor(styleValue.getExpression());
+ } else {
+ layer.heatmapColor(styleValue.getIntExpression(VALUE_KEY));
+ }
+ }
+
+ public static void setHeatmapOpacity(HeatmapLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.heatmapOpacity(styleValue.getExpression());
+ } else {
+ layer.heatmapOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setHeatmapOpacityTransition(HeatmapLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.heatmapOpacityTransition(transition);
+ }
+ }
+
+ public static void setVisibility(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ layer.visibility(Visibility.valueOf(styleValue.getEnumName()));
+ }
+
+ public static void setFillExtrusionOpacity(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillExtrusionOpacity(styleValue.getExpression());
+ } else {
+ layer.fillExtrusionOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setFillExtrusionOpacityTransition(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.fillExtrusionOpacityTransition(transition);
+ }
+ }
+
+ public static void setFillExtrusionColor(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillExtrusionColor(styleValue.getExpression());
+ } else {
+ layer.fillExtrusionColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setFillExtrusionColorTransition(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.fillExtrusionColorTransition(transition);
+ }
+ }
+
+ public static void setFillExtrusionTranslate(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillExtrusionTranslate(styleValue.getExpression());
+ } else {
+ layer.fillExtrusionTranslate(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+
+ public static void setFillExtrusionTranslateTransition(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.fillExtrusionTranslateTransition(transition);
+ }
+ }
+
+ public static void setFillExtrusionTranslateAnchor(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillExtrusionTranslateAnchor(styleValue.getExpression());
+ } else {
+ layer.fillExtrusionTranslateAnchor(FillExtrusionTranslateAnchor.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setFillExtrusionPattern(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ if (styleValue.isImageStringValue()) {
+ layer.fillExtrusionPattern(styleValue.getImageStringValue());
+ } else {
+ layer.fillExtrusionPattern(styleValue.getExpression());
+ }
+ } else {
+ layer.fillExtrusionPattern(styleValue.getImageURI());
+ }
+ }
+
+ public static void setFillExtrusionHeight(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillExtrusionHeight(styleValue.getExpression());
+ } else {
+ layer.fillExtrusionHeight(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setFillExtrusionHeightTransition(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.fillExtrusionHeightTransition(transition);
+ }
+ }
+
+ public static void setFillExtrusionBase(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillExtrusionBase(styleValue.getExpression());
+ } else {
+ layer.fillExtrusionBase(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setFillExtrusionBaseTransition(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.fillExtrusionBaseTransition(transition);
+ }
+ }
+
+ public static void setFillExtrusionVerticalGradient(FillExtrusionLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.fillExtrusionVerticalGradient(styleValue.getExpression());
+ } else {
+ layer.fillExtrusionVerticalGradient(styleValue.getBoolean(VALUE_KEY));
+ }
+ }
+
+ public static void setVisibility(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ layer.visibility(Visibility.valueOf(styleValue.getEnumName()));
+ }
+
+ public static void setRasterOpacity(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.rasterOpacity(styleValue.getExpression());
+ } else {
+ layer.rasterOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setRasterOpacityTransition(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.rasterOpacityTransition(transition);
+ }
+ }
+
+ public static void setRasterHueRotate(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.rasterHueRotate(styleValue.getExpression());
+ } else {
+ layer.rasterHueRotate(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setRasterHueRotateTransition(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.rasterHueRotateTransition(transition);
+ }
+ }
+
+ public static void setRasterBrightnessMin(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.rasterBrightnessMin(styleValue.getExpression());
+ } else {
+ layer.rasterBrightnessMin(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setRasterBrightnessMinTransition(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.rasterBrightnessMinTransition(transition);
+ }
+ }
+
+ public static void setRasterBrightnessMax(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.rasterBrightnessMax(styleValue.getExpression());
+ } else {
+ layer.rasterBrightnessMax(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setRasterBrightnessMaxTransition(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.rasterBrightnessMaxTransition(transition);
+ }
+ }
+
+ public static void setRasterSaturation(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.rasterSaturation(styleValue.getExpression());
+ } else {
+ layer.rasterSaturation(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setRasterSaturationTransition(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.rasterSaturationTransition(transition);
+ }
+ }
+
+ public static void setRasterContrast(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.rasterContrast(styleValue.getExpression());
+ } else {
+ layer.rasterContrast(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setRasterContrastTransition(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.rasterContrastTransition(transition);
+ }
+ }
+
+ public static void setRasterResampling(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.rasterResampling(styleValue.getExpression());
+ } else {
+ layer.rasterResampling(RasterResampling.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setRasterFadeDuration(RasterLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.rasterFadeDuration(styleValue.getExpression());
+ } else {
+ layer.rasterFadeDuration(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setVisibility(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ layer.visibility(Visibility.valueOf(styleValue.getEnumName()));
+ }
+
+ public static void setHillshadeIlluminationDirection(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.hillshadeIlluminationDirection(styleValue.getExpression());
+ } else {
+ layer.hillshadeIlluminationDirection(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setHillshadeIlluminationAnchor(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.hillshadeIlluminationAnchor(styleValue.getExpression());
+ } else {
+ layer.hillshadeIlluminationAnchor(HillshadeIlluminationAnchor.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setHillshadeExaggeration(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.hillshadeExaggeration(styleValue.getExpression());
+ } else {
+ layer.hillshadeExaggeration(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setHillshadeExaggerationTransition(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.hillshadeExaggerationTransition(transition);
+ }
+ }
+
+ public static void setHillshadeShadowColor(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.hillshadeShadowColor(styleValue.getExpression());
+ } else {
+ layer.hillshadeShadowColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setHillshadeShadowColorTransition(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.hillshadeShadowColorTransition(transition);
+ }
+ }
+
+ public static void setHillshadeHighlightColor(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.hillshadeHighlightColor(styleValue.getExpression());
+ } else {
+ layer.hillshadeHighlightColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setHillshadeHighlightColorTransition(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.hillshadeHighlightColorTransition(transition);
+ }
+ }
+
+ public static void setHillshadeAccentColor(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.hillshadeAccentColor(styleValue.getExpression());
+ } else {
+ layer.hillshadeAccentColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setHillshadeAccentColorTransition(HillshadeLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.hillshadeAccentColorTransition(transition);
+ }
+ }
+
+ public static void setVisibility(BackgroundLayer layer, RCTMGLStyleValue styleValue) {
+ layer.visibility(Visibility.valueOf(styleValue.getEnumName()));
+ }
+
+ public static void setBackgroundColor(BackgroundLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.backgroundColor(styleValue.getExpression());
+ } else {
+ layer.backgroundColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setBackgroundColorTransition(BackgroundLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.backgroundColorTransition(transition);
+ }
+ }
+
+ public static void setBackgroundPattern(BackgroundLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ if (styleValue.isImageStringValue()) {
+ layer.backgroundPattern(styleValue.getImageStringValue());
+ } else {
+ layer.backgroundPattern(styleValue.getExpression());
+ }
+ } else {
+ layer.backgroundPattern(styleValue.getImageURI());
+ }
+ }
+
+ public static void setBackgroundOpacity(BackgroundLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.backgroundOpacity(styleValue.getExpression());
+ } else {
+ layer.backgroundOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setBackgroundOpacityTransition(BackgroundLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.backgroundOpacityTransition(transition);
+ }
+ }
+
+ public static void setVisibility(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ layer.visibility(Visibility.valueOf(styleValue.getEnumName()));
+ }
+
+ public static void setSkyType(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.skyType(styleValue.getExpression());
+ } else {
+ layer.skyType(SkyType.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setSkyAtmosphereSun(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.skyAtmosphereSun(styleValue.getExpression());
+ } else {
+ layer.skyAtmosphereSun(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+ public static void setSkyAtmosphereSunIntensity(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.skyAtmosphereSunIntensity(styleValue.getExpression());
+ } else {
+ layer.skyAtmosphereSunIntensity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setSkyGradientCenter(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.skyGradientCenter(styleValue.getExpression());
+ } else {
+ layer.skyGradientCenter(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+ public static void setSkyGradientRadius(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.skyGradientRadius(styleValue.getExpression());
+ } else {
+ layer.skyGradientRadius(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+ public static void setSkyGradient(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.skyGradient(styleValue.getExpression());
+ } else {
+ layer.skyGradient(styleValue.getIntExpression(VALUE_KEY));
+ }
+ }
+
+ public static void setSkyAtmosphereHaloColor(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.skyAtmosphereHaloColor(styleValue.getExpression());
+ } else {
+ layer.skyAtmosphereHaloColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+ public static void setSkyAtmosphereColor(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.skyAtmosphereColor(styleValue.getExpression());
+ } else {
+ layer.skyAtmosphereColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+ public static void setSkyOpacity(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.skyOpacity(styleValue.getExpression());
+ } else {
+ layer.skyOpacity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setSkyOpacityTransition(SkyLayer layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.skyOpacityTransition(transition);
+ }
+ }
+
+ public static void setAnchor(Light layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.anchor(styleValue.getExpression());
+ } else {
+ layer.anchor(Anchor.valueOf(styleValue.getEnumName()));
+ }
+ }
+
+ public static void setPosition(Light layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.position(styleValue.getExpression());
+ } else {
+ layer.position(styleValue.getLightPosition());
+ }
+ }
+
+
+ public static void setPositionTransition(Light layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.positionTransition(transition);
+ }
+ }
+
+ public static void setColor(Light layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.color(styleValue.getExpression());
+ } else {
+ layer.color(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setColorTransition(Light layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.colorTransition(transition);
+ }
+ }
+
+ public static void setIntensity(Light layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.intensity(styleValue.getExpression());
+ } else {
+ layer.intensity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setIntensityTransition(Light layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.intensityTransition(transition);
+ }
+ }
+
+ public static void setRange(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.range(styleValue.getExpression());
+ } else {
+ layer.range(styleValue.getFloatArray(VALUE_KEY));
+ }
+ }
+
+
+ public static void setRangeTransition(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.rangeTransition(transition);
+ }
+ }
+
+ public static void setColor(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.color(styleValue.getExpression());
+ } else {
+ layer.color(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setColorTransition(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.colorTransition(transition);
+ }
+ }
+
+ public static void setHighColor(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.highColor(styleValue.getExpression());
+ } else {
+ layer.highColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setHighColorTransition(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.highColorTransition(transition);
+ }
+ }
+
+ public static void setSpaceColor(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.spaceColor(styleValue.getExpression());
+ } else {
+ layer.spaceColor(styleValue.getInt(VALUE_KEY));
+ }
+ }
+
+
+ public static void setSpaceColorTransition(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.spaceColorTransition(transition);
+ }
+ }
+
+ public static void setHorizonBlend(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.horizonBlend(styleValue.getExpression());
+ } else {
+ layer.horizonBlend(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setHorizonBlendTransition(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.horizonBlendTransition(transition);
+ }
+ }
+
+ public static void setStarIntensity(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.starIntensity(styleValue.getExpression());
+ } else {
+ layer.starIntensity(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+
+ public static void setStarIntensityTransition(Atmosphere layer, RCTMGLStyleValue styleValue) {
+ StyleTransition transition = styleValue.getTransition();
+ if (transition != null) {
+ layer.starIntensityTransition(transition);
+ }
+ }
+
+ public static void setExaggeration(Terrain layer, RCTMGLStyleValue styleValue) {
+ if (styleValue.isExpression()) {
+ layer.exaggeration(styleValue.getExpression());
+ } else {
+ layer.exaggeration(styleValue.getFloat(VALUE_KEY));
+ }
+ }
+
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.kt
new file mode 100644
index 000000000..d61a25595
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/RCTMGLStyleValue.kt
@@ -0,0 +1,223 @@
+package com.mapbox.rctmgl.components.styles
+
+import com.facebook.react.bridge.*
+import com.mapbox.bindgen.Value
+import com.mapbox.maps.extension.style.types.StyleTransition.Builder
+import com.mapbox.rctmgl.utils.ImageEntry
+import com.mapbox.maps.extension.style.types.StyleTransition
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.light.LightPosition
+import com.mapbox.rctmgl.utils.ExpressionParser
+import java.util.ArrayList
+
+class RCTMGLStyleValue(config: ReadableMap) {
+ val type: String?
+ private var isExpression = false
+ private var mExpression: Expression? = null
+ private val mPayload: ReadableMap?
+ var imageURI: String? = ""
+ private var isAddImage = false
+ var imageScale = ImageEntry.defaultScale
+ private fun isTokenizedValue(value: String): Boolean {
+ return value.startsWith("{") && value.endsWith("}")
+ }
+
+ val isFunction: Boolean
+ get() = type == "function"
+
+ fun getInt(key: String?): Int {
+ return mPayload!!.getInt(key!!)
+ }
+
+ fun getIntExpression(key: String?): Expression {
+ return Expression.literal(mPayload!!.getInt(key!!).toLong())
+ }
+
+ fun getString(key: String?): String? {
+ return mPayload!!.getString(key!!)
+ }
+
+ fun getEnumName(): String {
+ return mPayload!!.getString("value")!!.toUpperCase().replace("-", "_")
+ }
+
+ fun getDouble(key: String?): Double {
+ return mPayload!!.getDouble(key!!)
+ }
+
+ fun getFloat(key: String?): Float {
+ return getDouble(key).toFloat()
+ }
+
+ fun getDynamic(key: String?): Dynamic {
+ return mPayload!!.getDynamic(key!!)
+ }
+
+ fun getArray(key: String?): ReadableArray? {
+ return mPayload!!.getArray(key!!)
+ }
+
+ fun getBoolean(key: String?): Boolean {
+ return mPayload!!.getBoolean(key!!)
+ }
+
+ /*
+ public Float[] getFloatArray(String key) {
+ ReadableArray arr = getArray(key);
+
+ Float[] floatArr = new Float[arr.size()];
+ for (int i = 0; i < arr.size(); i++) {
+ ReadableMap item = arr.getMap(i);
+ floatArr[i] = (float) item.getDouble("value");
+ }
+
+ return floatArr;
+ }
+ */
+ fun getFloatArray(key: String?): List {
+ val arr = getArray(key)
+ val result = ArrayList(arr!!.size())
+ for (i in 0 until arr.size()) {
+ val item = arr.getMap(i)
+ result.add(item.getDouble("value"))
+ }
+ return result
+ }
+
+ /*
+ public String[] getStringArray(String key) {
+ ReadableArray arr = getArray(key);
+
+ String[] stringArr = new String[arr.size()];
+ for (int i = 0; i < arr.size(); i++) {
+ ReadableMap item = arr.getMap(i);
+ stringArr[i] = item.getString("value");
+ }
+
+ return stringArr;
+ } */
+ fun getStringArray(key: String?): List {
+ val arr = getArray(key)
+ val result = ArrayList(arr!!.size())
+ for (i in 0 until arr.size()) {
+ val item = arr.getMap(i)
+ result.add(item.getString("value"))
+ }
+ return result
+ }
+
+ val map: ReadableMap?
+ get() {
+ if ("hashmap" == mPayload!!.getString("type")) {
+ val keyValues = mPayload.getArray("value")
+ val result = WritableNativeMap()
+ for (i in 0 until keyValues!!.size()) {
+ val keyValue = keyValues.getArray(i)
+ val stringKey = keyValue.getMap(0).getString("value")
+ val value = WritableNativeMap()
+ value.merge(keyValue.getMap(1))
+ result.putMap(stringKey!!, value)
+ }
+ return result
+ }
+ return null
+ }
+
+ fun getMap(_key: String?): ReadableMap? {
+ return map
+ }
+
+ fun getExpression(): Expression? {
+ return mExpression
+ }
+
+ fun getLightPosition(): LightPosition {
+ return LightPosition.fromList(getFloatArray("value"))
+ }
+
+ fun isExpression(): Boolean {
+ return isExpression
+ }
+
+ fun shouldAddImage(): Boolean {
+ return isAddImage
+ }
+
+ val isImageStringValue: Boolean
+ get() = "string" == mPayload!!.getString("type")
+
+ fun getImageStringValue(): String? {
+ return mPayload!!.getString("value")
+ }
+
+ val transition: StyleTransition?
+ get() {
+ if (type != "transition") {
+ return null
+ }
+ val config = getMap(RCTMGLStyleFactory.VALUE_KEY)
+ var enablePlacementTransitions = true
+ if (config!!.hasKey("enablePlacementTransitions")) {
+ enablePlacementTransitions =
+ config.getMap("enablePlacementTransitions")!!.getBoolean("value")
+ }
+ var duration = 300
+ val delay = 0
+ if (config.hasKey("duration") && ReadableType.Map == config.getType("duration")) {
+ duration = config.getMap("duration")!!.getInt("value")
+ }
+ if (config.hasKey("delay") && ReadableType.Map == config.getType("delay")) {
+ duration = config.getMap("delay")!!.getInt("value")
+ }
+ return Builder().duration(duration.toLong()).delay(delay.toLong()).build()
+ }
+
+ companion object {
+ const val InterpolationModeExponential = 100
+ const val InterpolationModeInterval = 101
+ const val InterpolationModeCategorical = 102
+ const val InterpolationModeIdentity = 103
+ }
+
+ init {
+ type = config.getString("styletype")
+ mPayload = config.getMap("stylevalue")
+ isAddImage = false
+ if ("image" == type) {
+ imageScale = ImageEntry.defaultScale
+ if ("hashmap" == mPayload!!.getString("type")) {
+ val map = map
+ imageURI = map!!.getMap("uri")!!.getString("value")
+ if (map.getMap("scale") != null) {
+ imageScale = map.getMap("scale")!!.getDouble("value")
+ }
+ } else if ("string" == mPayload.getString("type")) {
+ val value = mPayload.getString("value")
+ if (value!!.contains("://")) {
+ imageURI = value
+ } else {
+ imageURI = null
+ isExpression = true
+ mExpression = Expression.literal(value)
+ }
+ } else {
+ imageURI = null
+ }
+ isAddImage = imageURI != null
+ }
+ if (!isAddImage) {
+ val dynamic = mPayload!!.getDynamic("value")
+ if (dynamic.type == ReadableType.Array) {
+ val array = dynamic.asArray()
+ if (array.size() > 0 && mPayload.getString("type") == "array") {
+ val map = array.getMap(0)
+ if (map != null && map.getString("type") == "string") {
+ isExpression = true
+ mExpression = ExpressionParser.fromTyped(mPayload)
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/atmosphere/RCTMGLAtmosphere.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/atmosphere/RCTMGLAtmosphere.kt
new file mode 100644
index 000000000..1275d0d10
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/atmosphere/RCTMGLAtmosphere.kt
@@ -0,0 +1,62 @@
+package com.mapbox.rctmgl.components.styles.atmosphere
+
+import android.content.Context
+import com.facebook.react.bridge.ReadableMap
+import com.mapbox.maps.MapboxMap
+import com.mapbox.maps.extension.style.atmosphere.generated.Atmosphere
+import com.mapbox.maps.extension.style.terrain.generated.Terrain
+import com.mapbox.maps.extension.style.terrain.generated.removeTerrain
+import com.mapbox.rctmgl.components.RemovalReason
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+import com.mapbox.rctmgl.components.styles.sources.AbstractSourceConsumer
+import com.mapbox.rctmgl.utils.Logger
+
+class RCTMGLAtmosphere(context: Context?) : AbstractSourceConsumer(context) {
+ override var iD: String? = null
+ protected var mAtmosphere: Atmosphere? = null
+
+ // beginregion RCTLayer
+ @JvmField
+ protected var mMap: MapboxMap? = null
+
+ @JvmField
+ protected var mReactStyle: ReadableMap? = null
+
+ fun setReactStyle(reactStyle: ReadableMap?) {
+ mReactStyle = reactStyle
+ if (mAtmosphere != null) {
+ addStyles()
+ }
+ }
+ // endregion RCTLayer
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ mMap = mapView.getMapboxMap()
+ val atmosphere = makeAtmosphere()
+ mAtmosphere = atmosphere
+ addStyles()
+ mapView.savedStyle?.let { atmosphere.bindTo(it) }
+ }
+
+ override fun removeFromMap(mapView: RCTMGLMapView, reason: RemovalReason): Boolean {
+ mapView.savedStyle?.let { it.removeTerrain() }
+ mMap = null
+ return super.removeFromMap(mapView, reason)
+ }
+
+ fun makeAtmosphere(): Atmosphere {
+ return Atmosphere()
+ }
+
+ fun addStyles() {
+ RCTMGLStyleFactory.setAtmosphereLayerStyle(
+ mAtmosphere, RCTMGLStyle(
+ context, mReactStyle!!,
+ mMap!!
+ )
+ )
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/atmosphere/RCTMGLAtmosphereManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/atmosphere/RCTMGLAtmosphereManager.kt
new file mode 100644
index 000000000..4a002c94b
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/atmosphere/RCTMGLAtmosphereManager.kt
@@ -0,0 +1,30 @@
+package com.mapbox.rctmgl.components.styles.atmosphere
+
+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
+
+class RCTMGLAtmosphereManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLAtmosphere {
+ return RCTMGLAtmosphere(reactContext)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(layer: RCTMGLAtmosphere, id: String?) {
+ layer.iD = id
+ }
+
+ @ReactProp(name = "reactStyle")
+ fun setReactStyle(atmosphere: RCTMGLAtmosphere, reactStyle: ReadableMap?) {
+ atmosphere.setReactStyle(reactStyle)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLAtmosphere"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTLayer.kt
new file mode 100644
index 000000000..6024ca5fb
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTLayer.kt
@@ -0,0 +1,303 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import android.content.Context
+import com.mapbox.maps.extension.style.layers.Layer
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.maps.Style
+import com.mapbox.maps.MapView
+import com.mapbox.rctmgl.components.styles.sources.AbstractSourceConsumer
+import com.facebook.react.bridge.ReadableMap
+import com.mapbox.maps.MapboxMap
+import com.facebook.react.bridge.ReadableArray
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView.FoundLayerCallback
+import com.facebook.common.logging.FLog
+import com.mapbox.maps.extension.style.expressions.dsl.generated.all
+import com.mapbox.maps.extension.style.expressions.dsl.generated.literal
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.layers.*
+import com.mapbox.maps.extension.style.layers.properties.generated.Visibility
+import com.mapbox.rctmgl.components.RemovalReason
+import com.mapbox.rctmgl.components.styles.layers.RCTLayer
+import com.mapbox.rctmgl.components.styles.sources.RCTSource
+import com.mapbox.rctmgl.modules.RCTMGLLogging
+import com.mapbox.rctmgl.utils.ExpressionParser
+import java.lang.ClassCastException
+import com.mapbox.rctmgl.utils.Logger
+
+abstract class RCTLayer(protected var mContext: Context) : AbstractSourceConsumer(
+ mContext
+) {
+ override var iD: String? = null
+ @JvmField
+ protected var mSourceID: String? = null
+ protected var mAboveLayerID: String? = null
+ protected var mBelowLayerID: String? = null
+ protected var mLayerIndex: Int? = null
+ protected var mVisible = false
+ protected var mMinZoomLevel: Double? = null
+ protected var mMaxZoomLevel: Double? = null
+ @JvmField
+ protected var mReactStyle: ReadableMap? = null
+ protected var mFilter: Expression? = null
+ @JvmField
+ protected var mMap: MapboxMap? = null
+ @JvmField
+ protected var mLayer: T? = null
+ protected var mHadFilter = false
+
+ protected var mExisting : Boolean? = null
+
+ fun setSourceID(sourceID: String?) {
+ mSourceID = sourceID
+ }
+
+ fun checkID(): String? {
+ if (iD == null) {
+ Logger.w(LOG_TAG, "iD is null in layer")
+ }
+ return iD;
+ }
+
+ fun setAboveLayerID(aboveLayerID: String?) {
+ if (mAboveLayerID != null && mAboveLayerID == aboveLayerID) {
+ return
+ }
+ mAboveLayerID = aboveLayerID
+ if (mLayer != null) {
+ removeFromMap(mMapView!!, RemovalReason.REORDER)
+ addAbove(mAboveLayerID)
+ }
+ }
+
+ fun setBelowLayerID(belowLayerID: String?) {
+ if (mBelowLayerID != null && mBelowLayerID == belowLayerID) {
+ return
+ }
+ mBelowLayerID = belowLayerID
+ if (mLayer != null) {
+ removeFromMap(mMapView!!,RemovalReason.REORDER)
+ addBelow(mBelowLayerID)
+ }
+ }
+
+ fun setLayerIndex(layerIndex: Int) {
+ if (mLayerIndex != null && mLayerIndex == layerIndex) {
+ return
+ }
+ mLayerIndex = layerIndex
+ if (mLayer != null) {
+ removeFromMap(mMapView!!,RemovalReason.REORDER)
+ addAtIndex(layerIndex)
+ }
+ }
+
+ fun setVisible(visible: Boolean) {
+ mVisible = visible
+ if (mLayer != null) {
+ mLayer!!.visibility(if (mVisible) Visibility.VISIBLE else Visibility.NONE)
+ }
+ }
+
+ fun setMinZoomLevel(minZoomLevel: Double) {
+ mMinZoomLevel = minZoomLevel
+ if (mLayer != null) {
+ mLayer!!.minZoom(minZoomLevel.toFloat().toDouble())
+ }
+ }
+
+ fun setMaxZoomLevel(maxZoomLevel: Double) {
+ mMaxZoomLevel = maxZoomLevel
+ if (mLayer != null) {
+ mLayer!!.maxZoom(maxZoomLevel.toFloat().toDouble())
+ }
+ }
+
+ fun setReactStyle(reactStyle: ReadableMap?) {
+ mReactStyle = reactStyle
+ if (mLayer != null) {
+ addStyles()
+ }
+ }
+
+ fun setFilter(readableFilterArray: ReadableArray?) {
+ val filterExpression = ExpressionParser.from(readableFilterArray)
+ mFilter = filterExpression
+ if (mLayer != null) {
+ if (mFilter != null) {
+ mHadFilter = true
+ updateFilter(mFilter)
+ } else if (mHadFilter) {
+ updateFilter(/* literal(true)*/all {} )
+ }
+ }
+ }
+
+ fun setExisting(existing: Boolean) {
+ mExisting = existing
+ }
+
+ fun add() {
+ if (!hasInitialized()) {
+ return
+ }
+ if (style == null) return
+
+ /* V10TODO
+ String userBackgroundID = LocationComponentConstants.BACKGROUND_LAYER;
+ Layer userLocationBackgroundLayer = getStyle().getLayer(userBackgroundID);
+
+ // place below user location layer
+ if (userLocationBackgroundLayer != null) {
+ getStyle().addLayerBelow(mLayer, userBackgroundID);
+ mMapView.layerAdded(mLayer);
+ return;
+ } */
+
+ Logger.logged("RCTLayer.add") {
+ style!!.addLayer(mLayer!!);
+ mMapView!!.layerAdded(mLayer!!)
+ }
+ }
+
+ fun addAbove(aboveLayerID: String?) {
+ mMapView!!.waitForLayer(aboveLayerID, object : FoundLayerCallback {
+ override fun found(layer: Layer?) {
+ if (!hasInitialized()) {
+ return
+ }
+ if (style == null) return
+ style!!.addLayerAbove(mLayer!!, aboveLayerID)
+ mMapView!!.layerAdded(mLayer!!)
+ }
+ })
+ }
+
+ fun addBelow(belowLayerID: String?) {
+ mMapView!!.waitForLayer(belowLayerID, object : FoundLayerCallback {
+ override fun found(layer: Layer?) {
+ if (!hasInitialized()) {
+ return
+ }
+ if (style == null) return
+ style!!.addLayerBelow(mLayer!!, belowLayerID)
+ mMapView!!.layerAdded(mLayer!!)
+ }
+ })
+ }
+
+ fun addAtIndex(index: Int) {
+ var index = index
+ if (!hasInitialized()) {
+ return
+ }
+ val style = this.style ?: return
+ val layerSize = style!!.styleLayers.size
+ if (index >= layerSize) {
+ FLog.e(
+ LOG_TAG,
+ "Layer index is greater than number of layers on map. Layer inserted at end of layer stack."
+ )
+ index = layerSize - 1
+ }
+ val layer = mLayer ?: return
+ val mapView = mMapView ?: return
+ style.addLayerAt(layer, index)
+ mapView.layerAdded(layer)
+ }
+
+ protected fun insertLayer() {
+ val style = this.style ?: return
+ val id = checkID() ?: return
+ if (style.styleLayerExists(id)) {
+ return // prevent adding a layer twice
+ }
+ if (mAboveLayerID != null) {
+ addAbove(mAboveLayerID)
+ } else if (mBelowLayerID != null) {
+ addBelow(mBelowLayerID)
+ } else if (mLayerIndex != null) {
+ addAtIndex(mLayerIndex!!)
+ } else {
+ add()
+ }
+ setZoomBounds()
+ }
+
+ protected fun setZoomBounds() {
+ if (mMaxZoomLevel != null) {
+ mLayer!!.maxZoom(mMaxZoomLevel!!.toFloat().toDouble())
+ }
+ if (mMinZoomLevel != null) {
+ mLayer!!.minZoom(mMinZoomLevel!!.toFloat().toDouble())
+ }
+ }
+
+ protected open fun updateFilter(expression: Expression?) {
+ // override if you want to update the filter
+ }
+
+ private fun getLayerAs(style: Style, id: String?): T? {
+ val result = style.getLayer(iD!!)
+ return try {
+ result as T?
+ } catch (exception: ClassCastException) {
+ null
+ }
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ mMap = mapView.getMapboxMap()
+ val style = style ?: return
+ val id = checkID() ?: return
+
+ val exists = style.styleLayerExists(id)
+ var existingLayer: T? = null;
+ if (exists) {
+ if (mExisting == null) {
+ Logger.e(LOG_TAG, "Layer $id seems to refer to an existing layer but existing flag is not specified, this is deprecated")
+ }
+ existingLayer = getLayerAs(style, id)
+ }
+ if (existingLayer != null) {
+ mLayer = existingLayer
+ } else {
+ mLayer = makeLayer()
+ insertLayer()
+ }
+
+ addStyles()
+ if (mFilter != null) {
+ mHadFilter = true
+ updateFilter(mFilter)
+ }
+ }
+
+ override fun removeFromMap(mapView: RCTMGLMapView, reason: RemovalReason): Boolean {
+ style?.let {
+ val layer = mLayer
+ if (layer != null) {
+ it.removeStyleLayer(layer.layerId)
+ } else {
+ Logger.e("RCTLayer","mLayer is null on removal layer from map")
+ }
+ }
+ return super.removeFromMap(mapView, reason)
+ }
+
+ private val style: Style?
+ private get() =
+ if (mMap == null) {
+ null
+ } else mMapView?.savedStyle
+
+ abstract fun makeLayer(): T
+ abstract fun addStyles()
+ private fun hasInitialized(): Boolean {
+ return mMap != null && mLayer != null
+ }
+
+ companion object {
+ const val LOG_TAG = "RCTLayer"
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.kt
new file mode 100644
index 000000000..e2167341c
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayer.kt
@@ -0,0 +1,21 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import android.content.Context
+import com.mapbox.maps.extension.style.layers.generated.BackgroundLayer
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+
+class RCTMGLBackgroundLayer(context: Context?) : RCTLayer(
+ context!!
+) {
+ override fun makeLayer(): BackgroundLayer {
+ return BackgroundLayer(iD!!)
+ }
+
+ override fun addStyles() {
+ RCTMGLStyleFactory.setBackgroundLayerStyle(
+ mLayer,
+ RCTMGLStyle(context, mReactStyle, mMap!!)
+ )
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayerManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayerManager.kt
new file mode 100644
index 000000000..b249215fd
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLBackgroundLayerManager.kt
@@ -0,0 +1,65 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+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
+
+class RCTMGLBackgroundLayerManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLBackgroundLayer {
+ return RCTMGLBackgroundLayer(reactContext)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(layer: RCTMGLBackgroundLayer, id: String?) {
+ layer.iD = id
+ }
+
+ @ReactProp(name = "existing")
+ fun setExisting(layer: RCTMGLBackgroundLayer, existing: Boolean) {
+ layer.setExisting(existing)
+ }
+
+ @ReactProp(name = "sourceID")
+ fun setSourceID(layer: RCTMGLBackgroundLayer, sourceID: String?) {
+ layer.setSourceID(sourceID)
+ }
+
+ @ReactProp(name = "aboveLayerID")
+ fun setAboveLayerID(layer: RCTMGLBackgroundLayer, aboveLayerID: String?) {
+ layer.setAboveLayerID(aboveLayerID)
+ }
+
+ @ReactProp(name = "belowLayerID")
+ fun setBelowLayerID(layer: RCTMGLBackgroundLayer, belowLayerID: String?) {
+ layer.setBelowLayerID(belowLayerID)
+ }
+
+ @ReactProp(name = "layerIndex")
+ fun setLayerIndex(layer: RCTMGLBackgroundLayer, layerIndex: Int) {
+ layer.setLayerIndex(layerIndex)
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(layer: RCTMGLBackgroundLayer, minZoomLevel: Double) {
+ layer.setMinZoomLevel(minZoomLevel)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(layer: RCTMGLBackgroundLayer, maxZoomLevel: Double) {
+ layer.setMaxZoomLevel(maxZoomLevel)
+ }
+
+ @ReactProp(name = "reactStyle")
+ fun setReactStyle(layer: RCTMGLBackgroundLayer, style: ReadableMap?) {
+ layer.setReactStyle(style)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLBackgroundLayer"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.kt
new file mode 100644
index 000000000..156b043bc
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayer.kt
@@ -0,0 +1,40 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import android.content.Context
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.layers.generated.CircleLayer
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+
+class RCTMGLCircleLayer(context: Context?) : RCTLayer(
+ context!!
+) {
+ private var mSourceLayerID: String? = null
+ override fun updateFilter(expression: Expression?) {
+ mLayer!!.filter(expression!!)
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ }
+
+ override fun makeLayer(): CircleLayer {
+ val layer = CircleLayer(iD!!, mSourceID!!)
+ if (mSourceLayerID != null) {
+ layer.sourceLayer(mSourceLayerID!!)
+ }
+ return layer
+ }
+
+ override fun addStyles() {
+ RCTMGLStyleFactory.setCircleLayerStyle(mLayer, RCTMGLStyle(context, mReactStyle, mMap!!))
+ }
+
+ fun setSourceLayerID(sourceLayerID: String?) {
+ mSourceLayerID = sourceLayerID
+ if (mLayer != null) {
+ mLayer!!.sourceLayer(sourceLayerID!!)
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayerManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayerManager.kt
new file mode 100644
index 000000000..6e76d8343
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLCircleLayerManager.kt
@@ -0,0 +1,76 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import com.facebook.react.bridge.ReadableArray
+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
+
+class RCTMGLCircleLayerManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLCircleLayer {
+ return RCTMGLCircleLayer(reactContext)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(layer: RCTMGLCircleLayer, id: String?) {
+ layer.iD = id
+ }
+
+ @ReactProp(name = "existing")
+ fun setExisting(layer: RCTMGLCircleLayer, existing: Boolean) {
+ layer.setExisting(existing)
+ }
+
+ @ReactProp(name = "sourceID")
+ fun setSourceID(layer: RCTMGLCircleLayer, sourceID: String?) {
+ layer.setSourceID(sourceID)
+ }
+
+ @ReactProp(name = "aboveLayerID")
+ fun setAboveLayerID(layer: RCTMGLCircleLayer, aboveLayerID: String?) {
+ layer.setAboveLayerID(aboveLayerID)
+ }
+
+ @ReactProp(name = "belowLayerID")
+ fun setBelowLayerID(layer: RCTMGLCircleLayer, belowLayerID: String?) {
+ layer.setBelowLayerID(belowLayerID)
+ }
+
+ @ReactProp(name = "layerIndex")
+ fun setLayerIndex(layer: RCTMGLCircleLayer, layerIndex: Int) {
+ layer.setLayerIndex(layerIndex)
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(layer: RCTMGLCircleLayer, minZoomLevel: Double) {
+ layer.setMinZoomLevel(minZoomLevel)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(layer: RCTMGLCircleLayer, maxZoomLevel: Double) {
+ layer.setMaxZoomLevel(maxZoomLevel)
+ }
+
+ @ReactProp(name = "reactStyle")
+ fun setReactStyle(layer: RCTMGLCircleLayer, style: ReadableMap?) {
+ layer.setReactStyle(style)
+ }
+
+ @ReactProp(name = "sourceLayerID")
+ fun setSourceLayerId(layer: RCTMGLCircleLayer, sourceLayerID: String?) {
+ layer.setSourceLayerID(sourceLayerID)
+ }
+
+ @ReactProp(name = "filter")
+ fun setFilter(layer: RCTMGLCircleLayer, filterList: ReadableArray?) {
+ layer.setFilter(filterList)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLCircleLayer"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.kt
new file mode 100644
index 000000000..1a43570c2
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayer.kt
@@ -0,0 +1,43 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import android.content.Context
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.layers.generated.FillExtrusionLayer
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+
+class RCTMGLFillExtrusionLayer(context: Context?) : RCTLayer(
+ context!!
+) {
+ private var mSourceLayerID: String? = null
+ override fun updateFilter(expression: Expression?) {
+ mLayer!!.filter(expression!!)
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ }
+
+ override fun makeLayer(): FillExtrusionLayer {
+ val layer = FillExtrusionLayer(iD!!, mSourceID!!)
+ if (mSourceLayerID != null) {
+ layer.sourceLayer(mSourceLayerID!!)
+ }
+ return layer
+ }
+
+ override fun addStyles() {
+ RCTMGLStyleFactory.setFillExtrusionLayerStyle(
+ mLayer,
+ RCTMGLStyle(context, mReactStyle, mMap!!)
+ )
+ }
+
+ fun setSourceLayerID(sourceLayerID: String?) {
+ mSourceLayerID = sourceLayerID
+ if (mLayer != null) {
+ mLayer!!.sourceLayer(mSourceLayerID!!)
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayerManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayerManager.kt
new file mode 100644
index 000000000..4e4ebfc17
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillExtrusionLayerManager.kt
@@ -0,0 +1,76 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import com.facebook.react.bridge.ReadableArray
+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
+
+class RCTMGLFillExtrusionLayerManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLFillExtrusionLayer {
+ return RCTMGLFillExtrusionLayer(reactContext)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(layer: RCTMGLFillExtrusionLayer, id: String?) {
+ layer.iD = id
+ }
+
+ @ReactProp(name = "existing")
+ fun setExisting(layer: RCTMGLFillExtrusionLayer, existing: Boolean) {
+ layer.setExisting(existing)
+ }
+
+ @ReactProp(name = "sourceID")
+ fun setSourceID(layer: RCTMGLFillExtrusionLayer, sourceID: String?) {
+ layer.setSourceID(sourceID)
+ }
+
+ @ReactProp(name = "aboveLayerID")
+ fun setAboveLayerID(layer: RCTMGLFillExtrusionLayer, aboveLayerID: String?) {
+ layer.setAboveLayerID(aboveLayerID)
+ }
+
+ @ReactProp(name = "belowLayerID")
+ fun setBelowLayerID(layer: RCTMGLFillExtrusionLayer, belowLayerID: String?) {
+ layer.setBelowLayerID(belowLayerID)
+ }
+
+ @ReactProp(name = "layerIndex")
+ fun setLayerIndex(layer: RCTMGLFillExtrusionLayer, layerIndex: Int) {
+ layer.setLayerIndex(layerIndex)
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(layer: RCTMGLFillExtrusionLayer, minZoomLevel: Double) {
+ layer.setMinZoomLevel(minZoomLevel)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(layer: RCTMGLFillExtrusionLayer, maxZoomLevel: Double) {
+ layer.setMaxZoomLevel(maxZoomLevel)
+ }
+
+ @ReactProp(name = "reactStyle")
+ fun setReactStyle(layer: RCTMGLFillExtrusionLayer, style: ReadableMap?) {
+ layer.setReactStyle(style)
+ }
+
+ @ReactProp(name = "sourceLayerID")
+ fun setSourceLayerId(layer: RCTMGLFillExtrusionLayer, sourceLayerID: String?) {
+ layer.setSourceLayerID(sourceLayerID)
+ }
+
+ @ReactProp(name = "filter")
+ fun setFilter(layer: RCTMGLFillExtrusionLayer, filterList: ReadableArray?) {
+ layer.setFilter(filterList)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLFillExtrusionLayer"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.kt
new file mode 100644
index 000000000..d3bd883c0
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayer.kt
@@ -0,0 +1,40 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import android.content.Context
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.layers.generated.FillLayer
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+
+class RCTMGLFillLayer(context: Context?) : RCTLayer(
+ context!!
+) {
+ private var mSourceLayerID: String? = null
+ override fun updateFilter(expression: Expression?) {
+ mLayer!!.filter(expression!!)
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ }
+
+ override fun makeLayer(): FillLayer {
+ val layer = FillLayer(iD!!, mSourceID!!)
+ if (mSourceLayerID != null) {
+ layer.sourceLayer(mSourceLayerID!!)
+ }
+ return layer
+ }
+
+ override fun addStyles() {
+ RCTMGLStyleFactory.setFillLayerStyle(mLayer, RCTMGLStyle(context, mReactStyle, mMap!!))
+ }
+
+ fun setSourceLayerID(sourceLayerID: String?) {
+ mSourceLayerID = sourceLayerID
+ if (mLayer != null) {
+ mLayer!!.sourceLayer(mSourceLayerID!!)
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayerManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayerManager.kt
new file mode 100644
index 000000000..4679c7f51
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLFillLayerManager.kt
@@ -0,0 +1,76 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import com.facebook.react.bridge.ReadableArray
+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
+
+class RCTMGLFillLayerManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLFillLayer {
+ return RCTMGLFillLayer(reactContext)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(layer: RCTMGLFillLayer, id: String?) {
+ layer.iD = id
+ }
+
+ @ReactProp(name = "existing")
+ fun setExisting(layer: RCTMGLFillLayer, existing: Boolean) {
+ layer.setExisting(existing)
+ }
+
+ @ReactProp(name = "sourceID")
+ fun setSourceID(layer: RCTMGLFillLayer, sourceID: String?) {
+ layer.setSourceID(sourceID)
+ }
+
+ @ReactProp(name = "sourceLayerID")
+ fun setSourceLayerId(layer: RCTMGLFillLayer, sourceLayerID: String?) {
+ layer.setSourceLayerID(sourceLayerID)
+ }
+
+ @ReactProp(name = "aboveLayerID")
+ fun setAboveLayerID(layer: RCTMGLFillLayer, aboveLayerID: String?) {
+ layer.setAboveLayerID(aboveLayerID)
+ }
+
+ @ReactProp(name = "belowLayerID")
+ fun setBelowLayerID(layer: RCTMGLFillLayer, belowLayerID: String?) {
+ layer.setBelowLayerID(belowLayerID)
+ }
+
+ @ReactProp(name = "layerIndex")
+ fun setLayerIndex(layer: RCTMGLFillLayer, layerIndex: Int) {
+ layer.setLayerIndex(layerIndex)
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(layer: RCTMGLFillLayer, minZoomLevel: Double) {
+ layer.setMinZoomLevel(minZoomLevel)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(layer: RCTMGLFillLayer, maxZoomLevel: Double) {
+ layer.setMaxZoomLevel(maxZoomLevel)
+ }
+
+ @ReactProp(name = "reactStyle")
+ fun setReactStyle(layer: RCTMGLFillLayer, style: ReadableMap?) {
+ layer.setReactStyle(style)
+ }
+
+ @ReactProp(name = "filter")
+ fun setFilter(layer: RCTMGLFillLayer, filterList: ReadableArray?) {
+ layer.setFilter(filterList)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLFillLayer"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.kt
new file mode 100644
index 000000000..012492227
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayer.kt
@@ -0,0 +1,40 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import android.content.Context
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.layers.generated.HeatmapLayer
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+
+class RCTMGLHeatmapLayer(context: Context?) : RCTLayer(
+ context!!
+) {
+ private var mSourceLayerID: String? = null
+ override fun updateFilter(expression: Expression?) {
+ mLayer!!.filter(expression!!)
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ }
+
+ override fun makeLayer(): HeatmapLayer {
+ val layer = HeatmapLayer(iD!!, mSourceID!!)
+ if (mSourceLayerID != null) {
+ layer.sourceLayer(mSourceLayerID!!)
+ }
+ return layer
+ }
+
+ override fun addStyles() {
+ RCTMGLStyleFactory.setHeatmapLayerStyle(mLayer, RCTMGLStyle(context, mReactStyle, mMap!!))
+ }
+
+ fun setSourceLayerID(sourceLayerID: String?) {
+ mSourceLayerID = sourceLayerID
+ if (mLayer != null) {
+ mLayer!!.sourceLayer(sourceLayerID!!)
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayerManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayerManager.kt
new file mode 100644
index 000000000..ec08e7a6e
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLHeatmapLayerManager.kt
@@ -0,0 +1,76 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import com.facebook.react.bridge.ReadableArray
+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
+
+class RCTMGLHeatmapLayerManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLHeatmapLayer {
+ return RCTMGLHeatmapLayer(reactContext)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(layer: RCTMGLHeatmapLayer, id: String?) {
+ layer.iD = id
+ }
+
+ @ReactProp(name = "existing")
+ fun setExisting(layer: RCTMGLHeatmapLayer, existing: Boolean) {
+ layer.setExisting(existing)
+ }
+
+ @ReactProp(name = "sourceID")
+ fun setSourceID(layer: RCTMGLHeatmapLayer, sourceID: String?) {
+ layer.setSourceID(sourceID)
+ }
+
+ @ReactProp(name = "aboveLayerID")
+ fun setAboveLayerID(layer: RCTMGLHeatmapLayer, aboveLayerID: String?) {
+ layer.setAboveLayerID(aboveLayerID)
+ }
+
+ @ReactProp(name = "belowLayerID")
+ fun setBelowLayerID(layer: RCTMGLHeatmapLayer, belowLayerID: String?) {
+ layer.setBelowLayerID(belowLayerID)
+ }
+
+ @ReactProp(name = "layerIndex")
+ fun setLayerIndex(layer: RCTMGLHeatmapLayer, layerIndex: Int) {
+ layer.setLayerIndex(layerIndex)
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(layer: RCTMGLHeatmapLayer, minZoomLevel: Double) {
+ layer.setMinZoomLevel(minZoomLevel)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(layer: RCTMGLHeatmapLayer, maxZoomLevel: Double) {
+ layer.setMaxZoomLevel(maxZoomLevel)
+ }
+
+ @ReactProp(name = "reactStyle")
+ fun setReactStyle(layer: RCTMGLHeatmapLayer, style: ReadableMap?) {
+ layer.setReactStyle(style)
+ }
+
+ @ReactProp(name = "sourceLayerID")
+ fun setSourceLayerId(layer: RCTMGLHeatmapLayer, sourceLayerID: String?) {
+ layer.setSourceLayerID(sourceLayerID)
+ }
+
+ @ReactProp(name = "filter")
+ fun setFilter(layer: RCTMGLHeatmapLayer, filterList: ReadableArray?) {
+ layer.setFilter(filterList)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLHeatmapLayer"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.kt
new file mode 100644
index 000000000..6a4f93271
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayer.kt
@@ -0,0 +1,40 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import android.content.Context
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.layers.generated.LineLayer
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+
+class RCTMGLLineLayer(context: Context?) : RCTLayer(
+ context!!
+) {
+ private var mSourceLayerID: String? = null
+ override fun updateFilter(expression: Expression?) {
+ mLayer!!.filter(expression!!)
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ }
+
+ override fun makeLayer(): LineLayer {
+ val layer = LineLayer(iD!!, mSourceID!!)
+ if (mSourceLayerID != null) {
+ layer.sourceLayer(mSourceLayerID!!)
+ }
+ return layer
+ }
+
+ override fun addStyles() {
+ RCTMGLStyleFactory.setLineLayerStyle(mLayer, RCTMGLStyle(context, mReactStyle, mMap!!))
+ }
+
+ fun setSourceLayerID(sourceLayerID: String?) {
+ mSourceLayerID = sourceLayerID
+ if (mLayer != null) {
+ mLayer!!.sourceLayer(mSourceLayerID!!)
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayerManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayerManager.kt
new file mode 100644
index 000000000..606fbf38d
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLLineLayerManager.kt
@@ -0,0 +1,76 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import com.facebook.react.bridge.ReadableArray
+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
+
+class RCTMGLLineLayerManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLLineLayer {
+ return RCTMGLLineLayer(reactContext)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(layer: RCTMGLLineLayer, id: String?) {
+ layer.iD = id
+ }
+
+ @ReactProp(name = "existing")
+ fun setExisting(layer: RCTMGLLineLayer, existing: Boolean) {
+ layer.setExisting(existing)
+ }
+
+ @ReactProp(name = "sourceID")
+ fun setSourceID(layer: RCTMGLLineLayer, sourceID: String?) {
+ layer.setSourceID(sourceID)
+ }
+
+ @ReactProp(name = "aboveLayerID")
+ fun setAboveLayerID(layer: RCTMGLLineLayer, aboveLayerID: String?) {
+ layer.setAboveLayerID(aboveLayerID)
+ }
+
+ @ReactProp(name = "belowLayerID")
+ fun setBelowLayerID(layer: RCTMGLLineLayer, belowLayerID: String?) {
+ layer.setBelowLayerID(belowLayerID)
+ }
+
+ @ReactProp(name = "layerIndex")
+ fun setLayerIndex(layer: RCTMGLLineLayer, layerIndex: Int) {
+ layer.setLayerIndex(layerIndex)
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(layer: RCTMGLLineLayer, minZoomLevel: Double) {
+ layer.setMinZoomLevel(minZoomLevel)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(layer: RCTMGLLineLayer, maxZoomLevel: Double) {
+ layer.setMaxZoomLevel(maxZoomLevel)
+ }
+
+ @ReactProp(name = "reactStyle")
+ fun setReactStyle(layer: RCTMGLLineLayer, style: ReadableMap?) {
+ layer.setReactStyle(style)
+ }
+
+ @ReactProp(name = "sourceLayerID")
+ fun setSourceLayerId(layer: RCTMGLLineLayer, sourceLayerID: String?) {
+ layer.setSourceLayerID(sourceLayerID)
+ }
+
+ @ReactProp(name = "filter")
+ fun setFilter(layer: RCTMGLLineLayer, filterList: ReadableArray?) {
+ layer.setFilter(filterList)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLLineLayer"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.kt
new file mode 100644
index 000000000..af5ce00c4
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayer.kt
@@ -0,0 +1,18 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import android.content.Context
+import com.mapbox.maps.extension.style.layers.generated.RasterLayer
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+
+class RCTMGLRasterLayer(context: Context?) : RCTLayer(
+ context!!
+) {
+ override fun makeLayer(): RasterLayer {
+ return RasterLayer(iD!!, mSourceID!!)
+ }
+
+ override fun addStyles() {
+ RCTMGLStyleFactory.setRasterLayerStyle(mLayer, RCTMGLStyle(context, mReactStyle, mMap!!))
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayerManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayerManager.kt
new file mode 100644
index 000000000..db3f56958
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLRasterLayerManager.kt
@@ -0,0 +1,65 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+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
+
+class RCTMGLRasterLayerManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLRasterLayer {
+ return RCTMGLRasterLayer(reactContext)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(layer: RCTMGLRasterLayer, id: String?) {
+ layer.iD = id
+ }
+
+ @ReactProp(name = "existing")
+ fun setExisting(layer: RCTMGLRasterLayer, existing: Boolean) {
+ layer.setExisting(existing)
+ }
+
+ @ReactProp(name = "sourceID")
+ fun setSourceID(layer: RCTMGLRasterLayer, sourceID: String?) {
+ layer.setSourceID(sourceID)
+ }
+
+ @ReactProp(name = "aboveLayerID")
+ fun setAboveLayerID(layer: RCTMGLRasterLayer, aboveLayerID: String?) {
+ layer.setAboveLayerID(aboveLayerID)
+ }
+
+ @ReactProp(name = "belowLayerID")
+ fun setBelowLayerID(layer: RCTMGLRasterLayer, belowLayerID: String?) {
+ layer.setBelowLayerID(belowLayerID)
+ }
+
+ @ReactProp(name = "layerIndex")
+ fun setLayerIndex(layer: RCTMGLRasterLayer, layerIndex: Int) {
+ layer.setLayerIndex(layerIndex)
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(layer: RCTMGLRasterLayer, minZoomLevel: Double) {
+ layer.setMinZoomLevel(minZoomLevel)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(layer: RCTMGLRasterLayer, maxZoomLevel: Double) {
+ layer.setMaxZoomLevel(maxZoomLevel)
+ }
+
+ @ReactProp(name = "reactStyle")
+ fun setReactStyle(layer: RCTMGLRasterLayer, style: ReadableMap?) {
+ layer.setReactStyle(style)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLRasterLayer"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayer.kt
new file mode 100644
index 000000000..c60c2e0e3
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayer.kt
@@ -0,0 +1,35 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import android.content.Context
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.layers.generated.SkyLayer
+import com.mapbox.rctmgl.components.styles.layers.RCTLayer
+import com.mapbox.rctmgl.utils.Logger.e
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+
+class RCTMGLSkyLayer(context: Context?) : RCTLayer(
+ context!!
+) {
+ private val mSourceLayerID: String? = null
+ override fun updateFilter(expression: Expression?) {
+ mLayer!!.filter(expression!!)
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ }
+
+ override fun makeLayer(): SkyLayer {
+ return SkyLayer(iD!!)
+ }
+
+ override fun addStyles() {
+ RCTMGLStyleFactory.setSkyLayerStyle(mLayer, RCTMGLStyle(context, mReactStyle!!, mMap!!))
+ }
+
+ fun setSourceLayerID(sourceLayerID: String?) {
+ e("RCTMGLSkyLayer", "Source layer should not be set for source layer id")
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayerManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayerManager.kt
new file mode 100644
index 000000000..751ff77b4
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSkyLayerManager.kt
@@ -0,0 +1,76 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import com.facebook.react.bridge.ReadableArray
+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
+
+class RCTMGLSkyLayerManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLSkyLayer {
+ return RCTMGLSkyLayer(reactContext)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(layer: RCTMGLSkyLayer, id: String?) {
+ layer.iD = id
+ }
+
+ @ReactProp(name = "existing")
+ fun setExisting(layer: RCTMGLSkyLayer, existing: Boolean) {
+ layer.setExisting(existing)
+ }
+
+ @ReactProp(name = "sourceID")
+ fun setSourceID(layer: RCTMGLSkyLayer, sourceID: String?) {
+ layer.setSourceID(sourceID)
+ }
+
+ @ReactProp(name = "aboveLayerID")
+ fun setAboveLayerID(layer: RCTMGLLineLayer, aboveLayerID: String?) {
+ layer.setAboveLayerID(aboveLayerID)
+ }
+
+ @ReactProp(name = "belowLayerID")
+ fun setBelowLayerID(layer: RCTMGLLineLayer, belowLayerID: String?) {
+ layer.setBelowLayerID(belowLayerID)
+ }
+
+ @ReactProp(name = "layerIndex")
+ fun setLayerIndex(layer: RCTMGLLineLayer, layerIndex: Int) {
+ layer.setLayerIndex(layerIndex)
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(layer: RCTMGLLineLayer, minZoomLevel: Double) {
+ layer.setMinZoomLevel(minZoomLevel)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(layer: RCTMGLSkyLayer, maxZoomLevel: Double) {
+ layer.setMaxZoomLevel(maxZoomLevel)
+ }
+
+ @ReactProp(name = "reactStyle")
+ fun setReactStyle(layer: RCTMGLSkyLayer, style: ReadableMap?) {
+ layer.setReactStyle(style)
+ }
+
+ @ReactProp(name = "sourceLayerID")
+ fun setSourceLayerId(layer: RCTMGLSkyLayer, sourceLayerID: String?) {
+ layer.setSourceLayerID(sourceLayerID)
+ }
+
+ @ReactProp(name = "filter")
+ fun setFilter(layer: RCTMGLSkyLayer, filterList: ReadableArray?) {
+ layer.setFilter(filterList)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLSkyLayer"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.kt
new file mode 100644
index 000000000..4e986b8dd
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayer.kt
@@ -0,0 +1,40 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import android.content.Context
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.layers.generated.SymbolLayer
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+
+class RCTMGLSymbolLayer(context: Context?) : RCTLayer(
+ context!!
+) {
+ private var mSourceLayerID: String? = null
+ override fun updateFilter(expression: Expression?) {
+ mLayer!!.filter(expression!!)
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ }
+
+ override fun makeLayer(): SymbolLayer {
+ val layer = SymbolLayer(iD!!, mSourceID!!)
+ if (mSourceLayerID != null) {
+ layer.sourceLayer(mSourceLayerID!!)
+ }
+ return layer
+ }
+
+ override fun addStyles() {
+ RCTMGLStyleFactory.setSymbolLayerStyle(mLayer, RCTMGLStyle(context, mReactStyle, mMap!!))
+ }
+
+ fun setSourceLayerID(sourceLayerID: String?) {
+ mSourceLayerID = sourceLayerID
+ if (mLayer != null) {
+ mLayer!!.sourceLayer(sourceLayerID!!)
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayerManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayerManager.kt
new file mode 100644
index 000000000..6dfe6edbe
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/layers/RCTMGLSymbolLayerManager.kt
@@ -0,0 +1,76 @@
+package com.mapbox.rctmgl.components.styles.layers
+
+import com.facebook.react.bridge.ReadableArray
+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
+
+class RCTMGLSymbolLayerManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLSymbolLayer {
+ return RCTMGLSymbolLayer(reactContext)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(layer: RCTMGLSymbolLayer, id: String?) {
+ layer.iD = id
+ }
+
+ @ReactProp(name = "existing")
+ fun setExisting(layer: RCTMGLSymbolLayer, existing: Boolean) {
+ layer.setExisting(existing)
+ }
+
+ @ReactProp(name = "sourceID")
+ fun setSourceID(layer: RCTMGLSymbolLayer, sourceID: String?) {
+ layer.setSourceID(sourceID)
+ }
+
+ @ReactProp(name = "aboveLayerID")
+ fun setAboveLayerID(layer: RCTMGLSymbolLayer, aboveLayerID: String?) {
+ layer.setAboveLayerID(aboveLayerID)
+ }
+
+ @ReactProp(name = "belowLayerID")
+ fun setBelowLayerID(layer: RCTMGLSymbolLayer, belowLayerID: String?) {
+ layer.setBelowLayerID(belowLayerID)
+ }
+
+ @ReactProp(name = "layerIndex")
+ fun setLayerIndex(layer: RCTMGLSymbolLayer, layerIndex: Int) {
+ layer.setLayerIndex(layerIndex)
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(layer: RCTMGLSymbolLayer, minZoomLevel: Double) {
+ layer.setMinZoomLevel(minZoomLevel)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(layer: RCTMGLSymbolLayer, maxZoomLevel: Double) {
+ layer.setMaxZoomLevel(maxZoomLevel)
+ }
+
+ @ReactProp(name = "reactStyle")
+ fun setReactStyle(layer: RCTMGLSymbolLayer, style: ReadableMap?) {
+ layer.setReactStyle(style)
+ }
+
+ @ReactProp(name = "sourceLayerID")
+ fun setSourceLayerId(layer: RCTMGLSymbolLayer, sourceLayerID: String?) {
+ layer.setSourceLayerID(sourceLayerID)
+ }
+
+ @ReactProp(name = "filter")
+ fun setFilter(layer: RCTMGLSymbolLayer, filterList: ReadableArray?) {
+ layer.setFilter(filterList)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLSymbolLayer"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/light/RCTMGLLight.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/light/RCTMGLLight.kt
new file mode 100644
index 000000000..7bbc692b4
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/light/RCTMGLLight.kt
@@ -0,0 +1,50 @@
+package com.mapbox.rctmgl.components.styles.light
+
+import android.content.Context
+import com.mapbox.maps.extension.style.light.generated.setLight
+import com.mapbox.rctmgl.components.AbstractMapFeature
+import com.mapbox.maps.MapboxMap
+import com.facebook.react.bridge.ReadableMap
+import com.mapbox.maps.Style
+import com.mapbox.maps.extension.style.light.generated.Light
+import com.mapbox.rctmgl.components.RemovalReason
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.components.styles.RCTMGLStyleFactory
+import com.mapbox.rctmgl.components.styles.RCTMGLStyle
+
+class RCTMGLLight(context: Context?) : AbstractMapFeature(context) {
+ private var mMap: MapboxMap? = null
+ private var mReactStyle: ReadableMap? = null
+ override fun addToMap(mapView: RCTMGLMapView) {
+ super.addToMap(mapView)
+ mMap = mapView.getMapboxMap()
+ setLight()
+ }
+
+ override fun removeFromMap(mapView: RCTMGLMapView, reason: RemovalReason): Boolean {
+ // ignore there's nothing to remove just update the light style
+ return super.removeFromMap(mapView, reason)
+ }
+
+ fun setReactStyle(reactStyle: ReadableMap?) {
+ mReactStyle = reactStyle
+ setLight()
+ }
+
+ private fun setLight(light: Light) {
+ RCTMGLStyleFactory.setLightLayerStyle(light, RCTMGLStyle(context, mReactStyle!!, mMap!!))
+ style!!.setLight(light)
+ }
+
+ private fun setLight() {
+ if (style != null) {
+ val light = Light()
+ setLight(light)
+ }
+ }
+
+ private val style: Style?
+ private get() = if (mMap == null) {
+ null
+ } else mMap!!.getStyle()
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/light/RCTMGLLightManager.java b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/light/RCTMGLLightManager.java
new file mode 100644
index 000000000..0bed87e7f
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/light/RCTMGLLightManager.java
@@ -0,0 +1,25 @@
+package com.mapbox.rctmgl.components.styles.light;
+
+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;
+
+public class RCTMGLLightManager extends ViewGroupManager {
+ public static final String REACT_CLASS = "RCTMGLLight";
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+
+ @Override
+ protected RCTMGLLight createViewInstance(ThemedReactContext reactContext) {
+ return new RCTMGLLight(reactContext);
+ }
+
+ @ReactProp(name="reactStyle")
+ public void setReactStyle(RCTMGLLight light, ReadableMap reactStyle) {
+ light.setReactStyle(reactStyle);
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/AbstractSourceConsumer.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/AbstractSourceConsumer.kt
new file mode 100644
index 000000000..9a6ade9b3
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/AbstractSourceConsumer.kt
@@ -0,0 +1,8 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.content.Context
+import com.mapbox.rctmgl.components.AbstractMapFeature
+
+abstract class AbstractSourceConsumer(context: Context?) : AbstractMapFeature(context) {
+ abstract val iD: String?
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSource.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSource.kt
new file mode 100644
index 000000000..f50cd4fad
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSource.kt
@@ -0,0 +1,69 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.content.Context
+import android.net.Uri
+import android.util.Log
+import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper
+import com.mapbox.maps.extension.style.sources.generated.ImageSource
+import com.mapbox.rctmgl.utils.LatLngQuad
+import java.net.URL
+
+class RCTMGLImageSource(context: Context?) : RCTSource(context) {
+ private var mURL: URL? = null
+ private var mResourceId = 0
+ private var mCoordQuad: LatLngQuad? = null
+
+ override fun hasNoDataSoRefersToExisting(): Boolean {
+ return mURL == null
+ }
+
+ override fun makeSource(): ImageSource? {
+ if (mURL == null) {
+ throw RuntimeException("ImageSource without URL not supported in v10, resourceId is not supported")
+ }
+ val id = iD;
+ if (id == null) {
+ throw RuntimeException("ImageSource without ID not supported in v10")
+ }
+ return ImageSource.Builder(id).coordinates(mCoordQuad!!.coordinates).url(mURL.toString()).build()
+ }
+
+ override fun onPress(feature: OnPressEvent?) {
+ // ignore, we cannot query raster layers
+ }
+
+ fun setURL(url: String?) {
+ try {
+ val uri = Uri.parse(url)
+ if (uri.scheme == null) {
+ mResourceId =
+ ResourceDrawableIdHelper.getInstance().getResourceDrawableId(this.context, url)
+ if (mSource != null) {
+ throw RuntimeException("ImageSource Resource id not supported in v10")
+ }
+ } else {
+ mURL = URL(url)
+ if (mSource != null) {
+ mSource!!.url(mURL.toString())
+ }
+ }
+ } catch (e: Exception) {
+ Log.w(LOG_TAG, e.localizedMessage)
+ }
+ }
+
+ fun setCoordinates(coordQuad: LatLngQuad?) {
+ mCoordQuad = coordQuad
+ try {
+ if (mSource != null) {
+ mSource!!.coordinates(mCoordQuad!!.coordinates)
+ }
+ } catch (e: Exception) {
+ Log.w(LOG_TAG, e.localizedMessage)
+ }
+ }
+
+ companion object {
+ const val LOG_TAG = "RCTMGLImageSource"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSourceManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSourceManager.kt
new file mode 100644
index 000000000..8eb54f994
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLImageSourceManager.kt
@@ -0,0 +1,54 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.view.View
+import com.facebook.react.bridge.ReadableArray
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.ViewGroupManager
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.mapbox.rctmgl.utils.GeoJSONUtils.toLatLngQuad
+
+class RCTMGLImageSourceManager : ViewGroupManager() {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLImageSource {
+ return RCTMGLImageSource(reactContext)
+ }
+
+ override fun getChildAt(source: RCTMGLImageSource, childPosition: Int): View {
+ return source.getChildAt(childPosition)
+ }
+
+ override fun getChildCount(source: RCTMGLImageSource): Int {
+ return source.childCount
+ }
+
+ override fun addView(source: RCTMGLImageSource, childView: View, childPosition: Int) {
+ source.addLayer(childView, childPosition)
+ }
+
+ override fun removeViewAt(source: RCTMGLImageSource, childPosition: Int) {
+ source.removeLayer(childPosition)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(source: RCTMGLImageSource, id: String?) {
+ source.iD = id
+ }
+
+ @ReactProp(name = "url")
+ fun setUrl(source: RCTMGLImageSource, url: String?) {
+ source.setURL(url)
+ }
+
+ @ReactProp(name = "coordinates")
+ fun setCoordinates(source: RCTMGLImageSource, arr: ReadableArray?) {
+ val quad = toLatLngQuad(arr) ?: return
+ source.setCoordinates(quad)
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLImageSource"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterDemSource.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterDemSource.kt
new file mode 100644
index 000000000..6080c48e7
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterDemSource.kt
@@ -0,0 +1,82 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.content.Context
+import androidx.annotation.Size
+import com.facebook.react.bridge.WritableMap
+import com.facebook.react.bridge.WritableNativeMap
+import com.mapbox.geojson.Feature
+import com.mapbox.geojson.FeatureCollection
+import com.mapbox.maps.SourceQueryOptions
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.sources.generated.RasterDemSource
+import com.mapbox.maps.extension.style.sources.getSource
+import com.mapbox.rctmgl.events.AndroidCallbackEvent
+import com.mapbox.rctmgl.events.FeatureClickEvent
+import com.mapbox.rctmgl.utils.Logger
+import java.util.*
+
+// import com.mapbox.rctmgl.R;
+// import com.mapbox.rctmgl.utils.DownloadMapImageTask;
+class RCTMGLRasterDemSource(context: Context?, private val mManager: RCTMGLRasterDemSourceManager) :
+ RCTMGLTileSource(context) {
+ override fun onPress(event: OnPressEvent?) {
+ mManager.handleEvent(FeatureClickEvent.makeVectorSourceEvent(this, event))
+ }
+
+ override fun makeSource(): RasterDemSource? {
+ val id = iD
+ if (id == null) {
+ Logger.w("RCTMGLRasterDemSource", "id is required")
+ return null
+ }
+ if (isDefaultSource(id)) {
+ return mMap!!.getStyle()!!.getSource(DEFAULT_ID) as RasterDemSource
+ }
+ val configurationUrl = uRL
+ return if (configurationUrl != null) {
+ RasterDemSource(
+ RasterDemSource.Builder(id)
+ .url(configurationUrl)
+ )
+ } else RasterDemSource(
+ RasterDemSource.Builder(id)
+ .tileSet(buildTileset())
+ )
+ }
+
+ fun querySourceFeatures(
+ callbackID: String?,
+ @Size(min = 1) layerIDs: List?,
+ filter: Expression?
+ ) {
+ if (mSource == null) {
+ val payload: WritableMap = WritableNativeMap()
+ payload.putString("error", "source is not yet loaded")
+ val event = AndroidCallbackEvent(this, callbackID, payload)
+ mManager.handleEvent(event)
+ return
+ }
+ val payload: WritableMap = WritableNativeMap()
+ mMap!!.querySourceFeatures(
+ iD!!,
+ SourceQueryOptions(layerIDs, filter!!)
+ ) { queriedFeatures ->
+ if (queriedFeatures.isError) {
+ //V10todo
+ payload.putString("error", queriedFeatures.error)
+ } else {
+ val features: MutableList = LinkedList()
+ for (feature in queriedFeatures.value!!) {
+ features.add(feature.feature)
+ }
+ payload.putString("data", FeatureCollection.fromFeatures(features).toJson())
+ }
+ }
+ val event = AndroidCallbackEvent(this, callbackID, payload)
+ mManager.handleEvent(event)
+ }
+
+ override fun hasNoDataSoRefersToExisting(): Boolean {
+ return uRL == null && tileUrlTemplates.isEmpty()
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterDemSourceManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterDemSourceManager.kt
new file mode 100644
index 000000000..ce2a8a501
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterDemSourceManager.kt
@@ -0,0 +1,30 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.common.MapBuilder
+import com.facebook.react.uimanager.ThemedReactContext
+
+// import com.mapbox.rctmgl.components.annotation.RCTMGLCallout;
+// import com.mapbox.rctmgl.utils.ResourceUtils;
+class RCTMGLRasterDemSourceManager(private val mContext: ReactApplicationContext) :
+ RCTMGLTileSourceManager(
+ mContext
+ ) {
+ override fun customEvents(): Map? {
+ return MapBuilder.builder()
+ .build()
+ }
+
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLRasterDemSource {
+ return RCTMGLRasterDemSource(reactContext, this)
+ }
+
+ companion object {
+ const val LOG_TAG = "RCTMGLRasterDemSourceManager"
+ const val REACT_CLASS = "RCTMGLRasterDemSource"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSource.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSource.kt
new file mode 100644
index 000000000..cf4e834ae
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSource.kt
@@ -0,0 +1,37 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.content.Context
+import com.mapbox.maps.extension.style.sources.generated.RasterSource
+
+class RCTMGLRasterSource(context: Context?) : RCTMGLTileSource(context) {
+ private var mTileSize: Int? = null
+ override fun makeSource(): RasterSource {
+ val id = iD!!
+ val configurationUrl = uRL
+ val tileSize = if (mTileSize == null) DEFAULT_TILE_SIZE else mTileSize!!
+ return if (configurationUrl != null) {
+ RasterSource.Builder(id).url(configurationUrl).tileSize(tileSize.toLong()).build()
+ } else RasterSource.Builder(id).tileSet(buildTileset())
+ .tileSize(tileSize.toLong()).build()
+ }
+
+ fun setTileSize(tileSize: Int) {
+ mTileSize = tileSize
+ }
+
+ override fun hasPressListener(): Boolean {
+ return false
+ }
+
+ override fun onPress(feature: OnPressEvent?) {
+ // ignore, cannot query raster layers
+ }
+
+ override fun hasNoDataSoRefersToExisting(): Boolean {
+ return uRL == null
+ }
+
+ companion object {
+ const val DEFAULT_TILE_SIZE = 512
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSourceManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSourceManager.kt
new file mode 100644
index 000000000..1434c841a
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLRasterSourceManager.kt
@@ -0,0 +1,32 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.annotations.ReactProp
+import javax.annotation.Nonnull
+
+class RCTMGLRasterSourceManager(reactApplicationContext: ReactApplicationContext) :
+ RCTMGLTileSourceManager(reactApplicationContext) {
+ @Nonnull
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ @Nonnull
+ override fun createViewInstance(@Nonnull reactContext: ThemedReactContext): RCTMGLRasterSource {
+ return RCTMGLRasterSource(reactContext)
+ }
+
+ @ReactProp(name = "tileSize")
+ fun setTileSize(source: RCTMGLRasterSource, tileSize: Int) {
+ source.setTileSize(tileSize)
+ }
+
+ override fun customEvents(): Map? {
+ return null
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLRasterSource"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSource.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSource.kt
new file mode 100644
index 000000000..a7b214883
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSource.kt
@@ -0,0 +1,273 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.content.Context
+import com.mapbox.maps.extension.style.sources.generated.GeoJsonSource
+import com.mapbox.rctmgl.utils.ImageEntry
+import android.graphics.drawable.BitmapDrawable
+import com.facebook.react.bridge.ReadableMap
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.rctmgl.events.FeatureClickEvent
+import com.facebook.react.bridge.WritableMap
+import com.facebook.react.bridge.WritableNativeMap
+import com.mapbox.bindgen.Value
+import com.mapbox.geojson.Feature
+import com.mapbox.rctmgl.events.AndroidCallbackEvent
+import com.mapbox.geojson.FeatureCollection
+import com.mapbox.maps.*
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.rctmgl.utils.Logger
+import java.net.URL
+import java.util.ArrayList
+import java.util.HashMap
+
+class RCTMGLShapeSource(context: Context, private val mManager: RCTMGLShapeSourceManager) :
+ RCTSource(context) {
+ private var mURL: URL? = null
+ private var mShape: String? = null
+ private var mCluster: Boolean? = null
+ private var mClusterRadius: Long? = null
+ private var mClusterMaxZoom: Long? = null
+ private var mClusterProperties: HashMap? = null
+ private var mMaxZoom: Long? = null
+ private var mBuffer: Long? = null
+ private var mTolerance: Double? = null
+ private var mLineMetrics: Boolean? = null
+ private val mImages: List>? = null
+ private val mNativeImages: List>? = null
+
+ override fun hasNoDataSoRefersToExisting(): Boolean {
+ return (mURL == null) && (mShape == null)
+ }
+
+ override fun addToMap(mapView: RCTMGLMapView) {
+ // Wait for style before adding the source to the map
+ mapView.getMapboxMap().getStyle {
+ val map = mapView.getMapboxMap()
+ super@RCTMGLShapeSource.addToMap(mapView)
+ }
+ }
+
+ override fun makeSource(): GeoJsonSource {
+ val builder = GeoJsonSource.Builder(iD.toString())
+ getOptions(builder)
+
+ builder.data(mShape ?: mURL.toString())
+
+ return builder.build()
+ }
+
+ fun setURL(url: URL) {
+ mURL = url
+ if (mSource != null && mMapView != null && !mMapView!!.isDestroyed) {
+ mSource!!.data(mURL.toString())
+ }
+ }
+
+ fun setShape(geoJSONStr: String) {
+ mShape = geoJSONStr
+ if (mSource != null && mMapView != null && !mMapView!!.isDestroyed) {
+ mSource!!.data(mShape!!)
+ val result = mMap!!.getStyle()!!
+ .setStyleSourceProperty(iD!!, "data", Value.valueOf(mShape!!))
+ }
+ }
+
+ fun setCluster(cluster: Boolean) {
+ mCluster = cluster
+ }
+
+ fun setClusterRadius(clusterRadius: Long) {
+ mClusterRadius = clusterRadius
+ }
+
+ fun setClusterMaxZoom(clusterMaxZoom: Long) {
+ mClusterMaxZoom = clusterMaxZoom
+ if (mSource != null && mMapView != null && !mMapView!!.isDestroyed) {
+ val result = mMap!!.getStyle()!!
+ .setStyleSourceProperty(iD!!, "clusterMaxZoom", Value.valueOf(clusterMaxZoom))
+ }
+ }
+
+ fun setClusterProperties(clusterProperties: HashMap) {
+ mClusterProperties = clusterProperties
+ }
+
+ fun setMaxZoom(maxZoom: Long) {
+ mMaxZoom = maxZoom
+ }
+
+ fun setBuffer(buffer: Long) {
+ mBuffer = buffer
+ }
+
+ fun setTolerance(tolerance: Double) {
+ mTolerance = tolerance
+ }
+
+ fun setLineMetrics(lineMetrics: Boolean) {
+ mLineMetrics = lineMetrics
+ }
+
+ override fun onPress(event: OnPressEvent?) {
+ mManager.handleEvent(FeatureClickEvent.makeShapeSourceEvent(this, event))
+ }
+
+ private fun getOptions(builder: GeoJsonSource.Builder) {
+ if (mCluster != null) {
+ builder.cluster(mCluster!!)
+ }
+ if (mClusterRadius != null) {
+ builder.clusterRadius(mClusterRadius!!)
+ }
+ if (mClusterMaxZoom != null) {
+ builder.clusterMaxZoom(mClusterMaxZoom!!)
+ }
+ if (mClusterProperties != null) {
+ builder.clusterProperties(mClusterProperties!!)
+ }
+ if (mMaxZoom != null) {
+ builder.maxzoom(mMaxZoom!!)
+ }
+ if (mBuffer != null) {
+ builder.buffer(mBuffer!!)
+ }
+ if (mTolerance != null) {
+ builder.tolerance(mTolerance!!)
+ }
+ if (mLineMetrics != null) {
+ builder.lineMetrics(mLineMetrics!!)
+ }
+ }
+
+ fun querySourceFeatures(
+ callbackID: String,
+ filter: Expression?
+ ) {
+ if (mSource == null) {
+ val payload: WritableMap = WritableNativeMap()
+ payload.putString("error", "source is not yet loaded")
+ val event = AndroidCallbackEvent(this, callbackID, payload)
+ mManager.handleEvent(event)
+ return
+ }
+ val _this = this
+ mMap!!.querySourceFeatures(
+ iD!!, SourceQueryOptions(
+ null, // v10todo
+ filter!!
+ )
+ ) { features ->
+ if (features.isError) {
+ Logger.e("RCTMGLShapeSource", String.format("Error: %s", features.error))
+ } else {
+ val payload: WritableMap = WritableNativeMap()
+ val result: MutableList = ArrayList(
+ features.value!!.size
+ )
+ for (i in features.value!!) {
+ result.add(i.feature)
+ }
+ payload.putString("data", FeatureCollection.fromFeatures(result).toJson())
+ val event = AndroidCallbackEvent(_this, callbackID, payload)
+ mManager.handleEvent(event)
+ }
+ }
+ }
+
+ private fun callbackSuccess(callbackID: String, payload: WritableMap) {
+ val event = AndroidCallbackEvent(this, callbackID, payload)
+ mManager.handleEvent(event)
+ }
+ private fun callbackError(callbackID: String, error: String, where: String) {
+ val payload: WritableMap = WritableNativeMap()
+ payload.putString("error", "$where: $error")
+ val event = AndroidCallbackEvent(this, callbackID, payload)
+ mManager.handleEvent(event)
+ }
+
+ fun getClusterExpansionZoom(callbackID: String, featureJSON: String) {
+ val feature = Feature.fromJson(featureJSON)
+
+ mMap!!.getGeoJsonClusterExpansionZoom(iD!!, feature, QueryFeatureExtensionCallback { features ->
+ if (features.isValue) {
+ val contents = features.value!!.value!!.contents
+ val payload: WritableMap = WritableNativeMap()
+
+ if (contents is Long) {
+ val payload: WritableMap = WritableNativeMap()
+ payload.putInt("data", contents.toInt())
+ callbackSuccess(callbackID, payload)
+ return@QueryFeatureExtensionCallback
+ } else {
+ callbackError(
+ callbackID,
+ "Not a number: $contents",
+ "getClusterExpansionZoom/getGeoJsonClusterExpansionZoom"
+ )
+ return@QueryFeatureExtensionCallback
+ }
+ } else {
+ callbackError(
+ callbackID,
+ features.error ?: "Unknown error",
+ "getClusterExpansionZoom/getGeoJsonClusterExpansionZoom"
+ )
+ return@QueryFeatureExtensionCallback
+ }
+ })
+ }
+
+ fun getClusterLeaves(callbackID: String, featureJSON: String, number: Int, offset: Int) {
+ val feature = Feature.fromJson(featureJSON)
+
+ val _this = this
+ mMap!!.getGeoJsonClusterLeaves(iD!!, feature, number.toLong(), offset.toLong(), QueryFeatureExtensionCallback { features ->
+ if (features.isValue) {
+ val leaves = features.value!!
+ .featureCollection
+ val payload: WritableMap = WritableNativeMap()
+ payload.putString(
+ "data",
+ FeatureCollection.fromFeatures(leaves!!).toJson()
+ )
+ callbackSuccess(callbackID, payload)
+ } else {
+ callbackError(
+ callbackID,
+ features.error ?: "Unknown error",
+ "getClusterLeaves/getGeoJsonClusterLeaves"
+ )
+ return@QueryFeatureExtensionCallback
+ }
+ })
+ }
+
+ fun getClusterChildren(callbackID: String, featureJSON: String) {
+ val feature = Feature.fromJson(featureJSON)
+
+ val _this = this
+ mMap!!.getGeoJsonClusterChildren(iD!!, feature, QueryFeatureExtensionCallback { features ->
+ if (features.isValue) {
+ val children = features.value!!
+ .featureCollection
+ val payload: WritableMap = WritableNativeMap()
+ payload.putString(
+ "data",
+ FeatureCollection.fromFeatures(children!!).toJson()
+ )
+ callbackSuccess(callbackID, payload)
+ }else {
+ callbackError(
+ callbackID,
+ features.error ?: "Unknown error",
+ "getClusterLeaves/queryFeatureExtensions"
+ )
+ return@QueryFeatureExtensionCallback
+ }
+ })
+ }
+
+ /*companion object {
+ private val mImagePlaceholder: Bitmap? = null
+ }*/
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.kt
new file mode 100644
index 000000000..a52f7e89e
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLShapeSourceManager.kt
@@ -0,0 +1,204 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.util.Log
+import android.view.View
+import com.facebook.react.bridge.ReactApplicationContext
+import com.mapbox.rctmgl.components.AbstractEventEmitter
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.facebook.react.bridge.ReadableMap
+import com.facebook.react.bridge.ReadableArray
+import com.facebook.react.bridge.ReadableType
+import com.facebook.react.common.MapBuilder
+import com.mapbox.bindgen.Value
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.rctmgl.events.constants.EventKeys
+import com.mapbox.rctmgl.utils.ExpressionParser
+import com.mapbox.rctmgl.utils.Logger
+import java.net.MalformedURLException
+import java.net.URL
+import java.util.ArrayList
+import java.util.HashMap
+
+
+class RCTMGLShapeSourceManager(private val mContext: ReactApplicationContext) :
+ AbstractEventEmitter(
+ mContext
+ ) {
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ override fun createViewInstance(reactContext: ThemedReactContext): RCTMGLShapeSource {
+ return RCTMGLShapeSource(reactContext, this)
+ }
+
+ override fun getChildAt(source: RCTMGLShapeSource, childPosition: Int): View {
+ return source.getChildAt(childPosition)
+ }
+
+ override fun getChildCount(source: RCTMGLShapeSource): Int {
+ return source.childCount
+ }
+
+ override fun addView(source: RCTMGLShapeSource, childView: View, childPosition: Int) {
+ source.addLayer(childView, getChildCount(source))
+ }
+
+ override fun removeViewAt(source: RCTMGLShapeSource, childPosition: Int) {
+ source.removeLayer(childPosition)
+ }
+
+ @ReactProp(name = "id")
+ fun setId(source: RCTMGLShapeSource, id: String) {
+ source.iD = id
+ }
+
+ @ReactProp(name = "existing")
+ fun setExisting(source: RCTMGLShapeSource, existing: Boolean) {
+ source.mExisting = existing;
+ }
+
+ @ReactProp(name = "url")
+ fun setURL(source: RCTMGLShapeSource, urlStr: String) {
+ try {
+ source.setURL(URL(urlStr))
+ } catch (e: MalformedURLException) {
+ Logger.w(LOG_TAG, e.localizedMessage ?: "Unknown URL error")
+ }
+ }
+
+ @ReactProp(name = "shape")
+ fun setGeometry(source: RCTMGLShapeSource, geoJSONStr: String) {
+ source.setShape(geoJSONStr)
+ }
+
+ @ReactProp(name = "cluster")
+ fun setCluster(source: RCTMGLShapeSource, cluster: Int) {
+ source.setCluster(cluster == 1)
+ }
+
+ @ReactProp(name = "clusterRadius")
+ fun setClusterRadius(source: RCTMGLShapeSource, radius: Int) {
+ source.setClusterRadius(radius.toLong())
+ }
+
+ @ReactProp(name = "clusterMaxZoomLevel")
+ fun setClusterMaxZoomLevel(source: RCTMGLShapeSource, clusterMaxZoom: Int) {
+ source.setClusterMaxZoom(clusterMaxZoom.toLong())
+ }
+
+ @ReactProp(name = "clusterProperties")
+ fun setClusterProperties(source: RCTMGLShapeSource, map: ReadableMap) {
+ val properties = HashMap()
+ val iterator = map.keySetIterator()
+ while (iterator.hasNextKey()) {
+ val name = iterator.nextKey()
+ val expressions = map.getArray(name)
+ val builder: MutableList = ArrayList()
+ for (iExp in 0 until expressions!!.size()) {
+ var argument: Expression
+ argument = when (expressions.getType(iExp)) {
+ ReadableType.Array -> ExpressionParser.from(
+ expressions.getArray(iExp)
+ )!!
+ ReadableType.Map -> ExpressionParser.from(
+ expressions.getMap(iExp)
+ )
+ ReadableType.Boolean -> Expression.literal(expressions.getBoolean(iExp))
+ ReadableType.Number -> Expression.literal(expressions.getDouble(iExp))
+ else -> Expression.literal(expressions.getString(iExp))
+ }
+ builder.add(argument)
+ }
+ properties[name] = Value(builder)
+ }
+ source.setClusterProperties(properties)
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(source: RCTMGLShapeSource, maxZoom: Int) {
+ source.setMaxZoom(maxZoom.toLong())
+ }
+
+ @ReactProp(name = "buffer")
+ fun setBuffer(source: RCTMGLShapeSource, buffer: Int) {
+ source.setBuffer(buffer.toLong())
+ }
+
+ @ReactProp(name = "tolerance")
+ fun setTolerance(source: RCTMGLShapeSource, tolerance: Double) {
+ source.setTolerance(tolerance)
+ }
+
+ @ReactProp(name = "lineMetrics")
+ fun setLineMetrics(source: RCTMGLShapeSource, lineMetrics: Boolean) {
+ source.setLineMetrics(lineMetrics)
+ }
+
+ @ReactProp(name = "hasPressListener")
+ fun setHasPressListener(source: RCTMGLShapeSource, hasPressListener: Boolean) {
+ source.setHasPressListener(hasPressListener)
+ }
+
+ @ReactProp(name = "hitbox")
+ fun setHitbox(source: RCTMGLShapeSource, map: ReadableMap) {
+ source.setHitbox(map)
+ }
+
+ override fun customEvents(): Map? {
+ return MapBuilder.builder()
+ .put(EventKeys.SHAPE_SOURCE_LAYER_CLICK, "onMapboxShapeSourcePress")
+ .put(EventKeys.MAP_ANDROID_CALLBACK, "onAndroidCallback")
+ .build()
+ }
+
+ override fun getCommandsMap(): Map? {
+ return MapBuilder.builder()
+ .put("features", METHOD_FEATURES)
+ .put("getClusterExpansionZoom", METHOD_GET_CLUSTER_EXPANSION_ZOOM)
+ .put("getClusterLeaves", METHOD_GET_CLUSTER_LEAVES)
+ .put("getClusterChildren", METHOD_GET_CLUSTER_CHILDREN)
+ .build()
+ }
+
+ override fun receiveCommand(source: RCTMGLShapeSource, commandID: Int, args: ReadableArray?) {
+ if (args == null) {
+ return
+ }
+
+ val callbackID = args.getString(0);
+
+ when (commandID) {
+ METHOD_FEATURES -> source.querySourceFeatures(
+ callbackID,
+ ExpressionParser.from(args.getArray(1))
+ )
+ METHOD_GET_CLUSTER_EXPANSION_ZOOM -> source.getClusterExpansionZoom(
+ callbackID,
+ args.getString(1)
+ )
+ METHOD_GET_CLUSTER_LEAVES -> source.getClusterLeaves(
+ callbackID,
+ args.getString(1),
+ args.getInt(2),
+ args.getInt(3)
+ )
+ METHOD_GET_CLUSTER_CHILDREN -> source.getClusterChildren(
+ callbackID,
+ args.getString(1)
+ )
+ }
+ }
+
+ companion object {
+ const val LOG_TAG = "RCTMGLShapeSourceMgr"
+ const val REACT_CLASS = "RCTMGLShapeSource"
+
+ //region React Methods
+ const val METHOD_FEATURES = 103
+ const val METHOD_GET_CLUSTER_EXPANSION_ZOOM = 104
+ const val METHOD_GET_CLUSTER_LEAVES = 105
+ const val METHOD_GET_CLUSTER_CHILDREN = 106
+ }
+}
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSource.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSource.kt
new file mode 100644
index 000000000..6e6c7a729
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSource.kt
@@ -0,0 +1,44 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.accessibilityservice.GestureDescription
+import android.content.Context
+import com.mapbox.maps.extension.style.sources.Source
+import com.mapbox.maps.extension.style.sources.TileSet
+import com.mapbox.maps.extension.style.sources.generated.Scheme
+import java.util.*
+
+abstract class RCTMGLTileSource(context: Context?) : RCTSource(context) {
+ var uRL: String? = null
+ public var tileUrlTemplates: Collection = ArrayList()
+ var attribution: String? = null
+ var minZoomLevel: Int? = null
+ var maxZoomLevel: Int? = null
+ var tMS = false
+ fun buildTileset(): TileSet {
+ val tileUrlTemplates =
+ tileUrlTemplates.toTypedArray()
+
+ val builder = TileSet.Builder(
+ TILE_SPEC_VERSION,
+ Arrays.asList(*tileUrlTemplates.clone())
+ )
+ if (minZoomLevel != null) {
+ builder.minZoom(minZoomLevel!!.toFloat().toInt())
+ }
+ if (maxZoomLevel != null) {
+ builder.maxZoom(maxZoomLevel!!.toFloat().toInt())
+ }
+ if (tMS) {
+ builder.scheme(Scheme.TMS)
+ }
+ val attribution = this.attribution
+ if (attribution != null) {
+ builder.attribution(attribution)
+ }
+ return builder.build()
+ }
+
+ companion object {
+ const val TILE_SPEC_VERSION = "2.1.0"
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSourceManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSourceManager.kt
new file mode 100644
index 000000000..28eb1dc46
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLTileSourceManager.kt
@@ -0,0 +1,69 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.view.View
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.bridge.ReadableArray
+import com.facebook.react.bridge.ReadableType
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.mapbox.rctmgl.components.AbstractEventEmitter
+
+abstract class RCTMGLTileSourceManager?> internal constructor(
+ reactApplicationContext: ReactApplicationContext
+) : AbstractEventEmitter(reactApplicationContext) {
+ override fun getChildAt(source: T, childPosition: Int): View {
+ return source!!.getChildAt(childPosition)
+ }
+
+ override fun getChildCount(source: T): Int {
+ return source!!.childCount
+ }
+
+ override fun addView(source: T, childView: View, childPosition: Int) {
+ source!!.addLayer(childView, childPosition)
+ }
+
+ override fun removeViewAt(source: T, childPosition: Int) {
+ source!!.removeLayer(childPosition)
+ }
+
+ @ReactProp(name = "id")
+ fun setID(source: T, id: String?) {
+ source!!.iD = id
+ }
+
+ @ReactProp(name = "url")
+ fun setURL(source: T, url: String?) {
+ source!!.uRL = url
+ }
+
+ @ReactProp(name = "tileUrlTemplates")
+ fun setTileUrlTemplates(source: T, tileUrlTemplates: ReadableArray) {
+ val urls: MutableList = ArrayList()
+ for (i in 0 until tileUrlTemplates.size()) {
+ if (tileUrlTemplates.getType(0) == ReadableType.String) {
+ urls.add(tileUrlTemplates.getString(i))
+ }
+ }
+ source!!.tileUrlTemplates = urls
+ }
+
+ @ReactProp(name = "attribution")
+ fun setAttribution(source: T, attribution: String?) {
+ source!!.attribution = attribution
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ fun setMinZoomLevel(source: T, minZoomLevel: Int) {
+ source!!.minZoomLevel = minZoomLevel
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ fun setMaxZoomLevel(source: T, maxZoomLevel: Int) {
+ source!!.maxZoomLevel = maxZoomLevel
+ }
+
+ @ReactProp(name = "tms")
+ fun setTMS(source: T, tms: Boolean) {
+ source!!.tMS = tms
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSource.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSource.kt
new file mode 100644
index 000000000..89f1732e6
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSource.kt
@@ -0,0 +1,78 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.content.Context
+import androidx.annotation.Size
+import com.facebook.react.bridge.WritableMap
+import com.facebook.react.bridge.WritableNativeMap
+import com.mapbox.geojson.Feature
+import com.mapbox.geojson.FeatureCollection
+import com.mapbox.maps.SourceQueryOptions
+import com.mapbox.maps.extension.style.expressions.generated.Expression
+import com.mapbox.maps.extension.style.sources.generated.VectorSource
+import com.mapbox.maps.extension.style.sources.getSource
+import com.mapbox.rctmgl.events.AndroidCallbackEvent
+import com.mapbox.rctmgl.events.FeatureClickEvent
+import java.util.*
+
+class RCTMGLVectorSource(context: Context?, private val mManager: RCTMGLVectorSourceManager) :
+ RCTMGLTileSource(context) {
+ override fun onPress(event: OnPressEvent?) {
+ mManager.handleEvent(FeatureClickEvent.makeVectorSourceEvent(this, event))
+ }
+
+ override fun hasNoDataSoRefersToExisting(): Boolean {
+ return uRL == null;
+ }
+
+ override fun makeSource(): VectorSource {
+ val id = iD
+ if (id == null) {
+ throw RuntimeException("id should be specified for VectorSource");
+ }
+ if (isDefaultSource(id)) {
+ return mMap!!.getStyle()!!.getSource(DEFAULT_ID) as VectorSource
+ }
+ val configurationUrl = uRL
+ return if (configurationUrl != null) {
+ VectorSource(
+ VectorSource.Builder(id)
+ .url(configurationUrl)
+ )
+ } else VectorSource(
+ VectorSource.Builder(id)
+ .tileSet(buildTileset())
+ )
+ }
+
+ fun querySourceFeatures(
+ callbackID: String?,
+ @Size(min = 1) layerIDs: List?,
+ filter: Expression?
+ ) {
+ if (mSource == null) {
+ val payload: WritableMap = WritableNativeMap()
+ payload.putString("error", "source is not yet loaded")
+ val event = AndroidCallbackEvent(this, callbackID, payload)
+ mManager.handleEvent(event)
+ return
+ }
+ mMap!!.querySourceFeatures(
+ iD!!,
+ SourceQueryOptions(layerIDs, filter!!)
+ ) { queriedFeatures ->
+ val payload: WritableMap = WritableNativeMap()
+ if (queriedFeatures.isError) {
+ //V10todo
+ payload.putString("error", queriedFeatures.error)
+ } else {
+ val features: MutableList = LinkedList()
+ for (feature in queriedFeatures.value!!) {
+ features.add(feature.feature)
+ }
+ payload.putString("data", FeatureCollection.fromFeatures(features).toJson())
+ }
+ val event = AndroidCallbackEvent(this@RCTMGLVectorSource, callbackID, payload)
+ mManager.handleEvent(event)
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSourceManager.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSourceManager.kt
new file mode 100644
index 000000000..075f73d34
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTMGLVectorSourceManager.kt
@@ -0,0 +1,69 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import com.facebook.react.bridge.ReactApplicationContext
+import com.facebook.react.bridge.ReadableArray
+import com.facebook.react.bridge.ReadableMap
+import com.facebook.react.common.MapBuilder
+import com.facebook.react.uimanager.ThemedReactContext
+import com.facebook.react.uimanager.annotations.ReactProp
+import com.mapbox.rctmgl.events.constants.EventKeys
+import com.mapbox.rctmgl.utils.ConvertUtils
+import com.mapbox.rctmgl.utils.ExpressionParser
+import javax.annotation.Nonnull
+
+class RCTMGLVectorSourceManager(reactApplicationContext: ReactApplicationContext) :
+ RCTMGLTileSourceManager(reactApplicationContext) {
+ @Nonnull
+ override fun getName(): String {
+ return REACT_CLASS
+ }
+
+ @Nonnull
+ override fun createViewInstance(@Nonnull reactContext: ThemedReactContext): RCTMGLVectorSource {
+ return RCTMGLVectorSource(reactContext, this)
+ }
+
+ @ReactProp(name = "hasPressListener")
+ fun setHasPressListener(source: RCTMGLVectorSource, hasPressListener: Boolean) {
+ source.setHasPressListener(hasPressListener)
+ }
+
+ @ReactProp(name = "hitbox")
+ fun setHitbox(source: RCTMGLVectorSource, map: ReadableMap?) {
+ source.setHitbox(map!!)
+ }
+
+ override fun customEvents(): Map? {
+ return MapBuilder.builder()
+ .put(EventKeys.VECTOR_SOURCE_LAYER_CLICK, "onMapboxVectorSourcePress")
+ .put(EventKeys.MAP_ANDROID_CALLBACK, "onAndroidCallback")
+ .build()
+ }
+
+ override fun getCommandsMap(): Map? {
+ return MapBuilder.builder()
+ .put("features", METHOD_FEATURES)
+ .build()
+ }
+
+ override fun receiveCommand(
+ vectorSource: RCTMGLVectorSource,
+ commandID: Int,
+ args: ReadableArray?
+ ) {
+ when (commandID) {
+ METHOD_FEATURES -> vectorSource.querySourceFeatures(
+ args!!.getString(0),
+ ConvertUtils.toStringList(args.getArray(1)),
+ ExpressionParser.from(args.getArray(2))
+ )
+ }
+ }
+
+ companion object {
+ const val REACT_CLASS = "RCTMGLVectorSource"
+
+ //region React Methods
+ const val METHOD_FEATURES = 102
+ }
+}
\ No newline at end of file
diff --git a/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTSource.kt b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTSource.kt
new file mode 100644
index 000000000..77e5c349e
--- /dev/null
+++ b/android/rctmgl/src/main/java-v10/com/mapbox/rctmgl/components/styles/sources/RCTSource.kt
@@ -0,0 +1,235 @@
+package com.mapbox.rctmgl.components.styles.sources
+
+import android.content.Context
+import com.mapbox.maps.extension.style.sources.getSource
+import com.mapbox.maps.extension.style.sources.addSource
+import com.mapbox.rctmgl.components.AbstractMapFeature
+import com.mapbox.rctmgl.components.mapview.RCTMGLMapView
+import com.mapbox.maps.MapboxMap
+import com.mapbox.rctmgl.components.styles.sources.AbstractSourceConsumer
+import com.facebook.react.bridge.ReadableMap
+import com.mapbox.rctmgl.components.styles.sources.RCTSource
+import android.graphics.PointF
+import android.view.View
+import com.facebook.react.common.MapBuilder
+import com.mapbox.geojson.Feature
+import com.mapbox.maps.Style
+import com.mapbox.maps.extension.style.StyleContract
+import com.mapbox.maps.extension.style.sources.Source
+import com.mapbox.rctmgl.components.RemovalReason
+import com.mapbox.rctmgl.components.styles.sources.RCTSource.OnPressEvent
+import com.mapbox.rctmgl.utils.LatLng
+import com.mapbox.rctmgl.utils.Logger
+import java.lang.ClassCastException
+import java.util.ArrayList
+import java.util.HashMap
+
+data class FeatureInfo(val feature: AbstractMapFeature?, var added: Boolean) {
+}
+
+abstract class RCTSource(context: Context?) : AbstractMapFeature(context) {
+ @JvmField
+ protected var mMap: MapboxMap? = null
+ var iD: String? = null
+ @JvmField
+ protected var mSource: T? = null
+ protected var mHasPressListener = false
+ protected var mTouchHitbox: Map? = null
+ private var mSubFeatures = mutableListOf()
+
+ val layerIDs: List